]> Creatis software - creaImageIO.git/commitdiff
move directory
authorFrederic Cervenansky <Frederic.Cervenansky@creatis.insa-lyon.fr>
Tue, 16 Mar 2010 15:46:13 +0000 (15:46 +0000)
committerFrederic Cervenansky <Frederic.Cervenansky@creatis.insa-lyon.fr>
Tue, 16 Mar 2010 15:46:13 +0000 (15:46 +0000)
151 files changed:
src/AdditionalUsecreaImageIO2.cmake.in [new file with mode: 0644]
src/AdditionalcreaImageIO2Config.cmake.in [new file with mode: 0644]
src/BlockScopeWxApp.cpp [new file with mode: 0644]
src/BlockScopeWxApp.h [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/CppSQLite3.cpp [new file with mode: 0644]
src/CppSQLite3.h [new file with mode: 0644]
src/OldcreaImageIOGimmickView.h [new file with mode: 0644]
src/README.txt [new file with mode: 0644]
src/creaImageIOAbstractImageReader.h [new file with mode: 0644]
src/creaImageIODicomImageReader.cpp [new file with mode: 0644]
src/creaImageIODicomImageReader.h [new file with mode: 0644]
src/creaImageIODicomImageReader2.cpp [new file with mode: 0644]
src/creaImageIODicomImageReader2.h [new file with mode: 0644]
src/creaImageIODicomScanner.cpp [new file with mode: 0644]
src/creaImageIODicomScanner.h [new file with mode: 0644]
src/creaImageIOExternalGimmick.cpp [new file with mode: 0644]
src/creaImageIOExternalGimmick.h [new file with mode: 0644]
src/creaImageIOGimmick.cpp [new file with mode: 0644]
src/creaImageIOGimmick.h [new file with mode: 0644]
src/creaImageIOGimmickReaderDialog.cpp [new file with mode: 0644]
src/creaImageIOGimmickReaderDialog.h [new file with mode: 0644]
src/creaImageIOGimmickView.cpp [new file with mode: 0644]
src/creaImageIOGimmickView.h [new file with mode: 0644]
src/creaImageIOImagePointerHolder.h [new file with mode: 0644]
src/creaImageIOImageReader.cpp [new file with mode: 0644]
src/creaImageIOImageReader.h [new file with mode: 0644]
src/creaImageIOIndexedHeap.h [new file with mode: 0644]
src/creaImageIOIndexedHeap.txx [new file with mode: 0644]
src/creaImageIOListener.cpp [new file with mode: 0644]
src/creaImageIOListener.h [new file with mode: 0644]
src/creaImageIOMultiThreadImageReader.cpp [new file with mode: 0644]
src/creaImageIOMultiThreadImageReader.h [new file with mode: 0644]
src/creaImageIOPACSConnection.cpp [new file with mode: 0644]
src/creaImageIOPACSConnection.h [new file with mode: 0644]
src/creaImageIOSQLiteTreeHandler.cpp [new file with mode: 0644]
src/creaImageIOSQLiteTreeHandler.h [new file with mode: 0644]
src/creaImageIOSettings.cpp [new file with mode: 0644]
src/creaImageIOSettings.h [new file with mode: 0644]
src/creaImageIOSynchron.cpp [new file with mode: 0644]
src/creaImageIOSynchron.h [new file with mode: 0644]
src/creaImageIOSynchronizer.cpp [new file with mode: 0644]
src/creaImageIOSynchronizer.h [new file with mode: 0644]
src/creaImageIOSystem.cpp [new file with mode: 0644]
src/creaImageIOSystem.h [new file with mode: 0644]
src/creaImageIOTimestampDatabaseHandler.cpp [new file with mode: 0644]
src/creaImageIOTimestampDatabaseHandler.h [new file with mode: 0644]
src/creaImageIOTree.cpp [new file with mode: 0644]
src/creaImageIOTree.h [new file with mode: 0644]
src/creaImageIOTreeAttributeDescriptor.cpp [new file with mode: 0644]
src/creaImageIOTreeAttributeDescriptor.h [new file with mode: 0644]
src/creaImageIOTreeAttributeMapType.h [new file with mode: 0644]
src/creaImageIOTreeComparators.cpp [new file with mode: 0644]
src/creaImageIOTreeComparators.h [new file with mode: 0644]
src/creaImageIOTreeDescriptor.cpp [new file with mode: 0644]
src/creaImageIOTreeDescriptor.h [new file with mode: 0644]
src/creaImageIOTreeHandler.h [new file with mode: 0644]
src/creaImageIOTreeHandlerImageAdder.cpp [new file with mode: 0644]
src/creaImageIOTreeHandlerImageAdder.h [new file with mode: 0644]
src/creaImageIOTreeLevelDescriptor.cpp [new file with mode: 0644]
src/creaImageIOTreeLevelDescriptor.h [new file with mode: 0644]
src/creaImageIOTreeNode.cpp [new file with mode: 0644]
src/creaImageIOTreeNode.h [new file with mode: 0644]
src/creaImageIOTreeView.cpp [new file with mode: 0644]
src/creaImageIOTreeView.h [new file with mode: 0644]
src/creaImageIOUltrasonixImageReader.cpp [new file with mode: 0644]
src/creaImageIOUltrasonixImageReader.h [new file with mode: 0644]
src/creaImageIOVtkImageReader.cpp [new file with mode: 0644]
src/creaImageIOVtkImageReader.h [new file with mode: 0644]
src/creaImageIOWxAttributeSelectionPanel.cpp [new file with mode: 0644]
src/creaImageIOWxAttributeSelectionPanel.h [new file with mode: 0644]
src/creaImageIOWxCustomizeConfigPanel.cpp [new file with mode: 0644]
src/creaImageIOWxCustomizeConfigPanel.h [new file with mode: 0644]
src/creaImageIOWxDescriptorPanel.cpp [new file with mode: 0644]
src/creaImageIOWxDescriptorPanel.h [new file with mode: 0644]
src/creaImageIOWxDumpPanel.cpp [new file with mode: 0644]
src/creaImageIOWxDumpPanel.h [new file with mode: 0644]
src/creaImageIOWxEditFieldsPanel.cpp [new file with mode: 0644]
src/creaImageIOWxEditFieldsPanel.h [new file with mode: 0644]
src/creaImageIOWxExportDlg.cpp [new file with mode: 0644]
src/creaImageIOWxExportDlg.h [new file with mode: 0644]
src/creaImageIOWxGimmickFrame.cpp [new file with mode: 0644]
src/creaImageIOWxGimmickFrame.h [new file with mode: 0644]
src/creaImageIOWxGimmickPanel.cpp [new file with mode: 0644]
src/creaImageIOWxGimmickPanel.h [new file with mode: 0644]
src/creaImageIOWxGimmickReaderDialog.cpp [new file with mode: 0644]
src/creaImageIOWxGimmickReaderDialog.h [new file with mode: 0644]
src/creaImageIOWxGimmickTools.cpp [new file with mode: 0644]
src/creaImageIOWxGimmickTools.h [new file with mode: 0644]
src/creaImageIOWxGimmickView.cpp [new file with mode: 0644]
src/creaImageIOWxGimmickView.h [new file with mode: 0644]
src/creaImageIOWxListenerPanel.cpp [new file with mode: 0644]
src/creaImageIOWxListenerPanel.h [new file with mode: 0644]
src/creaImageIOWxPACSConnectionPanel.cpp [new file with mode: 0644]
src/creaImageIOWxPACSConnectionPanel.h [new file with mode: 0644]
src/creaImageIOWxTreeView.cpp [new file with mode: 0644]
src/creaImageIOWxTreeView.h [new file with mode: 0644]
src/creaImageIOWxViewer.cpp [new file with mode: 0644]
src/creaImageIOWxViewer.h [new file with mode: 0644]
src/creatisIO.cpp [new file with mode: 0644]
src/creatisIOComparator.cpp [new file with mode: 0644]
src/creatisIOComparator.h [new file with mode: 0644]
src/creatisIOWxDumpPanel.cpp [new file with mode: 0644]
src/data/localdatabase_Descriptor.dscp [new file with mode: 0644]
src/doxygen/Architecture.htm [new file with mode: 0644]
src/doxygen/CMakeLists.txt [new file with mode: 0644]
src/doxygen/ClassDiagram.htm [new file with mode: 0644]
src/doxygen/ClassDiagram.png [new file with mode: 0644]
src/doxygen/ComponentDiagram.htm [new file with mode: 0644]
src/doxygen/ComponentDiagram.png [new file with mode: 0644]
src/doxygen/DoxyMainPage.txt.in [new file with mode: 0644]
src/doxygen/Doxyfile.txt.in [new file with mode: 0644]
src/doxygen/LayerDiagram.htm [new file with mode: 0644]
src/doxygen/LayerDiagram.jpg [new file with mode: 0644]
src/doxygen/SeqAddDir.htm [new file with mode: 0644]
src/doxygen/SeqAddDir.png [new file with mode: 0644]
src/doxygen/SeqAddFile.htm [new file with mode: 0644]
src/doxygen/SeqAddFile.png [new file with mode: 0644]
src/doxygen/SeqCreateDB.htm [new file with mode: 0644]
src/doxygen/SeqCreateDB.png [new file with mode: 0644]
src/doxygen/SeqGetImages.htm [new file with mode: 0644]
src/doxygen/SeqGetImages.png [new file with mode: 0644]
src/doxygen/SeqRemove.htm [new file with mode: 0644]
src/doxygen/SeqRemove.png [new file with mode: 0644]
src/doxygen/SeqSelChanged.htm [new file with mode: 0644]
src/doxygen/SeqSelChanged.png [new file with mode: 0644]
src/icons/accept-48x48.png [new file with mode: 0644]
src/icons/accept.xpm [new file with mode: 0644]
src/icons/add-48x48.jpg [new file with mode: 0644]
src/icons/add-48x48.png [new file with mode: 0644]
src/icons/add.xpm [new file with mode: 0644]
src/icons/create-database-48x48.png [new file with mode: 0644]
src/icons/create-database.xpm [new file with mode: 0644]
src/icons/database-add-48x48.png [new file with mode: 0644]
src/icons/database-add.xpm [new file with mode: 0644]
src/icons/folder-down-48x48.png [new file with mode: 0644]
src/icons/folder-down.xpm [new file with mode: 0644]
src/icons/help-48x48.png [new file with mode: 0644]
src/icons/help.xpm [new file with mode: 0644]
src/icons/page-down-48x48.png [new file with mode: 0644]
src/icons/page-down.xpm [new file with mode: 0644]
src/icons/remove-48x48.png [new file with mode: 0644]
src/icons/remove.xpm [new file with mode: 0644]
src/icons/save.xcf [new file with mode: 0644]
src/icons/save.xpm [new file with mode: 0644]
src/icons/settings-40x40.png [new file with mode: 0644]
src/icons/settings.xpm [new file with mode: 0644]
src/icons/synchronize-48x48.png [new file with mode: 0644]
src/icons/synchronize.xpm [new file with mode: 0644]
src/icons/tools-48x48.png [new file with mode: 0644]
src/icons/tools.xpm [new file with mode: 0644]

diff --git a/src/AdditionalUsecreaImageIO2.cmake.in b/src/AdditionalUsecreaImageIO2.cmake.in
new file mode 100644 (file)
index 0000000..bdf20d7
--- /dev/null
@@ -0,0 +1,2 @@
+INCLUDE(${crea_USE_FILE})
+
diff --git a/src/AdditionalcreaImageIO2Config.cmake.in b/src/AdditionalcreaImageIO2Config.cmake.in
new file mode 100644 (file)
index 0000000..35ae10d
--- /dev/null
@@ -0,0 +1,2 @@
+# We have to find crea
+FIND_PACKAGE(crea REQUIRED)
\ No newline at end of file
diff --git a/src/BlockScopeWxApp.cpp b/src/BlockScopeWxApp.cpp
new file mode 100644 (file)
index 0000000..c8c361c
--- /dev/null
@@ -0,0 +1,45 @@
+#include <BlockScopeWxApp.h>
+#include <wx/wx.h>
+
+
+class DummyWxApp : public wxApp
+{
+public:
+  bool OnInit( );
+  int  OnExit() { return true; }
+};
+
+IMPLEMENT_APP_NO_MAIN(DummyWxApp);
+
+
+bool DummyWxApp::OnInit( )
+{       
+//  std::cout << "OnInit()"<<std::endl;
+  wxApp::OnInit();
+#ifdef __WXGTK__
+  //See http://www.wxwindows.org/faqgtk.htm#locale
+  setlocale(LC_NUMERIC, "C");
+#endif
+  return true;
+}
+
+
+BlockScopeWxApp::BlockScopeWxApp()
+{
+  mNeedToUninitialize = false;
+  if (wxApp::GetInstance()==0)
+    {
+      wxApp::SetInstance(new DummyWxApp);
+      wxInitialize();
+      mNeedToUninitialize = true;
+    }
+}
+
+BlockScopeWxApp::~BlockScopeWxApp()
+{
+  if (mNeedToUninitialize) wxUninitialize();
+}
+
+
+
diff --git a/src/BlockScopeWxApp.h b/src/BlockScopeWxApp.h
new file mode 100644 (file)
index 0000000..c550b4f
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __wxAppNoMain_h__
+#define __wxAppNoMain_h__
+
+
+class BlockScopeWxApp
+{
+public:
+  BlockScopeWxApp();
+  ~BlockScopeWxApp();
+private:
+  bool mNeedToUninitialize;
+};
+
+
+#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b68fae5
--- /dev/null
@@ -0,0 +1,228 @@
+SET(LIBRARY_NAME creaImageIO2)
+
+
+FILE(GLOB SOURCES_CREAIMAGEIO  
+  # SQLite 
+  CppSQLite3.cpp
+  # 
+  creaImageIOGimmick.cpp
+  creaImageIOSynchron.cpp
+  creaImageIOPACSConnection.cpp
+
+  # Abstract views
+  creaImageIOTreeView.cpp
+
+  # settings
+  creaImageIOSettings.cpp
+
+   BlockScopeWxApp.cpp
+  creaImageIOGimmickReaderDialog.cpp
+  creaImageIOExternalGimmick.cpp
+  #  Viewer
+  creaImageIOWxViewer.cpp
+  creaImageIOGimmickView.cpp
+  creaImageIOListener.cpp
+)
+ # Attributed tree data structure
+FILE(GLOB SOURCES_CREAIMAGEIO_TREE
+         creaImageIOTree.cpp
+         creaImageIOTreeAttributeDescriptor.cpp
+         creaImageIOTreeDescriptor.cpp
+         creaImageIOTreeNode.cpp
+         creaImageIOTreeLevelDescriptor.cpp
+           # Tree Handlers
+         creaImageIOTreeHandler.cpp
+         creaImageIOTreeHandlerImageAdder.cpp
+         creaImageIOSQLiteTreeHandler.cpp
+         )
+IF(USE_GDCM)
+ FILE(GLOB SOURCES_CREAIMAGEIO_IMG_DICOM_READER
+               creaImageIODicomImageReader.cpp)
+ENDIF(USE_GDCM)
+
+         
+IF(USE_GDCM2)
+ FILE(GLOB SOURCES_CREAIMAGEIO_IMG_DICOM_READER
+               creaImageIODicomImageReader2.cpp)
+ENDIF(USE_GDCM2)
+
+ # Image Readers
+FILE(GLOB SOURCES_CREAIMAGEIO_IMG_READER
+         creaImageIOAbstractImageReader.cpp
+         creaImageIOImageReader.cpp
+         creaImageIOUltrasonixImageReader.cpp
+         creaImageIOVtkImageReader.cpp
+         creaImageIOMultiThreadImageReader.cpp
+         ${SOURCES_CREAIMAGEIO_IMG_DICOM_READER}
+         )
+
+
+# The wxWidgets-based components
+if (USE_WXWIDGETS)
+FILE(GLOB SOURCES_CREAIMAGEIO_WX
+         creaImageIOWxAttributeSelectionPanel.cpp
+         creaImageIOWxCustomizeConfigPanel.cpp
+         creaImageIOWxDescriptorPanel.cpp
+         creaImageIOWxEditFieldsPanel.cpp
+         creaImageIOWxExportDlg.cpp
+         creaImageIOWxDumpPanel.cpp
+         creaImageIOWxGimmickView.cpp
+         creaImageIOWxGimmickReaderDialog.cpp
+      creaImageIOWxGimmickFrame.cpp
+      creaImageIOWxGimmickPanel.cpp
+      creaImageIOWxGimmickTools.cpp
+      creaImageIOWxListenerPanel.cpp
+      creaImageIOWxPACSConnectionPanel.cpp
+         creaImageIOWxTreeView.cpp
+         )
+endif()
+
+# Header Files   
+FILE(GLOB HEADER_CREAIMAGEIO creaImageIOImagePointerHolder.h)
+FILE(GLOB SOURCES_CREAIMAGEIO_PACS PACS/*.cpp)
+FILE(GLOB HEADER_CREAIMAGEIO_PACS PACS/*.h)
+
+
+SOURCE_GROUP("Source Files" FILES ${SOURCES_CREAIMAGEIO})
+SOURCE_GROUP("Header Files" FILES ${HEADER_CREAIMAGEIO})
+SOURCE_GROUP("Source Files\\GUI" FILES ${SOURCES_CREAIMAGEIO_WX})
+if(BUILD_CREA_PACS)
+       SOURCE_GROUP("Source Files\\PACS" FILES ${SOURCES_CREAIMAGEIO_PACS})
+       SOURCE_GROUP("Header Files\\PACS" FILES ${HEADER_CREAIMAGEIO_PACS})
+endif(BUILD_CREA_PACS)
+SOURCE_GROUP("Source Files\\Readers" FILES ${SOURCES_CREAIMAGEIO_IMG_READER}
+                                                                                       ${SOURCES_CREAIMAGEIO_IMG_DICOM_READER})
+SOURCE_GROUP("Source Files\\Tree" FILES ${SOURCES_CREAIMAGEIO_TREE})
+
+
+SET( PRIMITIVE_SRCS
+ ${SOURCES_CREAIMAGEIO}
+ ${HEADER_CREAIMAGEIO}
+ ${SOURCES_CREAIMAGEIO_IMG_READER}
+ ${SOURCES_CREAIMAGEIO_IMG_DICOM_READER}
+ ${SOURCES_CREAIMAGEIO_WX}
+ ${SOURCES_CREAIMAGEIO_TREE}
+)
+
+if( BUILD_CREA_PACS)
+       SET (SRCS
+               ${PRIMITIVE_SRCS}
+               ${SOURCES_CREAIMAGEIO_PACS}
+               ${HEADER_CREAIMAGEIO_PACS}
+               )
+else (BUILD_CREA_PACS)
+       SET (SRCS
+               ${PRIMITIVE_SRCS}
+               )
+endif (BUILD_CREA_PACS)
+
+
+
+
+OPTION(${LIBRARY_NAME}_BUILD_SHARED 
+  "Build ${LIBRARY_NAME} as a shared library (dynamic) ?" ON)
+IF (${LIBRARY_NAME}_BUILD_SHARED)
+  SET(CREAIMAGEIO_BUILD_SHARED SHARED)
+  crea_DEFINE(CREAIMAGEIO_BUILD_SHARED)
+ENDIF(${LIBRARY_NAME}_BUILD_SHARED)
+
+crea_DEFINE(CREAIMAGEIO_EXPORT_SYMBOLS)
+
+ADD_LIBRARY(${LIBRARY_NAME} ${CREAIMAGEIO_BUILD_SHARED} ${SRCS})
+
+
+TARGET_LINK_LIBRARIES(${LIBRARY_NAME} 
+  ${crea_LIBRARIES}
+  ${creaBruker_LIBRARIES}
+  ${WXWIDGETS_LIBRARIES}
+  ${VTK_LIBRARIES}
+  ${GDCM_LIBRARIES}
+  ${BOOST_LIBRARIES}
+  sqlite3)
+
+#----------------------------------------------------------------------------
+# INSTALLS LIBRARY
+FILE(GLOB HEADERS "*.h" "*.txx")
+INSTALL(
+  FILES ${HEADERS}
+  DESTINATION include/${LIBRARY_NAME}
+  )
+  
+
+IF (WIN32)
+  SET(CREAIMAGEIO_LIB_PATH bin)
+ELSE (WIN32)
+  SET(CREAIMAGEIO_LIB_PATH lib)
+ENDIF(WIN32)
+
+INSTALL(
+  TARGETS ${LIBRARY_NAME} 
+  DESTINATION ${CREAIMAGEIO_LIB_PATH})
+
+     # Sets the settings for macro CREA_ADVANCED_INSTALL_LIBRARY_FOR_CMAKE
+  SET(${LIBRARY_NAME}_INSTALL_FOLDER ${LIBRARY_NAME})
+  SET(${LIBRARY_NAME}_LIBRARIES ${LIBRARY_NAME})
+  
+#  FILE(RELATIVE_PATH 
+#    ${LIBRARY_NAME}_BUILD_TREE_RELATIVE_INCLUDE_PATHS 
+#    ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
+#    )
+SET(${LIBRARY_NAME}_BUILD_TREE_RELATIVE_INCLUDE_PATHS
+    src2
+    win32
+)
+
+
+  IF ( ${PROJECT_BINARY_DIR} STREQUAL ${EXECUTABLE_OUTPUT_PATH} )
+    SET(CILFC_EXECUTABLE_OUTPUT_REL_PATH ".")
+  ELSE ( ${PROJECT_BINARY_DIR} STREQUAL ${EXECUTABLE_OUTPUT_PATH} )
+    FILE(RELATIVE_PATH 
+      CILFC_EXECUTABLE_OUTPUT_REL_PATH
+      ${PROJECT_BINARY_DIR} ${EXECUTABLE_OUTPUT_PATH})
+  ENDIF ( ${PROJECT_BINARY_DIR} STREQUAL ${EXECUTABLE_OUTPUT_PATH} )
+
+  IF(UNIX)
+    SET(${LIBRARY_NAME}_BUILD_TREE_RELATIVE_LIBRARY_PATHS 
+      ${CILFC_EXECUTABLE_OUTPUT_REL_PATH})
+    SET(${LIBRARY_NAME}_INSTALL_TREE_RELATIVE_LIBRARY_PATHS lib)
+  ELSE(UNIX)
+    SET(${LIBRARY_NAME}_BUILD_TREE_RELATIVE_LIBRARY_PATHS 
+      ${CILFC_EXECUTABLE_OUTPUT_REL_PATH})
+    SET(${LIBRARY_NAME}_INSTALL_TREE_RELATIVE_LIBRARY_PATHS bin)
+  ENDIF(UNIX)
+  SET(${LIBRARY_NAME}_INSTALL_TREE_RELATIVE_INCLUDE_PATHS include/${LIBRARY_NAME})
+  
+  SET(${LIBRARY_NAME}_HAS_ADDITIONAL_CONFIG_FILE TRUE)
+SET(${LIBRARY_NAME}_ADDITIONAL_CONFIG_FILE 
+  ${PROJECT_SOURCE_DIR}/src2/Additional${LIBRARY_NAME}Config.cmake.in)
+SET(${LIBRARY_NAME}_ADDITIONAL_USE_FILE 
+  ${PROJECT_SOURCE_DIR}/src2/AdditionalUse${LIBRARY_NAME}.cmake.in)
+
+  # Invoke the advanced macro
+  CREA_ADVANCED_INSTALL_LIBRARY_FOR_CMAKE(${LIBRARY_NAME})
+IF (WIN32)
+       SET(INPUT_DATA_DIR ${PROJECT_SOURCE_DIR}/src2/data)
+       SET(OUTPUT_DATA_DIR ${PROJECT_BINARY_DIR}/bin/Shared/gimmick)
+ELSE (WIN32)
+       SET(INPUT_DATA_DIR ${PROJECT_SOURCE_DIR}/src2/data)
+       SET(OUTPUT_DATA_DIR ${PROJECT_BINARY_DIR}/share/gimmick)
+ENDIF (WIN32)
+CREA_CPDIR(${INPUT_DATA_DIR} ${OUTPUT_DATA_DIR})
+
+  
+#CREA_INSTALL_LIBRARY_FOR_CMAKE(${LIBRARY_NAME})
+#-----------------------------------------------------------------------------
+
+OPTION( BUILD_DOXYGEN_DOC "Build doxygen doc ?" OFF)
+IF(BUILD_DOXYGEN_DOC)
+  SUBDIRS(doxygen)
+ENDIF(BUILD_DOXYGEN_DOC)
+
+INCLUDE_DIRECTORIES(
+#  ${PROJECT_BINARY_DIR}
+  ${PROJECT_SOURCE_DIR}/src2
+#  ${PROJECT_SOURCE_DIR}/src2/CppSQLite3
+  )
diff --git a/src/CppSQLite3.cpp b/src/CppSQLite3.cpp
new file mode 100644 (file)
index 0000000..4ad953f
--- /dev/null
@@ -0,0 +1,3000 @@
+////////////////////////////////////////////////////////////////////////////////
+
+// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
+
+//
+
+// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
+
+// 
+
+// Permission to use, copy, modify, and distribute this software and its
+
+// documentation for any purpose, without fee, and without a written
+
+// agreement, is hereby granted, provided that the above copyright notice, 
+
+// this paragraph and the following two paragraphs appear in all copies, 
+
+// modifications, and distributions.
+
+//
+
+// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
+
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
+
+// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+
+// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+
+// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+
+// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+
+// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
+
+// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+//
+
+// V3.0                03/08/2004      -Initial Version for sqlite3
+
+//
+
+// V3.1                16/09/2004      -Implemented getXXXXField using sqlite3 functions
+
+//                                             -Added CppSQLiteDB3::tableExists()
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "CppSQLite3.h"
+
+#include <cstdlib>
+
+
+
+
+
+// Named constant for passing to CppSQLite3Exception when passing it a string
+
+// that cannot be deleted.
+
+static const bool DONT_DELETE_MSG=false;
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Prototypes for SQLite functions not included in SQLite DLL, but copied below
+
+// from SQLite encode.c
+
+////////////////////////////////////////////////////////////////////////////////
+
+int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out);
+
+int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
+
+                                        const char* szErrMess,
+
+                                        bool bDeleteMsg/*=true*/) :
+
+  mnErrCode(nErrCode)
+
+{
+
+  mpszErrMess = sqlite3_mprintf("%s[%d]: %s",
+
+                               errorCodeAsString(nErrCode),
+
+                               nErrCode,
+
+                               szErrMess ? szErrMess : "");
+
+  /*
+
+  if (bDeleteMsg && szErrMess)
+
+    {
+
+      sqlite3_free(szErrMess);
+
+    }
+
+  */
+
+}
+
+
+
+CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
+
+                                        char* szErrMess,
+
+                                        bool bDeleteMsg/*=true*/) :
+
+  mnErrCode(nErrCode)
+
+{
+
+  mpszErrMess = sqlite3_mprintf("%s[%d]: %s",
+
+                               errorCodeAsString(nErrCode),
+
+                               nErrCode,
+
+                               szErrMess ? szErrMess : "");
+
+  
+
+  if (bDeleteMsg && szErrMess)
+
+    {
+
+      sqlite3_free(szErrMess);
+
+    }
+
+}
+
+                                                                       
+
+CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception&  e) :
+
+                                                                       mnErrCode(e.mnErrCode)
+
+{
+
+       mpszErrMess = 0;
+
+       if (e.mpszErrMess)
+
+       {
+
+               mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);
+
+       }
+
+}
+
+
+
+
+
+const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)
+
+{
+
+       switch (nErrCode)
+
+       {
+
+               case SQLITE_OK          : return "SQLITE_OK";
+
+               case SQLITE_ERROR       : return "SQLITE_ERROR";
+
+               case SQLITE_INTERNAL    : return "SQLITE_INTERNAL";
+
+               case SQLITE_PERM        : return "SQLITE_PERM";
+
+               case SQLITE_ABORT       : return "SQLITE_ABORT";
+
+               case SQLITE_BUSY        : return "SQLITE_BUSY";
+
+               case SQLITE_LOCKED      : return "SQLITE_LOCKED";
+
+               case SQLITE_NOMEM       : return "SQLITE_NOMEM";
+
+               case SQLITE_READONLY    : return "SQLITE_READONLY";
+
+               case SQLITE_INTERRUPT   : return "SQLITE_INTERRUPT";
+
+               case SQLITE_IOERR       : return "SQLITE_IOERR";
+
+               case SQLITE_CORRUPT     : return "SQLITE_CORRUPT";
+
+               case SQLITE_NOTFOUND    : return "SQLITE_NOTFOUND";
+
+               case SQLITE_FULL        : return "SQLITE_FULL";
+
+               case SQLITE_CANTOPEN    : return "SQLITE_CANTOPEN";
+
+               case SQLITE_PROTOCOL    : return "SQLITE_PROTOCOL";
+
+               case SQLITE_EMPTY       : return "SQLITE_EMPTY";
+
+               case SQLITE_SCHEMA      : return "SQLITE_SCHEMA";
+
+               case SQLITE_TOOBIG      : return "SQLITE_TOOBIG";
+
+               case SQLITE_CONSTRAINT  : return "SQLITE_CONSTRAINT";
+
+               case SQLITE_MISMATCH    : return "SQLITE_MISMATCH";
+
+               case SQLITE_MISUSE      : return "SQLITE_MISUSE";
+
+               case SQLITE_NOLFS       : return "SQLITE_NOLFS";
+
+               case SQLITE_AUTH        : return "SQLITE_AUTH";
+
+               case SQLITE_FORMAT      : return "SQLITE_FORMAT";
+
+               case SQLITE_RANGE       : return "SQLITE_RANGE";
+
+               case SQLITE_ROW         : return "SQLITE_ROW";
+
+               case SQLITE_DONE        : return "SQLITE_DONE";
+
+               case CPPSQLITE_ERROR    : return "CPPSQLITE_ERROR";
+
+               default: return "UNKNOWN_ERROR";
+
+       }
+
+}
+
+
+
+
+
+CppSQLite3Exception::~CppSQLite3Exception()
+
+{
+
+       if (mpszErrMess)
+
+       {
+
+               sqlite3_free(mpszErrMess);
+
+               mpszErrMess = 0;
+
+       }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Buffer::CppSQLite3Buffer()
+
+{
+
+       mpBuf = 0;
+
+}
+
+
+
+
+
+CppSQLite3Buffer::~CppSQLite3Buffer()
+
+{
+
+       clear();
+
+}
+
+
+
+
+
+void CppSQLite3Buffer::clear()
+
+{
+
+       if (mpBuf)
+
+       {
+
+               sqlite3_free(mpBuf);
+
+               mpBuf = 0;
+
+       }
+
+
+
+}
+
+
+
+
+
+const char* CppSQLite3Buffer::format(const char* szFormat, ...)
+
+{
+
+       clear();
+
+       va_list va;
+
+       va_start(va, szFormat);
+
+       mpBuf = sqlite3_vmprintf(szFormat, va);
+
+       va_end(va);
+
+       return mpBuf;
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Binary::CppSQLite3Binary() :
+
+                                               mpBuf(0),
+
+                                               mnBinaryLen(0),
+
+                                               mnBufferLen(0),
+
+                                               mnEncodedLen(0),
+
+                                               mbEncoded(false)
+
+{
+
+}
+
+
+
+
+
+CppSQLite3Binary::~CppSQLite3Binary()
+
+{
+
+       clear();
+
+}
+
+
+
+
+
+void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)
+
+{
+
+       mpBuf = allocBuffer(nLen);
+
+       memcpy(mpBuf, pBuf, nLen);
+
+}
+
+
+
+
+
+void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)
+
+{
+
+       clear();
+
+
+
+       mnEncodedLen = strlen((const char*)pBuf);
+
+       mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator
+
+
+
+       mpBuf = (unsigned char*)malloc(mnBufferLen);
+
+
+
+       if (!mpBuf)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Cannot allocate memory",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       memcpy(mpBuf, pBuf, mnBufferLen);
+
+       mbEncoded = true;
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Binary::getEncoded()
+
+{
+
+       if (!mbEncoded)
+
+       {
+
+               unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);
+
+               memcpy(ptmp, mpBuf, mnBinaryLen);
+
+               mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);
+
+               free(ptmp);
+
+               mbEncoded = true;
+
+       }
+
+
+
+       return mpBuf;
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Binary::getBinary()
+
+{
+
+       if (mbEncoded)
+
+       {
+
+               // in/out buffers can be the same
+
+               mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);
+
+
+
+               if (mnBinaryLen == -1)
+
+               {
+
+                       throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                                       "Cannot decode binary",
+
+                                                                       DONT_DELETE_MSG);
+
+               }
+
+
+
+               mbEncoded = false;
+
+       }
+
+
+
+       return mpBuf;
+
+}
+
+
+
+
+
+int CppSQLite3Binary::getBinaryLength()
+
+{
+
+       getBinary();
+
+       return mnBinaryLen;
+
+}
+
+
+
+
+
+unsigned char* CppSQLite3Binary::allocBuffer(int nLen)
+
+{
+
+       clear();
+
+
+
+       // Allow extra space for encoded binary as per comments in
+
+       // SQLite encode.c See bottom of this file for implementation
+
+       // of SQLite functions use 3 instead of 2 just to be sure ;-)
+
+       mnBinaryLen = nLen;
+
+       mnBufferLen = 3 + (257*nLen)/254;
+
+
+
+       mpBuf = (unsigned char*)malloc(mnBufferLen);
+
+
+
+       if (!mpBuf)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Cannot allocate memory",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       mbEncoded = false;
+
+
+
+       return mpBuf;
+
+}
+
+
+
+
+
+void CppSQLite3Binary::clear()
+
+{
+
+       if (mpBuf)
+
+       {
+
+               mnBinaryLen = 0;
+
+               mnBufferLen = 0;
+
+               free(mpBuf);
+
+               mpBuf = 0;
+
+       }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Query::CppSQLite3Query()
+
+{
+
+       mpVM = 0;
+
+       mbEof = true;
+
+       mnCols = 0;
+
+       mbOwnVM = false;
+
+}
+
+
+
+
+
+CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)
+
+{
+
+       mpVM = rQuery.mpVM;
+
+       // Only one object can own the VM
+
+       const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
+
+       mbEof = rQuery.mbEof;
+
+       mnCols = rQuery.mnCols;
+
+       mbOwnVM = rQuery.mbOwnVM;
+
+}
+
+
+
+
+
+CppSQLite3Query::CppSQLite3Query(sqlite3* pDB,
+
+                                                       sqlite3_stmt* pVM,
+
+                                                       bool bEof,
+
+                                                       bool bOwnVM/*=true*/)
+
+{
+
+       mpDB = pDB;
+
+       mpVM = pVM;
+
+       mbEof = bEof;
+
+       mnCols = sqlite3_column_count(mpVM);
+
+       mbOwnVM = bOwnVM;
+
+}
+
+
+
+
+
+CppSQLite3Query::~CppSQLite3Query()
+
+{
+
+       try
+
+       {
+
+               finalize();
+
+       }
+
+       catch (...)
+
+       {
+
+       }
+
+}
+
+
+
+
+
+CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)
+
+{
+
+       try
+
+       {
+
+               finalize();
+
+       }
+
+       catch (...)
+
+       {
+
+       }
+
+       mpVM = rQuery.mpVM;
+
+       // Only one object can own the VM
+
+       const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
+
+       mbEof = rQuery.mbEof;
+
+       mnCols = rQuery.mnCols;
+
+       mbOwnVM = rQuery.mbOwnVM;
+
+       return *this;
+
+}
+
+
+
+
+
+int CppSQLite3Query::numFields()
+
+{
+
+       checkVM();
+
+       return mnCols;
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldValue(int nField)
+
+{
+
+       checkVM();
+
+
+
+       if (nField < 0 || nField > mnCols-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid field index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       return (const char*)sqlite3_column_text(mpVM, nField);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldValue(const char* szField)
+
+{
+
+       int nField = fieldIndex(szField);
+
+       return (const char*)sqlite3_column_text(mpVM, nField);
+
+}
+
+
+
+
+
+int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)
+
+{
+
+       if (fieldDataType(nField) == SQLITE_NULL)
+
+       {
+
+               return nNullValue;
+
+       }
+
+       else
+
+       {
+
+               return sqlite3_column_int(mpVM, nField);
+
+       }
+
+}
+
+
+
+
+
+int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)
+
+{
+
+       int nField = fieldIndex(szField);
+
+       return getIntField(nField, nNullValue);
+
+}
+
+
+
+
+
+double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)
+
+{
+
+       if (fieldDataType(nField) == SQLITE_NULL)
+
+       {
+
+               return fNullValue;
+
+       }
+
+       else
+
+       {
+
+               return sqlite3_column_double(mpVM, nField);
+
+       }
+
+}
+
+
+
+
+
+double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)
+
+{
+
+       int nField = fieldIndex(szField);
+
+       return getFloatField(nField, fNullValue);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)
+
+{
+
+       if (fieldDataType(nField) == SQLITE_NULL)
+
+       {
+
+               return szNullValue;
+
+       }
+
+       else
+
+       {
+
+               return (const char*)sqlite3_column_text(mpVM, nField);
+
+       }
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)
+
+{
+
+       int nField = fieldIndex(szField);
+
+       return getStringField(nField, szNullValue);
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)
+
+{
+
+       checkVM();
+
+
+
+       if (nField < 0 || nField > mnCols-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid field index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       nLen = sqlite3_column_bytes(mpVM, nField);
+
+       return (const unsigned char*)sqlite3_column_blob(mpVM, nField);
+
+}
+
+
+
+
+
+const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)
+
+{
+
+       int nField = fieldIndex(szField);
+
+       return getBlobField(nField, nLen);
+
+}
+
+
+
+
+
+bool CppSQLite3Query::fieldIsNull(int nField)
+
+{
+
+       return (fieldDataType(nField) == SQLITE_NULL);
+
+}
+
+
+
+
+
+bool CppSQLite3Query::fieldIsNull(const char* szField)
+
+{
+
+       int nField = fieldIndex(szField);
+
+       return (fieldDataType(nField) == SQLITE_NULL);
+
+}
+
+
+
+
+
+int CppSQLite3Query::fieldIndex(const char* szField)
+
+{
+
+       checkVM();
+
+
+
+       if (szField)
+
+       {
+
+               for (int nField = 0; nField < mnCols; nField++)
+
+               {
+
+                       const char* szTemp = sqlite3_column_name(mpVM, nField);
+
+
+
+                       if (strcmp(szField, szTemp) == 0)
+
+                       {
+
+                               return nField;
+
+                       }
+
+               }
+
+       }
+
+
+
+       throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                       "Invalid field name requested",
+
+                                                       DONT_DELETE_MSG);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldName(int nCol)
+
+{
+
+       checkVM();
+
+
+
+       if (nCol < 0 || nCol > mnCols-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid field index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       return sqlite3_column_name(mpVM, nCol);
+
+}
+
+
+
+
+
+const char* CppSQLite3Query::fieldDeclType(int nCol)
+
+{
+
+       checkVM();
+
+
+
+       if (nCol < 0 || nCol > mnCols-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid field index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       return sqlite3_column_decltype(mpVM, nCol);
+
+}
+
+
+
+
+
+int CppSQLite3Query::fieldDataType(int nCol)
+
+{
+
+       checkVM();
+
+
+
+       if (nCol < 0 || nCol > mnCols-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid field index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       return sqlite3_column_type(mpVM, nCol);
+
+}
+
+
+
+
+
+bool CppSQLite3Query::eof()
+
+{
+
+       checkVM();
+
+       return mbEof;
+
+}
+
+
+
+
+
+void CppSQLite3Query::nextRow()
+
+{
+
+       checkVM();
+
+
+
+       int nRet = sqlite3_step(mpVM);
+
+
+
+       if (nRet == SQLITE_DONE)
+
+       {
+
+               // no rows
+
+               mbEof = true;
+
+       }
+
+       else if (nRet == SQLITE_ROW)
+
+       {
+
+               // more rows, nothing to do
+
+       }
+
+       else
+
+       {
+
+               nRet = sqlite3_finalize(mpVM);
+
+               mpVM = 0;
+
+               const char* szError = sqlite3_errmsg(mpDB);
+
+               throw CppSQLite3Exception(nRet,
+
+                                                               (char*)szError,
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Query::finalize()
+
+{
+
+       if (mpVM && mbOwnVM)
+
+       {
+
+               int nRet = sqlite3_finalize(mpVM);
+
+               mpVM = 0;
+
+               if (nRet != SQLITE_OK)
+
+               {
+
+                       const char* szError = sqlite3_errmsg(mpDB);
+
+                       throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+               }
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Query::checkVM()
+
+{
+
+       if (mpVM == 0)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Null Virtual Machine pointer",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Table::CppSQLite3Table()
+
+{
+
+       mpaszResults = 0;
+
+       mnRows = 0;
+
+       mnCols = 0;
+
+       mnCurrentRow = 0;
+
+}
+
+
+
+
+
+CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)
+
+{
+
+       mpaszResults = rTable.mpaszResults;
+
+       // Only one object can own the results
+
+       const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
+
+       mnRows = rTable.mnRows;
+
+       mnCols = rTable.mnCols;
+
+       mnCurrentRow = rTable.mnCurrentRow;
+
+}
+
+
+
+
+
+CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)
+
+{
+
+       mpaszResults = paszResults;
+
+       mnRows = nRows;
+
+       mnCols = nCols;
+
+       mnCurrentRow = 0;
+
+}
+
+
+
+
+
+CppSQLite3Table::~CppSQLite3Table()
+
+{
+
+       try
+
+       {
+
+               finalize();
+
+       }
+
+       catch (...)
+
+       {
+
+       }
+
+}
+
+
+
+
+
+CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)
+
+{
+
+       try
+
+       {
+
+               finalize();
+
+       }
+
+       catch (...)
+
+       {
+
+       }
+
+       mpaszResults = rTable.mpaszResults;
+
+       // Only one object can own the results
+
+       const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
+
+       mnRows = rTable.mnRows;
+
+       mnCols = rTable.mnCols;
+
+       mnCurrentRow = rTable.mnCurrentRow;
+
+       return *this;
+
+}
+
+
+
+
+
+void CppSQLite3Table::finalize()
+
+{
+
+       if (mpaszResults)
+
+       {
+
+               sqlite3_free_table(mpaszResults);
+
+               mpaszResults = 0;
+
+       }
+
+}
+
+
+
+
+
+int CppSQLite3Table::numFields()
+
+{
+
+       checkResults();
+
+       return mnCols;
+
+}
+
+
+
+
+
+int CppSQLite3Table::numRows()
+
+{
+
+       checkResults();
+
+       return mnRows;
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::fieldValue(int nField)
+
+{
+
+       checkResults();
+
+
+
+       if (nField < 0 || nField > mnCols-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid field index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;
+
+       return mpaszResults[nIndex];
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::fieldValue(const char* szField)
+
+{
+
+       checkResults();
+
+
+
+       if (szField)
+
+       {
+
+               for (int nField = 0; nField < mnCols; nField++)
+
+               {
+
+                       if (strcmp(szField, mpaszResults[nField]) == 0)
+
+                       {
+
+                               int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;
+
+                               return mpaszResults[nIndex];
+
+                       }
+
+               }
+
+       }
+
+
+
+       throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                       "Invalid field name requested",
+
+                                                       DONT_DELETE_MSG);
+
+}
+
+
+
+
+
+int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)
+
+{
+
+       if (fieldIsNull(nField))
+
+       {
+
+               return nNullValue;
+
+       }
+
+       else
+
+       {
+
+               return atoi(fieldValue(nField));
+
+       }
+
+}
+
+
+
+
+
+int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)
+
+{
+
+       if (fieldIsNull(szField))
+
+       {
+
+               return nNullValue;
+
+       }
+
+       else
+
+       {
+
+               return atoi(fieldValue(szField));
+
+       }
+
+}
+
+
+
+
+
+double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)
+
+{
+
+       if (fieldIsNull(nField))
+
+       {
+
+               return fNullValue;
+
+       }
+
+       else
+
+       {
+
+               return atof(fieldValue(nField));
+
+       }
+
+}
+
+
+
+
+
+double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)
+
+{
+
+       if (fieldIsNull(szField))
+
+       {
+
+               return fNullValue;
+
+       }
+
+       else
+
+       {
+
+               return atof(fieldValue(szField));
+
+       }
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)
+
+{
+
+       if (fieldIsNull(nField))
+
+       {
+
+               return szNullValue;
+
+       }
+
+       else
+
+       {
+
+               return fieldValue(nField);
+
+       }
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)
+
+{
+
+       if (fieldIsNull(szField))
+
+       {
+
+               return szNullValue;
+
+       }
+
+       else
+
+       {
+
+               return fieldValue(szField);
+
+       }
+
+}
+
+
+
+
+
+bool CppSQLite3Table::fieldIsNull(int nField)
+
+{
+
+       checkResults();
+
+       return (fieldValue(nField) == 0);
+
+}
+
+
+
+
+
+bool CppSQLite3Table::fieldIsNull(const char* szField)
+
+{
+
+       checkResults();
+
+       return (fieldValue(szField) == 0);
+
+}
+
+
+
+
+
+const char* CppSQLite3Table::fieldName(int nCol)
+
+{
+
+       checkResults();
+
+
+
+       if (nCol < 0 || nCol > mnCols-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid field index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       return mpaszResults[nCol];
+
+}
+
+
+
+
+
+void CppSQLite3Table::setRow(int nRow)
+
+{
+
+       checkResults();
+
+
+
+       if (nRow < 0 || nRow > mnRows-1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid row index requested",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       mnCurrentRow = nRow;
+
+}
+
+
+
+
+
+void CppSQLite3Table::checkResults()
+
+{
+
+       if (mpaszResults == 0)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Null Results pointer",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3Statement::CppSQLite3Statement()
+
+{
+
+       mpDB = 0;
+
+       mpVM = 0;
+
+}
+
+
+
+
+
+CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)
+
+{
+
+       mpDB = rStatement.mpDB;
+
+       mpVM = rStatement.mpVM;
+
+       // Only one object can own VM
+
+       const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
+
+}
+
+
+
+
+
+CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)
+
+{
+
+       mpDB = pDB;
+
+       mpVM = pVM;
+
+}
+
+
+
+
+
+CppSQLite3Statement::~CppSQLite3Statement()
+
+{
+
+       try
+
+       {
+
+               finalize();
+
+       }
+
+       catch (...)
+
+       {
+
+       }
+
+}
+
+
+
+
+
+CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)
+
+{
+
+       mpDB = rStatement.mpDB;
+
+       mpVM = rStatement.mpVM;
+
+       // Only one object can own VM
+
+       const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
+
+       return *this;
+
+}
+
+
+
+
+
+int CppSQLite3Statement::execDML()
+
+{
+
+       checkDB();
+
+       checkVM();
+
+
+
+       const char* szError=0;
+
+
+
+       int nRet = sqlite3_step(mpVM);
+
+
+
+       if (nRet == SQLITE_DONE)
+
+       {
+
+               int nRowsChanged = sqlite3_changes(mpDB);
+
+
+
+               nRet = sqlite3_reset(mpVM);
+
+
+
+               if (nRet != SQLITE_OK)
+
+               {
+
+                       szError = sqlite3_errmsg(mpDB);
+
+                       throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+               }
+
+
+
+               return nRowsChanged;
+
+       }
+
+       else
+
+       {
+
+               nRet = sqlite3_reset(mpVM);
+
+               szError = sqlite3_errmsg(mpDB);
+
+               throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+CppSQLite3Query CppSQLite3Statement::execQuery()
+
+{
+
+       checkDB();
+
+       checkVM();
+
+
+
+       int nRet = sqlite3_step(mpVM);
+
+
+
+       if (nRet == SQLITE_DONE)
+
+       {
+
+               // no rows
+
+               return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false);
+
+       }
+
+       else if (nRet == SQLITE_ROW)
+
+       {
+
+               // at least 1 row
+
+               return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false);
+
+       }
+
+       else
+
+       {
+
+               nRet = sqlite3_reset(mpVM);
+
+               const char* szError = sqlite3_errmsg(mpDB);
+
+               throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const char* szValue)
+
+{
+
+       checkVM();
+
+       int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT);
+
+
+
+       if (nRes != SQLITE_OK)
+
+       {
+
+               throw CppSQLite3Exception(nRes,
+
+                                                               "Error binding string param",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const int nValue)
+
+{
+
+       checkVM();
+
+       int nRes = sqlite3_bind_int(mpVM, nParam, nValue);
+
+
+
+       if (nRes != SQLITE_OK)
+
+       {
+
+               throw CppSQLite3Exception(nRes,
+
+                                                               "Error binding int param",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const double dValue)
+
+{
+
+       checkVM();
+
+       int nRes = sqlite3_bind_double(mpVM, nParam, dValue);
+
+
+
+       if (nRes != SQLITE_OK)
+
+       {
+
+               throw CppSQLite3Exception(nRes,
+
+                                                               "Error binding double param",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)
+
+{
+
+       checkVM();
+
+       int nRes = sqlite3_bind_blob(mpVM, nParam,
+
+                                                               (const void*)blobValue, nLen, SQLITE_TRANSIENT);
+
+
+
+       if (nRes != SQLITE_OK)
+
+       {
+
+               throw CppSQLite3Exception(nRes,
+
+                                                               "Error binding blob param",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+       
+
+void CppSQLite3Statement::bindNull(int nParam)
+
+{
+
+       checkVM();
+
+       int nRes = sqlite3_bind_null(mpVM, nParam);
+
+
+
+       if (nRes != SQLITE_OK)
+
+       {
+
+               throw CppSQLite3Exception(nRes,
+
+                                                               "Error binding NULL param",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::reset()
+
+{
+
+       if (mpVM)
+
+       {
+
+               int nRet = sqlite3_reset(mpVM);
+
+
+
+               if (nRet != SQLITE_OK)
+
+               {
+
+                       const char* szError = sqlite3_errmsg(mpDB);
+
+                       throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+               }
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::finalize()
+
+{
+
+       if (mpVM)
+
+       {
+
+               int nRet = sqlite3_finalize(mpVM);
+
+               mpVM = 0;
+
+
+
+               if (nRet != SQLITE_OK)
+
+               {
+
+                       const char* szError = sqlite3_errmsg(mpDB);
+
+                       throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+               }
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::checkDB()
+
+{
+
+       if (mpDB == 0)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Database not open",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+void CppSQLite3Statement::checkVM()
+
+{
+
+       if (mpVM == 0)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Null Virtual Machine pointer",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+CppSQLite3DB::CppSQLite3DB()
+
+{
+
+       mpDB = 0;
+
+       mnBusyTimeoutMs = 60000; // 60 seconds
+
+}
+
+
+
+
+
+CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)
+
+{
+
+       mpDB = db.mpDB;
+
+       mnBusyTimeoutMs = 60000; // 60 seconds
+
+}
+
+
+
+
+
+CppSQLite3DB::~CppSQLite3DB()
+
+{
+
+       close();
+
+}
+
+
+
+
+
+CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)
+
+{
+
+       mpDB = db.mpDB;
+
+       mnBusyTimeoutMs = 60000; // 60 seconds
+
+       return *this;
+
+}
+
+
+
+
+
+void CppSQLite3DB::open(const char* szFile)
+
+{
+
+       int nRet = sqlite3_open(szFile, &mpDB);
+
+
+
+       if (nRet != SQLITE_OK)
+
+       {
+
+               const char* szError = sqlite3_errmsg(mpDB);
+
+               throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+       }
+
+
+
+       setBusyTimeout(mnBusyTimeoutMs);
+
+}
+
+
+
+
+
+void CppSQLite3DB::close()
+
+{
+
+       if (mpDB)
+
+       {
+
+               sqlite3_close(mpDB);
+
+               mpDB = 0;
+
+       }
+
+}
+
+
+
+
+
+CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)
+
+{
+
+       checkDB();
+
+
+
+       sqlite3_stmt* pVM = compile(szSQL);
+
+       return CppSQLite3Statement(mpDB, pVM);
+
+}
+
+
+
+
+
+bool CppSQLite3DB::tableExists(const char* szTable)
+
+{
+
+       char szSQL[128];
+
+       sprintf(szSQL,
+
+                       "select count(*) from sqlite_master where type='table' and name='%s'",
+
+                       szTable);
+
+       int nRet = execScalar(szSQL);
+
+       return (nRet > 0);
+
+}
+
+
+
+
+
+int CppSQLite3DB::execDML(const char* szSQL)
+
+{
+
+       checkDB();
+
+
+
+       char* szError=0;
+
+
+
+       int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError);
+
+
+
+       if (nRet == SQLITE_OK)
+
+       {
+
+               return sqlite3_changes(mpDB);
+
+       }
+
+       else
+
+       {
+
+               throw CppSQLite3Exception(nRet, szError);
+
+       }
+
+}
+
+
+
+
+
+CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)
+
+{
+
+       checkDB();
+
+
+
+       sqlite3_stmt* pVM = compile(szSQL);
+
+
+
+       int nRet = sqlite3_step(pVM);
+
+
+
+       if (nRet == SQLITE_DONE)
+
+       {
+
+               // no rows
+
+               return CppSQLite3Query(mpDB, pVM, true/*eof*/);
+
+       }
+
+       else if (nRet == SQLITE_ROW)
+
+       {
+
+               // at least 1 row
+
+               return CppSQLite3Query(mpDB, pVM, false/*eof*/);
+
+       }
+
+       else
+
+       {
+
+               nRet = sqlite3_finalize(pVM);
+
+               const char* szError= sqlite3_errmsg(mpDB);
+
+               throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+int CppSQLite3DB::execScalar(const char* szSQL)
+
+{
+
+       CppSQLite3Query q = execQuery(szSQL);
+
+
+
+       if (q.eof() || q.numFields() < 1)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Invalid scalar query",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+
+
+       return atoi(q.fieldValue(0));
+
+}
+
+
+
+
+
+CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)
+
+{
+
+       checkDB();
+
+
+
+       char* szError=0;
+
+       char** paszResults=0;
+
+       int nRet;
+
+       int nRows(0);
+
+       int nCols(0);
+
+
+
+       nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError);
+
+
+
+       if (nRet == SQLITE_OK)
+
+       {
+
+               return CppSQLite3Table(paszResults, nRows, nCols);
+
+       }
+
+       else
+
+       {
+
+               throw CppSQLite3Exception(nRet, szError);
+
+       }
+
+}
+
+
+
+
+
+sqlite_int64 CppSQLite3DB::lastRowId()
+
+{
+
+       return sqlite3_last_insert_rowid(mpDB);
+
+}
+
+
+
+
+
+void CppSQLite3DB::setBusyTimeout(int nMillisecs)
+
+{
+
+       mnBusyTimeoutMs = nMillisecs;
+
+       sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs);
+
+}
+
+
+
+
+
+void CppSQLite3DB::checkDB()
+
+{
+
+       if (!mpDB)
+
+       {
+
+               throw CppSQLite3Exception(CPPSQLITE_ERROR,
+
+                                                               "Database not open",
+
+                                                               DONT_DELETE_MSG);
+
+       }
+
+}
+
+
+
+
+
+sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
+
+{
+
+       checkDB();
+
+
+
+       char* szError=0;
+
+       const char* szTail=0;
+
+       sqlite3_stmt* pVM;
+
+
+
+       int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail);
+
+
+
+       if (nRet != SQLITE_OK)
+
+       {
+
+               throw CppSQLite3Exception(nRet, szError);
+
+       }
+
+
+
+       return pVM;
+
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+// SQLite encode.c reproduced here, containing implementation notes and source
+
+// for sqlite3_encode_binary() and sqlite3_decode_binary() 
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+/*
+
+** 2002 April 25
+
+**
+
+** The author disclaims copyright to this source code.  In place of
+
+** a legal notice, here is a blessing:
+
+**
+
+**    May you do good and not evil.
+
+**    May you find forgiveness for yourself and forgive others.
+
+**    May you share freely, never taking more than you give.
+
+**
+
+*************************************************************************
+
+** This file contains helper routines used to translate binary data into
+
+** a null-terminated string (suitable for use in SQLite) and back again.
+
+** These are convenience routines for use by people who want to store binary
+
+** data in an SQLite database.  The code in this file is not used by any other
+
+** part of the SQLite library.
+
+**
+
+** $Id: CppSQLite3.cpp,v 1.4 2010/03/16 15:46:13 cervenansky Exp $
+
+*/
+
+
+
+/*
+
+** How This Encoder Works
+
+**
+
+** The output is allowed to contain any character except 0x27 (') and
+
+** 0x00.  This is accomplished by using an escape character to encode
+
+** 0x27 and 0x00 as a two-byte sequence.  The escape character is always
+
+** 0x01.  An 0x00 is encoded as the two byte sequence 0x01 0x01.  The
+
+** 0x27 character is encoded as the two byte sequence 0x01 0x03.  Finally,
+
+** the escape character itself is encoded as the two-character sequence
+
+** 0x01 0x02.
+
+**
+
+** To summarize, the encoder works by using an escape sequences as follows:
+
+**
+
+**       0x00  ->  0x01 0x01
+
+**       0x01  ->  0x01 0x02
+
+**       0x27  ->  0x01 0x03
+
+**
+
+** If that were all the encoder did, it would work, but in certain cases
+
+** it could double the size of the encoded string.  For example, to
+
+** encode a string of 100 0x27 characters would require 100 instances of
+
+** the 0x01 0x03 escape sequence resulting in a 200-character output.
+
+** We would prefer to keep the size of the encoded string smaller than
+
+** this.
+
+**
+
+** To minimize the encoding size, we first add a fixed offset value to each 
+
+** byte in the sequence.  The addition is modulo 256.  (That is to say, if
+
+** the sum of the original character value and the offset exceeds 256, then
+
+** the higher order bits are truncated.)  The offset is chosen to minimize
+
+** the number of characters in the string that need to be escaped.  For
+
+** example, in the case above where the string was composed of 100 0x27
+
+** characters, the offset might be 0x01.  Each of the 0x27 characters would
+
+** then be converted into an 0x28 character which would not need to be
+
+** escaped at all and so the 100 character input string would be converted
+
+** into just 100 characters of output.  Actually 101 characters of output - 
+
+** we have to record the offset used as the first byte in the sequence so
+
+** that the string can be decoded.  Since the offset value is stored as
+
+** part of the output string and the output string is not allowed to contain
+
+** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.
+
+**
+
+** Here, then, are the encoding steps:
+
+**
+
+**     (1)   Choose an offset value and make it the first character of
+
+**           output.
+
+**
+
+**     (2)   Copy each input character into the output buffer, one by
+
+**           one, adding the offset value as you copy.
+
+**
+
+**     (3)   If the value of an input character plus offset is 0x00, replace
+
+**           that one character by the two-character sequence 0x01 0x01.
+
+**           If the sum is 0x01, replace it with 0x01 0x02.  If the sum
+
+**           is 0x27, replace it with 0x01 0x03.
+
+**
+
+**     (4)   Put a 0x00 terminator at the end of the output.
+
+**
+
+** Decoding is obvious:
+
+**
+
+**     (5)   Copy encoded characters except the first into the decode 
+
+**           buffer.  Set the first encoded character aside for use as
+
+**           the offset in step 7 below.
+
+**
+
+**     (6)   Convert each 0x01 0x01 sequence into a single character 0x00.
+
+**           Convert 0x01 0x02 into 0x01.  Convert 0x01 0x03 into 0x27.
+
+**
+
+**     (7)   Subtract the offset value that was the first character of
+
+**           the encoded buffer from all characters in the output buffer.
+
+**
+
+** The only tricky part is step (1) - how to compute an offset value to
+
+** minimize the size of the output buffer.  This is accomplished by testing
+
+** all offset values and picking the one that results in the fewest number
+
+** of escapes.  To do that, we first scan the entire input and count the
+
+** number of occurances of each character value in the input.  Suppose
+
+** the number of 0x00 characters is N(0), the number of occurances of 0x01
+
+** is N(1), and so forth up to the number of occurances of 0xff is N(255).
+
+** An offset of 0 is not allowed so we don't have to test it.  The number
+
+** of escapes required for an offset of 1 is N(1)+N(2)+N(40).  The number
+
+** of escapes required for an offset of 2 is N(2)+N(3)+N(41).  And so forth.
+
+** In this way we find the offset that gives the minimum number of escapes,
+
+** and thus minimizes the length of the output string.
+
+*/
+
+
+
+/*
+
+** Encode a binary buffer "in" of size n bytes so that it contains
+
+** no instances of characters '\'' or '\000'.  The output is 
+
+** null-terminated and can be used as a string value in an INSERT
+
+** or UPDATE statement.  Use sqlite3_decode_binary() to convert the
+
+** string back into its original binary.
+
+**
+
+** The result is written into a preallocated output buffer "out".
+
+** "out" must be able to hold at least 2 +(257*n)/254 bytes.
+
+** In other words, the output will be expanded by as much as 3
+
+** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
+
+** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
+
+**
+
+** The return value is the number of characters in the encoded
+
+** string, excluding the "\000" terminator.
+
+*/
+
+int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out){
+
+  int i, j, e, m;
+
+  int cnt[256];
+
+  if( n<=0 ){
+
+    out[0] = 'x';
+
+    out[1] = 0;
+
+    return 1;
+
+  }
+
+  memset(cnt, 0, sizeof(cnt));
+
+  for(i=n-1; i>=0; i--){ cnt[in[i]]++; }
+
+  m = n;
+
+  for(i=1; i<256; i++){
+
+    int sum;
+
+    if( i=='\'' ) continue;
+
+    sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];
+
+    if( sum<m ){
+
+      m = sum;
+
+      e = i;
+
+      if( m==0 ) break;
+
+    }
+
+  }
+
+  out[0] = e;
+
+  j = 1;
+
+  for(i=0; i<n; i++){
+
+    int c = (in[i] - e)&0xff;
+
+    if( c==0 ){
+
+      out[j++] = 1;
+
+      out[j++] = 1;
+
+    }else if( c==1 ){
+
+      out[j++] = 1;
+
+      out[j++] = 2;
+
+    }else if( c=='\'' ){
+
+      out[j++] = 1;
+
+      out[j++] = 3;
+
+    }else{
+
+      out[j++] = c;
+
+    }
+
+  }
+
+  out[j] = 0;
+
+  return j;
+
+}
+
+
+
+/*
+
+** Decode the string "in" into binary data and write it into "out".
+
+** This routine reverses the encoding created by sqlite3_encode_binary().
+
+** The output will always be a few bytes less than the input.  The number
+
+** of bytes of output is returned.  If the input is not a well-formed
+
+** encoding, -1 is returned.
+
+**
+
+** The "in" and "out" parameters may point to the same buffer in order
+
+** to decode a string in place.
+
+*/
+
+int sqlite3_decode_binary(const unsigned char *in, unsigned char *out){
+
+  int i, c, e;
+
+  e = *(in++);
+
+  i = 0;
+
+  while( (c = *(in++))!=0 ){
+
+    if( c==1 ){
+
+      c = *(in++);
+
+      if( c==1 ){
+
+        c = 0;
+
+      }else if( c==2 ){
+
+        c = 1;
+
+      }else if( c==3 ){
+
+        c = '\'';
+
+      }else{
+
+        return -1;
+
+      }
+
+    }
+
+    out[i++] = (c + e)&0xff;
+
+  }
+
+  return i;
+
+}
+
diff --git a/src/CppSQLite3.h b/src/CppSQLite3.h
new file mode 100644 (file)
index 0000000..9d5bcd4
--- /dev/null
@@ -0,0 +1,618 @@
+////////////////////////////////////////////////////////////////////////////////
+
+// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
+
+//
+
+// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
+
+// 
+
+// Permission to use, copy, modify, and distribute this software and its
+
+// documentation for any purpose, without fee, and without a written
+
+// agreement, is hereby granted, provided that the above copyright notice, 
+
+// this paragraph and the following two paragraphs appear in all copies, 
+
+// modifications, and distributions.
+
+//
+
+// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
+
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
+
+// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+
+// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+
+// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+
+// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+
+// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
+
+// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+//
+
+// V3.0                03/08/2004      -Initial Version for sqlite3
+
+//
+
+// V3.1                16/09/2004      -Implemented getXXXXField using sqlite3 functions
+
+//                                             -Added CppSQLiteDB3::tableExists()
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _CppSQLite3_H_
+
+#define _CppSQLite3_H_
+
+
+
+#include "sqlite3.h"
+
+#include <cstdio>
+
+#include <cstring>
+
+
+
+#define CPPSQLITE_ERROR 1000
+
+
+
+class CppSQLite3Exception
+
+{
+
+public:
+
+
+
+    CppSQLite3Exception(const int nErrCode,
+
+                       char* szErrMess,
+
+                       bool bDeleteMsg=true);
+
+  CppSQLite3Exception(const int nErrCode,
+
+                     const char* szErrMess,
+
+                     bool bDeleteMsg=true);
+
+  
+
+    CppSQLite3Exception(const CppSQLite3Exception&  e);
+
+
+
+    virtual ~CppSQLite3Exception();
+
+
+
+    const int errorCode() { return mnErrCode; }
+
+
+
+    const char* errorMessage() { return mpszErrMess; }
+
+
+
+    static const char* errorCodeAsString(int nErrCode);
+
+
+
+private:
+
+
+
+    int mnErrCode;
+
+    char* mpszErrMess;
+
+};
+
+
+
+
+
+class CppSQLite3Buffer
+
+{
+
+public:
+
+
+
+    CppSQLite3Buffer();
+
+
+
+    ~CppSQLite3Buffer();
+
+
+
+    const char* format(const char* szFormat, ...);
+
+
+
+    operator const char*() { return mpBuf; }
+
+
+
+    void clear();
+
+
+
+private:
+
+
+
+    char* mpBuf;
+
+};
+
+
+
+
+
+class CppSQLite3Binary
+
+{
+
+public:
+
+
+
+    CppSQLite3Binary();
+
+
+
+    ~CppSQLite3Binary();
+
+
+
+    void setBinary(const unsigned char* pBuf, int nLen);
+
+    void setEncoded(const unsigned char* pBuf);
+
+
+
+    const unsigned char* getEncoded();
+
+    const unsigned char* getBinary();
+
+
+
+    int getBinaryLength();
+
+
+
+    unsigned char* allocBuffer(int nLen);
+
+
+
+    void clear();
+
+
+
+private:
+
+
+
+    unsigned char* mpBuf;
+
+    int mnBinaryLen;
+
+    int mnBufferLen;
+
+    int mnEncodedLen;
+
+    bool mbEncoded;
+
+};
+
+
+
+
+
+class CppSQLite3Query
+
+{
+
+public:
+
+
+
+    CppSQLite3Query();
+
+
+
+    CppSQLite3Query(const CppSQLite3Query& rQuery);
+
+
+
+    CppSQLite3Query(sqlite3* pDB,
+
+                               sqlite3_stmt* pVM,
+
+                bool bEof,
+
+                bool bOwnVM=true);
+
+
+
+    CppSQLite3Query& operator=(const CppSQLite3Query& rQuery);
+
+
+
+    virtual ~CppSQLite3Query();
+
+
+
+    int numFields();
+
+
+
+    int fieldIndex(const char* szField);
+
+    const char* fieldName(int nCol);
+
+
+
+    const char* fieldDeclType(int nCol);
+
+    int fieldDataType(int nCol);
+
+
+
+    const char* fieldValue(int nField);
+
+    const char* fieldValue(const char* szField);
+
+
+
+    int getIntField(int nField, int nNullValue=0);
+
+    int getIntField(const char* szField, int nNullValue=0);
+
+
+
+    double getFloatField(int nField, double fNullValue=0.0);
+
+    double getFloatField(const char* szField, double fNullValue=0.0);
+
+
+
+    const char* getStringField(int nField, const char* szNullValue="");
+
+    const char* getStringField(const char* szField, const char* szNullValue="");
+
+
+
+    const unsigned char* getBlobField(int nField, int& nLen);
+
+    const unsigned char* getBlobField(const char* szField, int& nLen);
+
+
+
+    bool fieldIsNull(int nField);
+
+    bool fieldIsNull(const char* szField);
+
+
+
+    bool eof();
+
+
+
+    void nextRow();
+
+
+
+    void finalize();
+
+
+
+private:
+
+
+
+    void checkVM();
+
+
+
+       sqlite3* mpDB;
+
+    sqlite3_stmt* mpVM;
+
+    bool mbEof;
+
+    int mnCols;
+
+    bool mbOwnVM;
+
+};
+
+
+
+
+
+class CppSQLite3Table
+
+{
+
+public:
+
+
+
+    CppSQLite3Table();
+
+
+
+    CppSQLite3Table(const CppSQLite3Table& rTable);
+
+
+
+    CppSQLite3Table(char** paszResults, int nRows, int nCols);
+
+
+
+    virtual ~CppSQLite3Table();
+
+
+
+    CppSQLite3Table& operator=(const CppSQLite3Table& rTable);
+
+
+
+    int numFields();
+
+
+
+    int numRows();
+
+
+
+    const char* fieldName(int nCol);
+
+
+
+    const char* fieldValue(int nField);
+
+    const char* fieldValue(const char* szField);
+
+
+
+    int getIntField(int nField, int nNullValue=0);
+
+    int getIntField(const char* szField, int nNullValue=0);
+
+
+
+    double getFloatField(int nField, double fNullValue=0.0);
+
+    double getFloatField(const char* szField, double fNullValue=0.0);
+
+
+
+    const char* getStringField(int nField, const char* szNullValue="");
+
+    const char* getStringField(const char* szField, const char* szNullValue="");
+
+
+
+    bool fieldIsNull(int nField);
+
+    bool fieldIsNull(const char* szField);
+
+
+
+    void setRow(int nRow);
+
+
+
+    void finalize();
+
+
+
+private:
+
+
+
+    void checkResults();
+
+
+
+    int mnCols;
+
+    int mnRows;
+
+    int mnCurrentRow;
+
+    char** mpaszResults;
+
+};
+
+
+
+
+
+class CppSQLite3Statement
+
+{
+
+public:
+
+
+
+    CppSQLite3Statement();
+
+
+
+    CppSQLite3Statement(const CppSQLite3Statement& rStatement);
+
+
+
+    CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM);
+
+
+
+    virtual ~CppSQLite3Statement();
+
+
+
+    CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);
+
+
+
+    int execDML();
+
+
+
+    CppSQLite3Query execQuery();
+
+
+
+    void bind(int nParam, const char* szValue);
+
+    void bind(int nParam, const int nValue);
+
+    void bind(int nParam, const double dwValue);
+
+    void bind(int nParam, const unsigned char* blobValue, int nLen);
+
+    void bindNull(int nParam);
+
+
+
+    void reset();
+
+
+
+    void finalize();
+
+
+
+private:
+
+
+
+    void checkDB();
+
+    void checkVM();
+
+
+
+    sqlite3* mpDB;
+
+    sqlite3_stmt* mpVM;
+
+};
+
+
+
+
+
+class CppSQLite3DB
+
+{
+
+public:
+
+
+
+    CppSQLite3DB();
+
+
+
+    virtual ~CppSQLite3DB();
+
+
+
+    void open(const char* szFile);
+
+
+
+    void close();
+
+
+
+       bool tableExists(const char* szTable);
+
+
+
+    int execDML(const char* szSQL);
+
+
+
+    CppSQLite3Query execQuery(const char* szSQL);
+
+
+
+    int execScalar(const char* szSQL);
+
+
+
+    CppSQLite3Table getTable(const char* szSQL);
+
+
+
+    CppSQLite3Statement compileStatement(const char* szSQL);
+
+
+
+    sqlite_int64 lastRowId();
+
+
+
+    void interrupt() { sqlite3_interrupt(mpDB); }
+
+
+
+    void setBusyTimeout(int nMillisecs);
+
+
+
+    static const char* SQLiteVersion() { return SQLITE_VERSION; }
+
+
+
+private:
+
+
+
+    CppSQLite3DB(const CppSQLite3DB& db);
+
+    CppSQLite3DB& operator=(const CppSQLite3DB& db);
+
+
+
+    sqlite3_stmt* compile(const char* szSQL);
+
+
+
+    void checkDB();
+
+
+
+    sqlite3* mpDB;
+
+    int mnBusyTimeoutMs;
+
+};
+
+
+
+#endif
+
diff --git a/src/OldcreaImageIOGimmickView.h b/src/OldcreaImageIOGimmickView.h
new file mode 100644 (file)
index 0000000..3aa98ac
--- /dev/null
@@ -0,0 +1,162 @@
+namespace creaImageIO
+{
+       /**
+       * \ingroup View
+       */
+    //=====================================================================
+    
+    //=====================================================================
+    ///Abstract class that handles views, attributes and previews (GUI) for Gimmick.
+       class GimmickView
+    {
+    public:
+      /// Ctor
+      GimmickView();
+      /// Virtual destructor
+      virtual ~GimmickView();
+
+       //====================================================================
+       // General
+       //====================================================================
+
+    /// Returns the size of the current selection
+    virtual int GetSelectionSize() { return 0; } 
+    /// Returns true if there is a valid selection
+    virtual bool IsSelectionValid(){ return false; }
+    /// Returns the vector of full filenames of selected images
+    virtual void GetSelectedFiles(std::vector<std::string>&){ return; }
+    /// Returns the vector of images corresponding to selection
+    virtual void GetSelectedImages(std::vector<vtkImageData*>&){ return; }
+    /// Returns the vector of DicomNode corresponding to selection
+    virtual void GetSelectedDicomNodes(std::vector<DicomNode*>&){ return; }
+   /// Returns the DicomNode corresponding to the tree item
+    virtual DicomNode* GetDicomNodeOfItem(const TreeItemId& i);
+
+       
+       /// Type of list of DicomDatabase
+    typedef std::vector<DicomDatabase*> DicomDatabaseListType;
+    /// Returns the list of DicomDatabase open
+    virtual DicomDatabaseListType& GetDicomDatabaseList() 
+    { return null; }
+    /// Returns the list of DicomDatabase open (const)
+    virtual const DicomDatabaseListType& GetDicomDatabaseList() const 
+    { return null; }
+
+       protected:
+       ///Opens an existing database, or else, creates a local database.
+    virtual void OpenOrNewDatabase(bool open){ return; }
+       ///Shows the help
+       virtual void ShowHelp();
+
+       private:
+       ///Gets the extension of the database
+       const std::string& GetDatabaseExtension() { return null; }
+       ///Sets the extension of the database
+    virtual void SetDatabaseExtension(const std::string& ext){ return; }
+
+
+       //====================================================================
+    // Preview Display Related
+       //====================================================================
+
+
+    ///Shows the image sent as a parameter
+       private:
+        virtual void ShowImage(vtkImageData* image){ return; }
+
+       //====================================================================
+    // Favorites Related
+       //====================================================================
+
+
+       public:
+       ///Loads or creates a favorites database
+    virtual void LoadOrCreateFavoritesDatabase(){ return; }
+       private:
+       ///Creates the user settings directory
+    void CreateUserSettingsDirectory(){ return; }
+       ///Obtains the user settings directory
+       const std::string& GetUserSettingsDirectory(){ return null; }
+
+       //====================================================================  
+       // Attribute Display Related
+       //====================================================================
+
+
+       ///Shows the Information regarding the node sent as a parameter
+       private:
+     virtual void ShowInformation(DicomNode*){ return; }
+   
+       //====================================================================
+    // Tree Display Related
+    //====================================================================
+
+       protected:
+    /// Completely rebuilds the view with 
+    /// current DicomDatabaseList
+    virtual void RebuildView(){ return; }
+       /// Recursively updates the part of the view corresponding 
+    /// to the DicomDatabase passed
+    /// i.e. creates items for the DicomNode which do not have
+    ///      deletes obsolete items (whose DicomNode has been deleted)
+    virtual void UpdateDicomDatabaseView(DicomDatabase*){ return; }
+    /// Recursively updates the part of the view corresponding 
+    /// to the DicomNode provided.
+    /// parent is its parent in the tree (where to insert / remove it)
+       virtual void UpdateDicomNodeView(DicomNode* n, const TreeItemId& parent){ return; }
+    
+       private:
+       ///Type definition of the data regarding the tree
+    typedef WxGimmickTreeItemData TreeItemData;
+       ///Gets the item data of the tree item passed as a parameter
+    TreeItemData* GetItemData(const TreeItemId& id){ return null; }
+    ///Type definition of the data insid a node of the tree
+    typedef WxGimmickDicomNodeData NodeData;
+
+
+       //====================================================================
+    // Class Attributes
+    //====================================================================
+
+       
+       int mSelectionType;
+    int mSelectionMaxImageDimension;
+    int mCurrentSelectionImageSize[4];
+
+       ///Existent Database List
+    DicomDatabaseListType mDicomDatabaseList;
+       ///Favorites database
+    DicomDatabase* mFavoriteDatabase;
+
+       ///Path to the database list file
+    std::string mDatabaseListFile;
+       ///Extension of the database
+    std::string mDatabaseExtension;
+
+    bool mJustStarted;
+
+    int  mFirstDicomDatabaseIconIndex;
+
+   // Previewer
+    vtkImageViewer2* mViewer;
+    
+    int mx1,mx2,my1,my2,mz1,mz2;
+    double mspx,mspy,mspz;
+  
+    // Image preview :
+    // Multi-thread image reader
+    MultiThreadImageReader mReader;
+    // map of images name to node
+    std::map<std::string,DicomNode*> mImageFileNameToNode;
+  
+    //Controller which manages the interaction with the model
+       Gimmick* controller;
+
+    };
+    // EO class GimmickView
+    //=====================================================================
+  
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
\ No newline at end of file
diff --git a/src/README.txt b/src/README.txt
new file mode 100644 (file)
index 0000000..fbe4fd9
--- /dev/null
@@ -0,0 +1,71 @@
+New architecture created on 04/02/09 following a MVC approach
+
+Elements of the architecture:
+
+* Data structure: Attributed tree
+--------------------------------------
+in namespace creaImageIO::tree
+Tree :   Attributed tree structure
+        inherits Node
+        holds a vector of root TreeNode 
+TreeData : Abstract class to store user data on a tree
+Node : 
+        belong to a Tree, 
+        holds a pointer on parent Node, 
+        holds a vector of children Node
+NodeData : Abstract class to store user data on a tree node
+Descriptor : Descriptor of the structure a tree (number of levels, descriptors of each level, ...)
+         
+        holds a vector of LevelDescriptor
+LevelDescriptor : 
+         holds a vector of TreeAttributeDescriptor
+AttributeDescriptor :
+        stores name, dicom group/elem, flags
+Comparator: Abstract definition of a comparator of Node
+           Comparison is done by operator()(Node* const &, Node* const &)
+ComparatorWithOrder : Abstract Comparator whose order can be reversed
+                   Concrete comparison is done by method compare(Node* const &, Node* const &)
+LexicographicalComparator :  A Comparator which stores a vector of Comparators and which performs lexicographical comparison               
+
+IntComparator    : Compares the values of a given Attribute of the Nodes which is decoded as an int    value
+FloatComparator  : Compares the values of a given Attribute of the Nodes which is decoded as a  float  value
+StringComparator : Compares the values of a given Attribute of the Nodes which is decoded as a  string value
+
+
+* Models : TreeHandler and descendants
+--------------------------------------
+
+TreeHandler : Abstract class which 'handles' a Tree structure.
+           Can:
+           Load the children of a given Node
+
+SQLiteTreeHandler : Concrete TreeHandler which manages a tree stored in a sqlite database
+CppSQLite3.h / CppSQLite3.cpp : C++ interface to sqlite db
+...
+
+ImageFinder : Parses (recursively) a part of a filesystem to look for known images and load their attributes in order to add the images to a Tree (submission via a TreeHandler::AddBranch)
+
+
+* Image handling
+----------------
+
+creaImageIOImageReader.h/cpp :
+SpecificImageReader
+ImageReader
+
+creaImageIOMultiThreadImageReader.h/cpp
+creaImageIOIndexedHeap.h/cpp
+
+* Views :
+---------
+TreeView
+WxTreeView
+WxGimmickView
+QTreeView 
+QGimmickView
+...
+
+* Controller :
+--------------
+Gimmick
+...
diff --git a/src/creaImageIOAbstractImageReader.h b/src/creaImageIOAbstractImageReader.h
new file mode 100644 (file)
index 0000000..3957f3a
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __creaImageIOAbstractImageReader_h_INCLUDED__
+#define __creaImageIOAbstractImageReader_h_INCLUDED__
+
+
+#include <vtkImageData.h>
+#include <string>
+#include <map>
+#include <vector>
+#include "creaImageIOTreeAttributeMapType.h"
+
+namespace creaImageIO
+{
+
+
+  /**
+   * \ingroup IO
+   */
+  
+  //=====================================================================
+  /// Abstract image reader 
+  class AbstractImageReader 
+  {
+  public:
+    AbstractImageReader() {}
+    virtual ~AbstractImageReader() {}
+
+       /// Get the reader's name
+    const std::string& GetName() const { return mName; }
+
+       /// Add file extensions read by the reader
+    virtual void PushBackExtensions(std::vector<std::string>&) {}
+
+       /// Test if file is read by this reader
+    virtual bool CanRead(const std::string& filename) { return false; }
+
+       /// return for a file a 2D VTkImage
+    virtual vtkImageData* ReadImage(const std::string& filename) { return 0; } 
+
+       /// Read the attributes for a file
+    virtual void ReadAttributes(const std::string& filename, 
+                               tree::AttributeMapType& attr) {}
+
+  protected:
+
+    /// Set the reader's name
+    void SetName(const std::string& s) { mName = s; }
+  private:
+    std::string mName;
+  };
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIOAbstractImageReader_h_INCLUDED__
diff --git a/src/creaImageIODicomImageReader.cpp b/src/creaImageIODicomImageReader.cpp
new file mode 100644 (file)
index 0000000..05ea3b2
--- /dev/null
@@ -0,0 +1,162 @@
+#include <creaImageIODicomImageReader.h>
+
+#include <vtkGdcmReader.h>
+
+
+
+#include <creaImageIOSystem.h>
+#include "boost/filesystem/path.hpp"
+
+#include <creaImageIOTreeAttributeDescriptor.h>
+#include <vtkStringArray.h>
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+
+  //=====================================================================
+  DicomImageReader::DicomImageReader()
+  {
+    mReader = vtkGdcmReader::New();
+//EED  mReader->SetFlipY(false);
+    SetName ( "Dicom" );
+
+  };
+  //=====================================================================
+  
+  //=====================================================================
+  DicomImageReader::~DicomImageReader()
+  {
+    mReader->Delete();
+  }
+  //=====================================================================
+
+  //=====================================================================  
+  bool DicomImageReader::CanRead(const std::string& filename)
+  { 
+    GDCM_NAME_SPACE::Document*doc;
+    GDCM_NAME_SPACE::File* file = GDCM_NAME_SPACE::File::New();
+    file->SetLoadMode( GDCM_NAME_SPACE::LD_ALL);
+    file->SetFileName(filename.c_str());
+    file->Load();
+    bool ok = file->IsReadable();
+       if(!ok)
+       {
+               doc = (GDCM_NAME_SPACE::Document*)file; 
+               ok = doc->IsReadable();
+       }
+    file->Delete();
+    return ok;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  vtkImageData* DicomImageReader::ReadImage(const std::string& filename)
+  {
+    vtkImageData* im = 0;
+    try
+      {
+       mReader->SetFileName(filename.c_str());
+       mReader->Update();
+       im = vtkImageData::New();
+       im->ShallowCopy(mReader->GetOutput());
+      }
+    catch (...)
+      {
+       if (im!=0) im->Delete();
+         im = 0;
+      }
+    return im;
+  }
+
+  //=====================================================================
+  void DicomImageReader::PushBackExtensions(std::vector<std::string>& v)
+  {
+    v.push_back("dcm");
+    v.push_back("");
+  }
+  //=====================================================================
+  
+  //========================================================================
+  std::string irclean(const std::string& str)
+  {
+         if(str.size() > 0)
+         {
+               if (str == "GDCM::Unfound") 
+                 {
+               return "";
+                 }
+               if (str[str.size()-1]==' ')
+                 {
+               return irclean(str.substr(0,str.size()-1));
+                 }
+               if (str[str.size()-1]==0)
+                 {
+               return irclean(str.substr(0,str.size()-1));
+                 }
+         }
+    
+    return str;
+  }
+  //========================================================================
+  //=====================================================================
+  void DicomImageReader::ReadAttributes(const std::string& filename, 
+                     std::map<std::string,std::string>& attr)
+  {
+    GimmickMessage(2,"Reading attributes from DICOM file '"
+                  <<filename<<"'"<<std::endl);
+
+    GDCM_NAME_SPACE::File* file = GDCM_NAME_SPACE::File::New();
+       //boost::shared_ptr<GDCM_NAME_SPACE::File> file(GDCM_NAME_SPACE::File::New());//, DicomImageReader::deleter());
+
+    GDCM_NAME_SPACE::Document *doc= GDCM_NAME_SPACE::File::New();
+    doc->SetLoadMode( GDCM_NAME_SPACE::LD_ALL);
+    doc->SetFileName(filename.c_str());
+    doc->Load();
+    file->SetLoadMode( GDCM_NAME_SPACE::LD_ALL);
+    file->SetFileName(filename.c_str());
+    file->Load();
+    if (file->IsReadable())// ||((GDCM_NAME_SPACE::Document*) file)->IsReadable())
+      {
+       std::map<std::string,std::string>::iterator i;
+       for (i=attr.begin();i!=attr.end();++i)
+         {
+           if ( i->first == "D0004_1500" )
+             {
+               boost::filesystem::path full_path(filename);
+               std::string f = full_path.leaf();
+               i->second = f;
+             }
+           else if ( i->first == "FullFileName" )
+             {
+               i->second = filename;
+             }
+                 else if ( i->first == "FullFileDirectory" )
+             {
+                         std::string::size_type last_pos = filename.find_last_of("//");
+                         //find first separator
+                         i->second = filename.substr(0, last_pos);
+             }
+           else
+             {
+               uint16_t el;
+               uint16_t gr;
+               
+               tree::AttributeDescriptor::GetDicomGroupElementFromKey(i->first,gr,el);
+               if ( ( gr!=0 ) && ( el!=0 ) )
+                 {
+                   std::string val =  file->GetEntryString(gr,el);
+                   i->second = irclean(val);
+                 }
+             }
+         }
+      }
+  }
+
+  //=====================================================================
+  
+} // namespace creaImageIO
+
diff --git a/src/creaImageIODicomImageReader.h b/src/creaImageIODicomImageReader.h
new file mode 100644 (file)
index 0000000..00f5cb0
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __creaImageIODicomImageReader_h_INCLUDED__
+#define __creaImageIODicomImageReader_h_INCLUDED__
+
+
+#include <creaImageIOAbstractImageReader.h>
+#include <gdcmFile.h> 
+// forward decl
+class vtkGdcmReader;
+
+namespace creaImageIO
+{
+
+
+  /**
+   * \ingroup IO
+   */
+  
+  //=====================================================================
+  /// Concrete image reader for DICOM images 
+  class DicomImageReader : virtual public AbstractImageReader
+  {
+  public:
+    DicomImageReader();
+    virtual ~DicomImageReader();
+
+       /// Add file extensions read by the reader
+    virtual void PushBackExtensions(std::vector<std::string>&);
+       /// Test if file is read by this reader
+    virtual bool CanRead(const std::string& filename);
+       /// return for a file a 2D VTkImage
+    virtual vtkImageData* ReadImage(const std::string& filename);
+       /// Read the attributes for a file
+    virtual void ReadAttributes(const std::string& filename, 
+                               tree::AttributeMapType& attr);
+
+  private:
+    vtkGdcmReader* mReader;
+       struct deleter
+       {
+               
+       };
+       friend struct deleter;
+  };
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIODicomImageReader_h_INCLUDED__
diff --git a/src/creaImageIODicomImageReader2.cpp b/src/creaImageIODicomImageReader2.cpp
new file mode 100644 (file)
index 0000000..3dd8120
--- /dev/null
@@ -0,0 +1,235 @@
+#include <creaImageIODicomImageReader2.h>
+
+
+
+#include <creaImageIOSystem.h>
+#include "boost/filesystem/path.hpp"
+
+#include <creaImageIOTreeAttributeDescriptor.h>
+#include <vtkStringArray.h>
+#include <creaImageIOGimmick.h>
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+
+  //=====================================================================
+  DicomImageReader::DicomImageReader()
+  {
+         mReader =  vtkGDCMImageReader::New();
+    SetName ( "Dicom" );
+       
+  };
+  //=====================================================================
+  
+  //=====================================================================
+  DicomImageReader::~DicomImageReader()
+  {
+         mReader->Delete();
+  }
+  //=====================================================================
+
+  //=====================================================================  
+  bool DicomImageReader::CanRead(const std::string& filename)
+  { 
+         gdcm::Reader reader;
+      reader.SetFileName( filename.c_str() );
+      return  reader.Read();
+        
+  }
+  //=====================================================================
+
+  //=====================================================================
+  vtkImageData* DicomImageReader::ReadImage(const std::string& filename)
+  {
+    vtkImageData* im = 0;
+    try
+      {
+       mReader->SetFileName(filename.c_str());
+       mReader->Update();
+       im = vtkImageData::New();
+       im->ShallowCopy(mReader->GetOutput());
+      }
+    catch (...)
+      {
+       if (im!=0) im->Delete();
+         im = 0;
+      }
+    return im;
+  }
+
+  //=====================================================================
+  void DicomImageReader::PushBackExtensions(std::vector<std::string>& v)
+  {
+    v.push_back("dcm");
+    v.push_back("");
+  }
+  //=====================================================================
+  
+  //========================================================================
+  std::string irclean(const std::string& str)
+  {
+         if(str.size() > 0)
+         {
+               if (str == "GDCM::Unfound") 
+                 {
+               return "";
+                 }
+               if (str[str.size()-1]==' ')
+                 {
+               return irclean(str.substr(0,str.size()-1));
+                 }
+               if (str[str.size()-1]==0)
+                 {
+               return irclean(str.substr(0,str.size()-1));
+                 }
+         }
+    
+    return str;
+  }
+  //========================================================================
+  //=====================================================================
+  void DicomImageReader::ReadAttributes(const std::string& filename, 
+                     std::map<std::string,std::string>& attr)
+  {
+    GimmickMessage(2,"Reading attributes from DICOM file '"
+                  <<filename<<"'"<<std::endl);
+
+   
+        gdcm::Reader reader;
+      reader.SetFileName( filename.c_str() );
+         if (reader.Read())
+      {
+       std::map<std::string,std::string>::iterator i;
+       for (i=attr.begin();i!=attr.end();++i)
+         {
+           if ( i->first == "D0004_1500" )
+             {
+               boost::filesystem::path full_path(filename);
+               std::string f = full_path.leaf();
+               i->second = f;
+             }
+           else if ( i->first == "FullFileName" )
+             {
+               i->second = filename;
+             }
+                 else if ( i->first == "FullFileDirectory" )
+             {
+                         std::string::size_type last_pos = filename.find_last_of("//");
+                         //find first separator
+                         i->second = filename.substr(0, last_pos);
+             }
+           else
+             {
+               uint16_t el;
+               uint16_t gr;
+               
+               tree::AttributeDescriptor::GetDicomGroupElementFromKey(i->first,gr,el);
+               if ( ( gr!=0 ) && ( el!=0 ) )
+                 {
+                          gdcm::DataElement de( gdcm::Tag(gr,el) );
+                          std::string val = GetStringValueFromTag(reader.GetFile().GetDataSet().GetDataElement(gdcm::Tag(gr,el)));
+                   i->second = irclean(val);
+                 }
+             }
+         }
+      }
+  }
+
+void DicomImageReader::ReadAttributes2(const std::string& filename, 
+                     std::map<std::string,std::string>& attr)
+  {
+      
+       if(!b_loaded)
+       {
+               std::map<std::string,std::string>::iterator i;
+               for (i=attr.begin();i!=attr.end();++i)
+                 {
+                       if ( i->first == "D0004_1500" ||  i->first == "FullFileName" || i->first == "FullFileDirectory" )
+                       {
+                       
+                       }
+                       else
+                       {
+                       uint16_t el;
+                       uint16_t gr;
+                       
+                       tree::AttributeDescriptor::GetDicomGroupElementFromKey(i->first,gr,el);
+                       mscan.AddTag(gdcm::Tag(gr,el) );
+                       }
+               }
+               b_loaded = true;
+       }
+        bool b = mscan.IsKey(filename.c_str());
+     if( b )
+      {
+                 const gdcm::Scanner::TagToValue &mapping = mscan.GetMapping(filename.c_str());
+                 gdcm::Scanner::TagToValue::const_iterator it = mapping.begin();
+                 std::map<std::string, std::string>::iterator i;
+               for (i=attr.begin();i!=attr.end();++i, ++it)
+               {
+                       if ( i->first == "D0004_1500" )
+                       {
+                               boost::filesystem::path full_path(filename);
+                               std::string f = full_path.leaf();
+                               i->second = f;
+                       }
+                       else if ( i->first == "FullFileName" )
+                       {
+                               i->second = filename;
+                       }
+                       else if ( i->first == "FullFileDirectory" )
+                       {
+                                 std::string::size_type last_pos = filename.find_last_of("//");
+                                 //find first separator
+                                 i->second = filename.substr(0, last_pos);
+                       }
+                       else
+                       {
+                               const char *value = it->second;
+                               i->second = irclean(it->second);
+                       }
+               }
+        }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  const std::string DicomImageReader::GetStringValueFromTag(const gdcm::DataElement& de)
+{
+  static std::string buffer;
+  buffer = "";  // cleanup previous call
+
+
+    const gdcm::ByteValue *bv = de.GetByteValue();
+    if( bv ) // Can be Type 2
+      {
+      buffer = std::string( bv->GetPointer(), bv->GetLength() );
+      // Will be padded with at least one \0
+      }
+
+
+  // Since return is a const char* the very first \0 will be considered
+  return buffer.c_str();
+}
+  //=====================================================================
+  
+} // namespace creaImageIO
+
diff --git a/src/creaImageIODicomImageReader2.h b/src/creaImageIODicomImageReader2.h
new file mode 100644 (file)
index 0000000..08b01f3
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __creaImageIODicomImageReader_h_INCLUDED__
+#define __creaImageIODicomImageReader_h_INCLUDED__
+
+
+#include <creaImageIOAbstractImageReader.h>
+#if defined(USE_GDCM2)
+#include <gdcmReader.h>
+#include <vtkGDCMImageReader.h>
+#include <gdcmScanner.h>
+#endif
+
+class vtkGDCMImageReader;
+
+namespace creaImageIO
+{
+
+
+  /**
+   * \ingroup IO
+   */
+  
+  //=====================================================================
+  /// Concrete image reader for DICOM images 
+  class DicomImageReader : virtual public AbstractImageReader
+  {
+  public:
+    DicomImageReader();
+    virtual ~DicomImageReader();
+
+       /// Add file extensions read by the reader
+    virtual void PushBackExtensions(std::vector<std::string>&);
+       /// Test if file is read by this reader
+    virtual bool CanRead(const std::string& filename);
+       /// return for a file a 2D VTkImage
+    virtual vtkImageData* ReadImage(const std::string& filename);
+       /// Read the attributes for a file
+    virtual void ReadAttributes(const std::string& filename, 
+                               tree::AttributeMapType& attr);
+       void ReadAttributes2(const std::string& filename, 
+                               tree::AttributeMapType& attr);
+
+  private:
+         const std::string GetStringValueFromTag( const gdcm::DataElement& ds);
+         vtkGDCMImageReader *mReader;
+         gdcm::Scanner mscan;
+         bool b_loaded;
+       struct deleter
+       {
+               void operator()(gdcm::File* p)
+               {
+                       delete p;
+               }
+       };
+       friend struct deleter;
+  };
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIODicomImageReader_h_INCLUDED__
diff --git a/src/creaImageIODicomScanner.cpp b/src/creaImageIODicomScanner.cpp
new file mode 100644 (file)
index 0000000..43706c1
--- /dev/null
@@ -0,0 +1,229 @@
+#include <creaImageIODicomScanner.h>
+#include "creaImageIOSystem.h"
+#include <boost/filesystem.hpp>
+#include "boost/algorithm/string.hpp"
+
+
+
+#include <creaImageIOSystem.h>
+#include "boost/filesystem/path.hpp"
+
+#include <creaImageIOTreeAttributeDescriptor.h>
+#include <vtkStringArray.h>
+#include <creaImageIOGimmick.h>
+#include <gdcmDirectory.h>
+
+#include <fstream>
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+
+  //=====================================================================
+  DicomImageScanner::DicomImageScanner()
+  {
+         mReader =  vtkGDCMImageReader::New();
+       mscan.ClearTags();
+       b_loaded = false;
+  };
+  //=====================================================================
+  
+  //=====================================================================
+  DicomImageScanner::~DicomImageScanner()
+  {
+         mReader->Delete();
+  }
+  //=====================================================================
+
+  //=====================================================================  
+  bool DicomImageScanner::addDirectory(std::string& filename,  std::map<std::string,std::string>& attr)
+  { 
+               if(!b_loaded)
+       {
+               mscan.ClearTags();
+               std::map<std::string,std::string>::iterator i;
+               int j= 0;
+               for (i=attr.begin();i!=attr.end();++i, j++)
+                 {
+                       if ( i->first == "D0004_1500" ||  i->first == "FullFileName" || i->first == "FullFileDirectory" )
+                       {
+                       
+                       }
+                       else
+                       {
+                       uint16_t el;
+                       uint16_t gr;
+                       
+                       tree::AttributeDescriptor::GetDicomGroupElementFromKey(i->first,gr,el);
+                       mscan.AddTag(gdcm::Tag(gr,el) );
+                       
+                       }
+               }
+               b_loaded = true;
+       }
+         gdcm::Directory d;
+           
+         boost::algorithm::replace_all(filename,"\\", "/");
+         d.Load(filename.c_str(),true);
+         mscan.Scan(d.GetFilenames());
+         
+      return  true;
+        
+  }
+  //=====================================================================
+
+  //=====================================================================
+  vtkImageData* DicomImageScanner::ReadImage(const std::string& filename)
+  {
+    vtkImageData* im = 0;
+    try
+      {
+       mReader->SetFileName(filename.c_str());
+       mReader->Update();
+       im = vtkImageData::New();
+       im->ShallowCopy(mReader->GetOutput());
+      }
+    catch (...)
+      {
+       if (im!=0) im->Delete();
+         im = 0;
+      }
+    return im;
+  }
+
+
+  //=====================================================================
+  
+  //========================================================================
+  std::string DicomImageScanner::irclean(const std::string& str)
+  {
+         if(str.size() > 0)
+         {
+               if (str == "GDCM::Unfound") 
+                 {
+               return "";
+                 }
+               if (str[str.size()-1]==' ')
+                 {
+               return irclean(str.substr(0,str.size()-1));
+                 }
+               if (str[str.size()-1]==0)
+                 {
+               return irclean(str.substr(0,str.size()-1));
+                 }
+         }
+    
+    return str;
+  }
+  //========================================================================
+  //=====================================================================
+
+void DicomImageScanner::ReadAttributes(const std::string& filename, 
+                     std::map<std::string,std::string>& attr)
+  {
+         std::string name = "E:\\data-images\\dicoms\\CD1\\DICOM\\09112417\\37390000/31582235";
+
+        bool b = mscan.IsKey(filename.c_str());
+    if( b )      {
+                 const gdcm::Scanner::TagToValue &mapping = mscan.GetMapping(filename.c_str());
+                 gdcm::Scanner::TagToValue::const_iterator it = mapping.begin();
+
+                 std::map<std::string, std::string>::iterator i;
+                 int j= 0;
+
+                 
+                 
+                 for (;it != mapping.end(); ++it)
+                 {
+                                       /*std::stringstream val;
+                                       val <<  "D";
+                                       val << std::hex << it->first.GetGroup() ;
+                                       val << "_";;
+                                       val << std::hex <<  it->first.GetElement();
+                                       var >> key*/
+                                char key[12] ;
+                                 
+                                 sprintf(key,"D%04x_%04x", it->first.GetGroup(), it->first.GetElement());
+                                 attr[key] = irclean(it->second);
+                 }
+                 
+                 
+                /* 
+                 
+                 
+                 for (i=attr.begin();i!=attr.end();++i, j++)
+               {*/
+                       if ( attr.find("D0004_1500") != attr.end())
+                       {
+                               boost::filesystem::path full_path(filename);
+                               std::string f = full_path.leaf();
+                               attr["D0004_1500"] = f;
+                       }
+                       if ( attr.find("FullFileName")!= attr.end())
+                       {
+                               attr["FullFileName"] = filename;
+                       }
+                       if ( attr.find("FullFileDirectory" )!= attr.end())
+                       {
+                                 std::string::size_type last_pos = filename.find_last_of("//");
+                                 //find first separator
+                                 attr["FullFileDirectory" ] = filename.substr(0, last_pos);
+                       }
+               //      else
+               //      {
+
+               //              uint16_t el;
+               //              uint16_t gr;
+
+               //              tree::AttributeDescriptor::GetDicomGroupElementFromKey(i->first,gr,el);
+
+               //      mscan.AddTag(gdcm::Tag(gr,el) );
+
+               //      //      const char *value = it->second;
+               //              i->second = irclean(it->second);
+               //              ++it;
+               //      }
+               //}
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  const std::string DicomImageScanner::GetStringValueFromTag(const gdcm::DataElement& de)
+{
+  static std::string buffer;
+  buffer = "";  // cleanup previous call
+
+
+    const gdcm::ByteValue *bv = de.GetByteValue();
+    if( bv ) // Can be Type 2
+      {
+      buffer = std::string( bv->GetPointer(), bv->GetLength() );
+      // Will be padded with at least one \0
+      }
+
+
+  // Since return is a const char* the very first \0 will be considered
+  return buffer.c_str();
+}
+  //=====================================================================
+  
+} // namespace creaImageIO
+
diff --git a/src/creaImageIODicomScanner.h b/src/creaImageIODicomScanner.h
new file mode 100644 (file)
index 0000000..9209751
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __creaImageIODicomScanner_h_INCLUDED__
+#define __creaImageIODicomScanner_h_INCLUDED__
+
+#include "creaImageIOTree.h"
+
+#if defined(USE_GDCM2)
+#include <gdcmReader.h>
+#include <vtkGDCMImageReader.h>
+#include <gdcmScanner.h>
+#endif
+
+class vtkGDCMImageReader;
+
+namespace creaImageIO
+{
+
+
+  /**
+   * \ingroup IO
+   */
+  
+  //=====================================================================
+  /// Concrete image reader for DICOM images 
+  class DicomImageScanner 
+  {
+  public:
+    DicomImageScanner();
+    virtual ~DicomImageScanner();
+
+       /// Add file extensions read by the reader
+    bool addDirectory(std::string& filename,   std::map<std::string,std::string>& attr);
+
+       /// return for a file a 2D VTkImage
+    virtual vtkImageData* ReadImage(const std::string& filename);
+       /// Read the attributes for a file
+    virtual void ReadAttributes(const std::string& filename, 
+                               tree::AttributeMapType& attr);
+       void ReadAttributes2(const std::string& filename, 
+                               tree::AttributeMapType& attr);
+
+        std::string irclean(const std::string& str);
+  private:
+         const std::string GetStringValueFromTag( const gdcm::DataElement& ds);
+         vtkGDCMImageReader *mReader;
+         gdcm::Scanner mscan;
+         bool b_loaded;
+
+  };
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIODicomScanner_h_INCLUDED__
diff --git a/src/creaImageIOExternalGimmick.cpp b/src/creaImageIOExternalGimmick.cpp
new file mode 100644 (file)
index 0000000..8201a81
--- /dev/null
@@ -0,0 +1,79 @@
+#include <creaImageIOExternalGimmick.h>
+
+
+vtkImageData* getImageDataDialog() {
+       //      wxApp::OnInit();
+       #ifdef __WXGTK__
+         //See http://www.wxwindows.org/faqgtk.htm#locale
+         setlocale(LC_NUMERIC, "C");
+       #endif
+          wxInitAllImageHandlers();
+
+          creaImageIO::SetGimmickMessageLevel(5);
+          creaImageIO::SetGimmickDebugMessageLevel(0);
+
+          int min_dim = GIMMICK_2D_IMAGE_SELECTION;
+          int max_dim = GIMMICK_3D_IMAGE_SELECTION;
+          int output_dim = NATIVE;
+          int threads = 1;         
+
+          creaImageIO::WxGimmickReaderDialog w(
+                                               0,
+                                          -1, 
+                                          "localdatabase_Descriptor.dscp",
+                                          "Local Database",
+                                          _T("Select image(s)        - Gimmick! (c) CREATIS-LRMN 2008"),
+                                          wxDefaultPosition,
+                                          wxSize(1200,800),
+                                          min_dim,
+                                          max_dim,
+                                          output_dim,
+                                          threads);
+          w.ShowModal();
+
+          if (w.GetReturnCode() == wxID_OK)
+                {
+                  std::cout << "$$$$ main : user clicked 'OK' $$$$"<<std::endl;
+                  std::cout << "$$$$ selected files : "<<std::endl;
+                  //Puts filenames
+                  std::vector<std::string> s;
+                  w.GetSelectedFiles(s);
+                  std::vector<std::string>::iterator i;
+                  for (i=s.begin();i!=s.end();++i) 
+                        {
+                          std::cout << *i << std::endl;
+                        }
+                  std::cout << "$$$$ "<<std::endl;
+
+                  //Puts images
+                  std::vector<vtkImageData*> images;
+                  w.GetSelectedImages(images,output_dim);
+                  std::cout<<images.size()<<std::endl;
+
+                  w.OnExit();
+                  return images[0];
+
+                  //crea::VtkBasicSlicer(images.front());
+                  //images.front()->Delete();
+                  
+
+                }
+          else if (w.GetReturnCode() == wxID_CANCEL)
+                {
+                  w.OnExit();
+                  std::cout << "$$$$ main : user clicked 'CANCEL' $$$$"<<std::endl;
+                }
+          else 
+                {
+                  w.OnExit();
+                  std::cout << "$$$$ main : dialog ended without return code ! $$$$"
+                                        <<std::endl;    
+                }
+
+          //   std::cout << "$$$$ main : deleting dialog"<<std::endl;
+          //   delete w;
+          std::cout << "$$$$$$$$$$$$$$$$$$$$ main ended "<<std::endl;
+          return NULL;
+       }
+       
+       
diff --git a/src/creaImageIOExternalGimmick.h b/src/creaImageIOExternalGimmick.h
new file mode 100644 (file)
index 0000000..10fe9b3
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __creaImageIOExternalGimmick_h_INCLUDED__
+#define __creaImageIOExternalGimmick_h_INCLUDED__
+
+#include "creaImageIOGimmickReaderDialog.h"
+#include <creaImageIOWxGimmickReaderDialog.h>
+
+ extern "C"                                                            
+ {                     
+       CREAIMAGEIO_EXPORT vtkImageData* getImageDataDialog();
+ }
+#endif
+
diff --git a/src/creaImageIOGimmick.cpp b/src/creaImageIOGimmick.cpp
new file mode 100644 (file)
index 0000000..5edb4ed
--- /dev/null
@@ -0,0 +1,491 @@
+
+#include <creaImageIOGimmick.h>
+
+#include <creaImageIOSystem.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+//#include "io.h"
+#ifndef PATH_MAX // If not defined yet : do it 
+#  define PATH_MAX 2048
+#endif
+#include <creaImageIOGimmick.h>
+#include <boost/algorithm/string.hpp>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+namespace creaImageIO
+{
+  //==============================================================
+  Gimmick::Gimmick()
+    : mImageAdder(0)
+  {    
+  RegisterGimmickMessageTypes();
+       mSettings=0;
+       mSynchronizer=0;
+       mLocalDescpName = "localdatabase_Descriptor.dscp";
+       mLocalDBName = "Local database";
+  }
+  //==============================================================
+
+
+  //==============================================================
+  Gimmick::~Gimmick()
+  {
+
+        if(mSettings!=0)
+         {
+               mSettings->writeSettingsFile();
+               delete mSettings;
+         }
+       if(mSynchronizer!=0)
+         {
+               delete mSynchronizer;
+         }
+  }
+  //==============================================================
+  
+  //==============================================================
+  void Gimmick::Initialize(const std::string i_namedescp, const std::string i_namedb)
+  {
+         mLocalDescpName = i_namedescp;
+         mLocalDBName = i_namedb;
+         Initialize();
+  }
+
+  //==============================================================
+  void Gimmick::Initialize()
+  {
+       std::string i_nameDB = mLocalDBName;
+    // Create the UserSettings dir if does not exist
+    CreateUserSettingsDirectory();
+    // Sets the current directory to the home dir
+    mCurrentDirectory =  GetHomeDirectory();
+    mSynchronizer= new Synchronizer(GetUserSettingsDirectory()+"Shared/gimmick/");
+
+    mSettings  = new Settings(mCurrentDirectory);
+       
+    std::string dbpath = GetLocalDatabasePath();
+
+    // Create or open local database
+    std::string dpath= mCurrentDirectory + "/.gimmick/Shared/gimmick/" + mLocalDescpName;
+       
+    boost::algorithm::replace_all( dpath,
+                                  INVALID_FILE_SEPARATOR , 
+                                  VALID_FILE_SEPARATOR);
+    mLocalDatabase = createDB(i_nameDB, dpath, dbpath);
+    // Add it to the TreeHandlerMap
+    mTreeHandlerMap[i_nameDB] = mLocalDatabase;
+    
+    //Add additional DB from user Settings
+    addDBSettings();   
+  }
+
+   ///////////////////////////////////////////////////////////////////////
+   // add DB to TreeHandler Map                                                //
+   // @param i_name : DB name                                          //
+   // @param i_location : DB location                                  //
+   // return : -                                                       //
+  ////////////////////////////////////////////////////////////////////////
+ void Gimmick::addDB(const std::string &i_name, 
+                    const std::string &i_location)
+       {
+               if(mTreeHandlerMap.find(i_name) == mTreeHandlerMap.end())
+               {
+                       mTreeHandlerMap[i_name] = new SQLiteTreeHandler(i_location);
+                       mTreeHandlerMap[i_name]->Open(true);
+                       mSettings->addDB(i_location);
+               }
+       }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // create a DB from a attributes descriptor file for medical images      //
+  // @param i_name : DB name                                                                                      //
+  // @param i_locDesc : location of descriptor file                                               //
+  // @param i_locDB : location of DB                                                                      //
+  // return : the SQLiteTreeHandler object on DB                                                  //
+       /////////////////////////////////////////////////////////////////////////
+       SQLiteTreeHandler* Gimmick::createDB(const std::string &i_name,
+                                            const std::string &i_locDesc,
+                                            const std::string &i_locDB)
+  {
+     SQLiteTreeHandler* sqlTreeH( new SQLiteTreeHandler(i_locDB) );
+    // Create or open local database
+    if (! boost::filesystem::exists(i_locDB) )
+     {
+         std::string mess = "Local database '";
+         mess += i_locDB;
+         mess += "' does not exist : creating it";
+         GimmickMessage(1,mess<<std::endl);
+         
+                // CREATING DB STRUCTURE
+         sqlTreeH->GetTree().GetDescriptor().createDescriptorfromFile(i_locDesc);
+         if ( ! sqlTreeH->Create(true) )
+        {
+               GimmickError("ERROR CREATING '"<<i_locDB<<"'");
+         }
+         sqlTreeH->SetAttribute(0,"Name",i_name);
+        }
+        else 
+        {
+               /// Open and test it
+               
+               GimmickDebugMessage(1,"Opening local database '" <<i_locDB<< "' " << std::endl);
+               if ( !sqlTreeH->Open(true) )
+               {
+                       GimmickError("ERROR OPENING '"<<i_locDB<<"'");
+               }
+       }
+       return sqlTreeH;
+  }
+
+  //==============================================================
+  void Gimmick::Finalize()
+  {
+         if(mTreeHandlerMap.size() >0)
+         {
+               // delete SQLiteTreeHandler Object
+               for( TreeHandlerMapType::const_iterator it = mTreeHandlerMap.begin();
+                                                                                                       it!= mTreeHandlerMap.end(); 
+                                                       ++it)
+               {
+                       delete it->second;
+               }
+         }
+  }
+  //==============================================================
+
+  //================================================================
+  // file separator
+#if defined(_WIN32)
+#define VALID_FILE_SEPARATOR "\\"
+#define INVALID_FILE_SEPARATOR "/"
+#else
+#define INVALID_FILE_SEPARATOR "\\"
+#define VALID_FILE_SEPARATOR "/"
+#endif
+  //================================================================
+
+  //================================================================
+  const std::string& Gimmick::GetHomeDirectory()
+  {
+    if (mHomeDirectory.size()==0) 
+      {
+#if defined(__GNUC__)
+       mHomeDirectory = getenv("HOME");
+#elif defined(_WIN32)
+       mHomeDirectory = getenv("USERPROFILE");
+#endif
+      }
+    return mHomeDirectory;
+  }
+  //================================================================
+  const std::string& Gimmick::GetUserSettingsDirectory()
+  {
+    if (mUserSettingsDirectory.size()==0) 
+      {
+       mUserSettingsDirectory = GetHomeDirectory();
+       mUserSettingsDirectory += "/.gimmick/";
+       boost::algorithm::replace_all( mUserSettingsDirectory, 
+                                      INVALID_FILE_SEPARATOR , 
+                                      VALID_FILE_SEPARATOR);
+      }
+    return mUserSettingsDirectory;
+  }
+  //================================================================
+
+
+  //================================================================
+  const std::string& Gimmick::GetLocalDatabasePath()
+  {
+    if (mLocalDatabasePath.size()==0) 
+      {
+       mLocalDatabasePath = GetUserSettingsDirectory();
+       mLocalDatabasePath += "Shared/gimmick/";
+       mLocalDatabasePath += mLocalDBName;
+       mLocalDatabasePath +=".sqlite3";
+       boost::algorithm::replace_all( mLocalDatabasePath,
+                                      INVALID_FILE_SEPARATOR , 
+                                      VALID_FILE_SEPARATOR);
+      }
+    return mLocalDatabasePath;    
+  }
+
+  //========================================================================
+
+  //========================================================================
+  void Gimmick::CreateUserSettingsDirectory()
+  {
+         
+        // std::string st("C:/Documents and Settings/cervenansky/.gimmick/");
+        //     boost::algorithm::replace_all( st, 
+               //                     INVALID_FILE_SEPARATOR , 
+               //                     VALID_FILE_SEPARATOR);
+               //const boost::filesystem::path mpath(st);
+//C:\Documents and Settings\cervenansky\.gimmick");
+         //if ( !boost::filesystem::exists( path ) )             return ;
+        //  boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
+        //  for ( boost::filesystem::directory_iterator itr( path );  itr != end_itr;  ++itr )
+        // {
+               //// If is directory & recurse : do recurse
+               //      if ( boost::filesystem::is_directory(itr->status()) )
+               //      return;
+        //  }
+
+         //JCP settings dir 02/10/2009
+         const std::string settingsdirectory = GetUserSettingsDirectory();
+               //boost::algorithm::replace_all( mUserSettingsDirectory, 
+                               //       INVALID_FILE_SEPARATOR , 
+                               //       VALID_FILE_SEPARATOR);
+;//("E:\frederic");
+                 //("C:\\Documents and Settings\\cervenansky\\.gimmick\\"); // settingsdirectory );
+               bool isdir = false;
+          isdir = boost::filesystem::is_directory(settingsdirectory); // settingsdirectory );
+    if (! isdir )
+      {
+       GimmickMessage(1,"Directory '"<<GetUserSettingsDirectory()<<"' "
+                      << "does not exist : creating it"<<std::endl);
+       
+       if ( ! boost::filesystem::create_directory( GetUserSettingsDirectory() ) )
+         {
+           GimmickError("ERROR CREATING '"<<GetUserSettingsDirectory()<<"'");
+         }
+      }
+
+       std::string setDir=GetUserSettingsDirectory();
+       boost::algorithm::replace_all( setDir,
+                                      INVALID_FILE_SEPARATOR , 
+                                      VALID_FILE_SEPARATOR);
+       setDir+="Shared/";
+       boost::filesystem::create_directory( setDir );
+       setDir+="gimmick/";
+       boost::filesystem::create_directory( setDir );
+       setDir+=mLocalDescpName;
+
+       if(!boost::filesystem::is_regular(setDir))
+       {
+               char name[PATH_MAX];
+               crea::System::GetAppPath(name,PATH_MAX);
+               std::cout<<name<<std::endl;
+               
+               std::string path=name;
+               path=path.substr(0,path.size()-1);
+               path=path.substr(0,path.find_last_of("/"));
+               //Creating directories
+
+// The following stuff works on Linux, NOT CHECKED on Windows // JPR
+               
+#if defined(_WIN32)            
+               path+="/bin/Shared/gimmick/";
+#endif
+
+#if defined (LINUX)
+               path+="/../share/gimmick/";
+#endif 
+#if defined(__APPLE__)
+               path+="/../../../../share/gimmick/";
+#endif 
+
+
+path+= mLocalDescpName;
+               
+               std::cout <<"From: " << path   <<std::endl;
+               std::cout <<"To: "   << setDir <<std::endl;
+               boost::algorithm::replace_all(  path,
+                                               INVALID_FILE_SEPARATOR , 
+                                               VALID_FILE_SEPARATOR);
+               boost::filesystem::copy_file(path,setDir);
+       }
+         
+  }
+  //========================================================================
+
+
+  //========================================================================
+  /// Sets message level
+  void Gimmick::SetMessageLevel(int l)
+  {
+    SetGimmickMessageLevel(l);
+  }
+  //========================================================================
+
+  //========================================================================
+  /// Sets message level
+  void Gimmick::SetDebugMessageLevel(int l)
+  {
+    SetGimmickDebugMessageLevel(l);
+  }
+  //========================================================================
+
+  //========================================================================
+  /// Returns the tree handler with the given name
+  TreeHandler* Gimmick::GetTreeHandler(const std::string& name) const 
+  {  
+    TreeHandlerMapType::const_iterator i;
+    i = GetTreeHandlerMap().find(name);
+    if ( i == GetTreeHandlerMap().end() )
+      {
+       GimmickError("TreeHandler '"<<name<<"' does not exist");
+      }
+    return i->second;
+  }
+
+  //========================================================================
+  /// Add the files to the tree handler
+  void Gimmick::AddFiles(const std::string& d, 
+                       const std::vector<std::string>& filenames)
+  {
+    GimmickMessage(2,"Adding files to '"<<d<<"'"<<std::endl);
+       mImageAdder.SetCurrentDatabase(d);
+       mImageAdder.SetTreeHandler(GetTreeHandler(d));
+       mImageAdder.SetSynchronizer(mSynchronizer);
+       mImageAdder.AddFiles(filenames);        
+  }
+  //========================================================================
+
+  //========================================================================
+  /// Add a dir to the local database
+  void Gimmick::AddDir(const std::string& d, const std::string& f, 
+                      bool recurse)
+  {
+       GimmickMessage(2,"Adding dir '"<<f<<"' to '"<<d<<"' recurse:"
+                        <<recurse<<std::endl);
+
+       TreeHandler * handler=GetTreeHandler(d);
+       mImageAdder.SetCurrentDatabase(d);
+       mImageAdder.SetTreeHandler(handler);
+       mImageAdder.SetSynchronizer(mSynchronizer);
+       mImageAdder.AddDirectory(f,recurse);  
+  }
+
+  //========================================================================
+
+  //========================================================================
+  void Gimmick::RemoveFile(const std::string& d, 
+                          tree::Node* node)
+  {
+         mImageAdder.SetCurrentDatabase(d);
+         mImageAdder.SetSynchronizer(mSynchronizer);
+         mImageAdder.RemoveFile(node);
+  }
+  //========================================================================
+
+  //void Gimmick::Anonymize(std::vector<std::string>i_files)  {  }
+  //========================================================================
+  void Gimmick::CopyFiles(const std::vector<std::string>& filenames, const std::string& d )
+  {
+         TreeHandler * handler=GetTreeHandler(d);
+         mImageAdder.SetCurrentDatabase(d);
+         mImageAdder.SetTreeHandler(handler);
+         mImageAdder.SetSynchronizer(mSynchronizer);
+         mImageAdder.CopyFiles(filenames, mSettings->getValue(SETTINGS_COPY_PATH));
+  }
+
+  //========================================================================
+  std::string Gimmick::Synchronize(const std::string& d, bool repair, bool checkAttributes)
+  {
+         TreeHandler * handler=GetTreeHandler(d);
+         mImageAdder.SetCurrentDatabase(d);
+         mImageAdder.SetTreeHandler(handler);
+         mImageAdder.SetSynchronizer(mSynchronizer);
+         return mImageAdder.Synchronize(repair, checkAttributes);
+  }
+
+  //========================================================================
+  /// 
+  void Gimmick::Print(const std::string& d)
+  {
+    GetTreeHandler(d)->GetTree().Print();
+  }
+  //========================================================================
+
+  void Gimmick::GetSetting(const std::string& name, std::string& value)
+  {
+    value = mSettings->getValue(name);
+  }
+  //========================================================================
+
+  //========================================================================
+
+  void Gimmick::GetAttributes(const std::string& d, 
+                       const std::string& filename, 
+                       const std::vector<std::string>& params, 
+                       std::vector<std::string>& results)
+  {
+         TreeHandler * handler=GetTreeHandler(d);
+         mImageAdder.SetCurrentDatabase(d);
+         mImageAdder.SetTreeHandler(handler);
+         mImageAdder.SetSynchronizer(mSynchronizer);
+         mImageAdder.GetAttributes(params, filename, results);
+  }
+  //========================================================================
+
+  //========================================================================
+
+  void Gimmick::UpdateSetting(const std::string& name, const std::string& value)
+  {
+         mSettings->updateSetting(name,value);
+         mSettings->writeSettingsFile();
+  }
+  //========================================================================
+
+  void Gimmick::DeleteDrive(const std::string& drive)
+  {
+       for( TreeHandlerMapType::const_iterator it = mTreeHandlerMap.begin();
+                                              it!= mTreeHandlerMap.end(); 
+                                              ++it)
+          {
+                  mImageAdder.SetTreeHandler(it->second);
+                  mImageAdder.DeleteDriveFromMainDB(drive);
+          }
+       mImageAdder.SetSynchronizer(mSynchronizer);
+       mImageAdder.DeleteDriveFromOtherDB(drive);
+  }
+
+  //========================================================================
+  void Gimmick::EditField(tree::Node* node, const std::string& d, const std::string& name, const std::string& key, const std::string& val)
+  {
+       TreeHandler * handler=GetTreeHandler(d);
+       mImageAdder.SetCurrentDatabase(d);
+       mImageAdder.SetTreeHandler(handler);
+       mImageAdder.EditField(node,name,key,val);
+  }
+  //========================================================================
+
+  ////////////////////////////////////////////////////////////////////////
+  // add DB from Settings file                                         //
+  // @param : -                                                                //
+  // return : -                                                                //
+  ////////////////////////////////////////////////////////////////////////
+  void Gimmick::addDBSettings()
+  {
+
+        std::string pathSettings = mSettings->getValue(SETTINGS_DBPATH);
+        
+        // split to find all paths
+        std::vector<std::string> paths;
+        std::string separator = ";";
+        std::string::size_type last_pos = pathSettings.find_first_not_of(separator);
+        //find first separator
+        std::string::size_type pos = pathSettings.find_first_of(separator, last_pos);
+        while(std::string::npos != pos || std::string::npos != last_pos)
+        {
+               paths.push_back(pathSettings.substr(last_pos, pos - last_pos));
+               last_pos = pathSettings.find_first_not_of(separator, pos);
+               pos = pathSettings.find_first_of(separator, last_pos);
+        }
+
+        std::vector<std::string>::iterator it_path = paths.begin();
+        for(; it_path != paths.end(); ++it_path)
+        {
+                pos = it_path->find_last_of("\\");
+                last_pos = it_path->find_last_of(".");
+                std::string name = it_path->substr(pos +1, last_pos -pos-1 );
+                addDB(name, it_path->c_str());
+        }
+  }    
+}
diff --git a/src/creaImageIOGimmick.h b/src/creaImageIOGimmick.h
new file mode 100644 (file)
index 0000000..017d153
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef __creaImageIOGimmick_h_INCLUDED__
+#define __creaImageIOGimmick_h_INCLUDED__
+
+#include <creaImageIOSQLiteTreeHandler.h>
+#include <creaImageIOTreeHandlerImageAdder.h>
+#include <creaImageIOSynchron.h>
+#include <creaImageIOSettings.h>
+
+
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#define DEBUG_NEW new(_NORMAL_BLOCK ,__FILE__, __LINE__)
+#else
+#define DEBUG_NEW new
+#endif
+// Only when asked
+/*
+#ifdef TRACKING_MEMORY_LEAKS
+#ifdef WIN32
+#pragma warning(disable : 4291)
+#endif
+
+void * operator new( size_t size, int line, const char *file );
+void * operator new[]( size_t size, int line, const char *file );
+void operator delete( void *p );
+void operator delete[]( void *p );
+
+#ifdef OMISCID_NEW
+#undef OMISCID_NEW
+#endif
+
+#define OMISCID_NEW new( __LINE__, __FILE__ )
+
+#else // TRACKING_MEMORY_LEAKS is not defined
+
+#define OMISCID_NEW new
+
+#endif*/
+
+
+namespace creaImageIO
+{
+       /**
+       * \defgroup Controller Controller
+       */
+       /**
+       * \defgroup View View
+       */
+       /**
+       * \defgroup Model Model
+       */
+       /**
+       * \defgroup GUI Top level graphical user interfaces
+       */
+       /**
+       * \defgroup IO Image I/O classes
+       */
+       /**
+       * \defgroup Tree Attributed tree management
+       */
+       /**
+       * \defgroup Previewer Preview related
+       */
+
+       /**
+       * \ingroup Controller
+       */
+
+  //=======================================================================
+  /// Central controler of the gimmick application
+  class CREAIMAGEIO_EXPORT Gimmick
+  {
+  public:
+    /// Ctor
+    Gimmick();
+    /// Dtor
+    ~Gimmick();
+    
+    ///
+    typedef TreeHandlerImageAdder::Progress AddProgress;
+    typedef TreeHandlerImageAdder::ProgressCallbackType AddProgressCallbackType;
+    
+    /// Adds the function f to the list of functions to call 
+    /// when addition operations progres.
+    /// f is of type AddProgressCallbackType which is:
+    /// void (*AddProgressCallbackType)(AddProgress&)
+    /// To pass a member function 'f' of an instance 'c' of a class 'C' 
+    /// as callback you have to 'bind' it, i.e. call:
+    /// ConnectAddProgressObserver ( boost::bind( &C::f , c, _1 ) );
+     void ConnectAddProgressObserver( AddProgressCallbackType callback )
+    { mImageAdder.ConnectProgressObserver(callback); }
+    
+    ///
+    const AddProgress& GetAddProgress() const { return mImageAdder.GetProgress(); }
+
+    /// Initializes with default values (read/creates databases, etc.)
+    void Initialize();
+
+       /// Initializes with the local database descriptor in the path given (read/creates databases, etc.)
+       void Initialize(const std::string namedescp, const std::string namedb = "Local Database");
+    
+    /// Finalize (closes databases, etc.)
+    void Finalize();
+
+    /// Sets level for messages "Gimmick!" 
+    static void SetMessageLevel(int level);
+    /// Sets level for debug messages "Gimmick! DEBUG" 
+    static void SetDebugMessageLevel(int level);
+    
+    /// Type of map from TreeHandler name to TreeHandler*
+       typedef std::map<std::string, TreeHandler*> TreeHandlerMapType;
+
+       typedef std::map<std::string, TreeHandler*>::const_iterator ItTreeHandlerMap;
+
+    /// Returns the TreeHandlerMap (ref)
+    TreeHandlerMapType& GetTreeHandlerMap() { return mTreeHandlerMap; }
+       
+    /// Returns the TreeHandlerMap (const ref)
+    const TreeHandlerMapType& GetTreeHandlerMap() const
+    { return mTreeHandlerMap; }    
+
+    /// Add the files to the given TreeHandler
+    void AddFiles(const std::string& handler,
+                 const std::vector<std::string>& filenames);
+
+    /// Add a dir to the given TreeHandler
+    void AddDir(const std::string& handler, const std::string& path, 
+               bool recurse);
+
+       /// Removes a file from the given TreeHandler
+       void RemoveFile(const std::string& d, 
+                       tree::Node* filename);
+
+       ///Deletes the given drive name from the databases
+       void DeleteDrive(const std::string& drive);
+  
+
+       /// Copies the files into the local directory
+       void CopyFiles(const std::vector<std::string>& filenames, const std::string& d );
+  
+
+       ///Synchronizes the loaded data with the database d. If repair is true the database will be updated, otherwise 
+       ///only a warning sign will be issued
+       std::string Synchronize(const std::string& d, bool repair, bool checkAttributes);
+
+    /// Prints the tree handled by the handler
+    void Print(const std::string& handler);
+       
+    ///create a DB from a given descriptor file and for a specific location
+       SQLiteTreeHandler* createDB(const std::string &i_name, 
+                               const std::string &i_locDesc, 
+                               const std::string &i_locDB);
+
+       /// add an existent DB 
+       void addDB(const std::string &i_nameDB, const std::string &i_locationDB);
+
+    /// Returns the TreeHandler with a given name
+    TreeHandler* GetTreeHandler(const std::string& name) const;
+
+       /// 
+       SQLiteTreeHandler* GetLocalDatabase() { return mLocalDatabase; }
+
+    const SQLiteTreeHandler* GetLocalDatabase() const     { return mLocalDatabase; }
+
+       ///Returns the given setting value for the given setting parameter
+       void GetSetting(const std::string& name, std::string& value);
+
+       ///Updates the settings file
+       void UpdateSetting(const std::string& name, const std::string& value);
+
+       /// add DB from Settings file
+    void addDBSettings();
+
+       ///Edits the field described by the name and key provided with the value given
+       void EditField(tree::Node* node, const std::string& d, const std::string& name, const std::string& key, const std::string& val);
+
+       /// Returns the attributes in results described in params
+       void GetAttributes(const std::string& d, 
+         const std::string& filename, 
+         const std::vector<std::string>& params, 
+         std::vector<std::string>& results);
+  
+    /// 
+    const std::string& GetHomeDirectory();
+    const std::string& GetUserSettingsDirectory();
+    void CreateUserSettingsDirectory();
+    const std::string& GetLocalDatabasePath();
+       
+
+
+    //=============================================
+  private:
+       SQLiteTreeHandler* mLocalDatabase;
+       TreeHandlerMapType mTreeHandlerMap;
+       Synchronizer* mSynchronizer;
+
+    std::string mCurrentDirectory;
+    std::string mHomeDirectory;
+    std::string mUserSettingsDirectory;
+    std::string mLocalDatabasePath;
+       Settings        *mSettings;
+    TreeHandlerImageAdder mImageAdder;
+       std::string mLocalDBName;
+       std::string mLocalDescpName;
+  };
+  // EO class Gimmick
+  //=======================================================================
+
+
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
+
+
diff --git a/src/creaImageIOGimmickReaderDialog.cpp b/src/creaImageIOGimmickReaderDialog.cpp
new file mode 100644 (file)
index 0000000..29c6bbf
--- /dev/null
@@ -0,0 +1,53 @@
+#include <creaImageIOGimmickReaderDialog.h>
+#include <creaImageIOWxGimmickReaderDialog.h>
+
+namespace creaImageIO
+{
+
+  bool GimmickReaderDialog(std::vector<vtkImageData*>& images,
+                          const std::string i_namedescp , 
+                          const std::string i_namedb ,
+                          const std::string& title,
+                          int posx, 
+                          int posy,
+                          int sizex,
+                          int sizey,
+                          int image_min_type,
+                          int image_max_type,
+                          int image_out_dim,
+                          int nb_threads)
+  {
+
+    
+    creaImageIO::WxGimmickReaderDialog w(0,
+                                        -1,
+                                        i_namedescp,
+                                        i_namedb,
+                                        crea::std2wx(title),
+                                        wxPoint(posx,posy),
+                                        wxSize(sizex,sizey),
+                                        image_min_type,
+                                        image_max_type,
+                                        nb_threads);
+    w.ShowModal();
+    
+    if (w.GetReturnCode() == wxID_OK)
+      {
+       w.GetSelectedImages(images,image_out_dim);
+       return true;
+      }
+    else if (w.GetReturnCode() == wxID_CANCEL)
+      {
+       return false;
+      }
+    else 
+      {
+       std::cout << "!! ERROR : GimmickReaderDialog : dialog ended without return code !"
+                 <<std::endl;
+       return false;
+      }
+  
+  
+  }
+
+}
diff --git a/src/creaImageIOGimmickReaderDialog.h b/src/creaImageIOGimmickReaderDialog.h
new file mode 100644 (file)
index 0000000..df640ff
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __creaImageIOGimmickReaderDialog_h_INCLUDED__
+#define __creaImageIOGimmickReaderDialog_h_INCLUDED__
+
+#include "creaImageIOSystem.h"
+#include <vtkImageData.h>
+#include <vector>
+
+ extern "C"                                                            
+ {                     
+       CREAIMAGEIO_EXPORT vtkImageData* getImageDataDialog();
+ }
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   * \brief Pops up a WxGimmickReaderDialog 
+   * returns true if the user clicked 'Ok', false if 'Cancel'
+   *  and fills the vector of images
+   */
+  bool CREAIMAGEIO_EXPORT GimmickReaderDialog
+  (std::vector<vtkImageData*>& images,
+   const std::string i_namedescp , 
+   const std::string i_namedb = "Local Database",
+   const std::string& title = "Select images",
+   int posx = 0, int posy = 0,
+   int sizex = 1200, int sizey = 800,
+   int image_min_type = 2,
+   int image_max_type = 3,
+   int image_out_dim = 2,
+   int nb_threads = 1);
+  
+}
+
+#endif
diff --git a/src/creaImageIOGimmickView.cpp b/src/creaImageIOGimmickView.cpp
new file mode 100644 (file)
index 0000000..3132aa6
--- /dev/null
@@ -0,0 +1,643 @@
+#include <creaImageIOGimmickView.h>
+#include <creaImageIOSystem.h>
+#include "boost/filesystem.hpp"
+
+#if defined(USE_GDCM)
+#include <gdcmGlobal.h>
+#include <gdcmSerieHelper.h>
+#include <vtkGdcmReader.h>
+#endif
+
+#if defined(USE_GDCM2)
+#include <vtkGDCMImageReader.h>
+#endif
+
+
+namespace fs = boost::filesystem;
+namespace creaImageIO
+{
+
+       ///Class used to represent the actual state of the image selected and to perform comparisons on its values
+  class ImageExtent
+  {
+  public:
+    ImageExtent(const std::string& x, const std::string& y, const std::string& z, const std::string& t)
+       {
+                sscanf(x.c_str(),"%d",&mExtent[0]);
+                sscanf(y.c_str(),"%d",&mExtent[1]);
+                sscanf(z.c_str(),"%d",&mExtent[2]);
+                sscanf(t.c_str(),"%d",&mExtent[3]);
+                if(x==""){mExtent[0]=1;}
+            if(y==""){mExtent[1]=1;}
+            if(z==""){mExtent[2]=1;}
+                if(t==""){mExtent[3]=1;}
+
+                if (mExtent[3]>1) mDim=4;
+                else if (mExtent[2]>1) mDim=3;
+            else if (mExtent[1]>1) mDim=2;
+            else if (mExtent[0]>1) mDim=1;
+                else mDim=0;
+       }
+       
+
+       ///Clears the extent
+    void Clear() { mExtent[0] = mExtent[1] = mExtent[2] = mExtent[3] = 1; }
+
+       ///Returns true if the two extents are compatible
+    bool IsCompatible( const ImageExtent& );
+
+       ///Adds the extent passed as a parameter to the current extent
+    void Add ( const ImageExtent& );
+               
+       ///Returns the ieth position of the extent
+    int Get(int i) { return mExtent[i]; }
+    
+       ///Returns the dimension of the current image
+    void SetDimension(int dim) { mDim=dim; }
+
+       ///Returns the dimension of the current image
+    int GetDimension() { return mDim; }
+
+  private:
+    int mExtent[4];
+    int mDim;
+  };
+
+  //======================================================================
+
+  //======================================================================
+  // CTor
+  GimmickView::GimmickView(boost::shared_ptr<Gimmick> gimmick, int threads)
+    : mGimmick(gimmick),
+         mReader(threads)
+  {
+    GimmickDebugMessage(1,"GimmickView::GimmickView"
+                       <<std::endl);
+       // Anciently started the threads ...
+    // Threads now automatically start at first image request
+    //mReader.Start();
+
+  }
+  //======================================================================
+
+  //======================================================================
+  /// Destructor
+  GimmickView::~GimmickView()
+  {
+    GimmickDebugMessage(1,"GimmickView::~GimmickView"
+                       <<std::endl);
+  }
+   //======================================================================
+  //======================================================================  
+  /// Initializes the view : 
+  /// Creates the TreeViews for all the TreeHandler of the Controller
+  /// 
+  void GimmickView::Initialize()
+  {
+       mReaderStarted=false;
+  }
+  //======================================================================
+
+  //======================================================================
+  /// Finalize 
+  void GimmickView::Finalize()
+  {
+  }
+
+  //======================================================================
+
+  //======================================================================
+  /// Create the tree views 
+  void GimmickView::CreateTreeViews()
+  {
+    GimmickMessage(2,"Creating the tree views"<<std::endl);
+    Gimmick::TreeHandlerMapType::const_iterator i;
+    for (i = mGimmick->GetTreeHandlerMap().begin();
+        i!= mGimmick->GetTreeHandlerMap().end();
+        ++i)
+      {
+       this->CreateTreeView(i->second);
+      }
+  }
+
+  /// Create a tree view with a given name
+  void GimmickView::CreateSingleTreeView(std::string &i_name)
+  {
+       this->CreateTreeView(mGimmick->GetTreeHandlerMap()[i_name]);
+     
+  }
+
+
+  //======================================================================
+
+  //======================================================================
+  /// Updates the TreeView of given name from level l to bottom
+  /// (calls the virtual method TreeView::Update())
+  void GimmickView::UpdateTreeViewLevel(const std::string& t, int l)
+  {
+    TreeViewMapType::iterator i;
+    i = GetTreeViewMap().find(t);
+    if ( i == GetTreeViewMap().end() )
+      {
+       GimmickError("INTERNAL ERROR : GimmickView::UpdateTreeView : '"
+                    <<t<<"' is not in TreeViewMap");
+      }
+    i->second->UpdateLevel(l);
+  }
+
+  //======================================================================
+  /// Clears the status and begins a new selection process
+  void GimmickView::ResetExtent()
+  {
+         if(mImageExtent!=0)
+         {
+                 mImageExtent.reset();
+         }
+         valid=true;
+  }
+
+  //======================================================================
+
+  //======================================================================
+  bool ImageExtent::IsCompatible(const ImageExtent& ie)
+  {
+         bool compatible=true;
+         ImageExtent * extent= (ImageExtent*)&ie;
+         if((*extent).Get(0)!=Get(0)
+                || (*extent).Get(1)!=Get(1))
+         {
+                 compatible=false;
+         }
+         return compatible;
+  }
+
+  //======================================================================
+
+  //======================================================================
+  void ImageExtent::Add(const ImageExtent& ie)
+  {
+         ImageExtent * extent= (ImageExtent*)&ie;
+         mExtent[2]+=(*extent).Get(2);
+         if(mExtent[2]>1)
+         {
+         SetDimension(3);
+         }
+  }
+
+  //======================================================================
+  /// No selected image
+  bool GimmickView::NoValidateSelected ()
+  {
+       GimmickDebugMessage(2,"Validating selected"<<std::endl);
+       std::string mMessage;
+       mMessage="Cannot have 0 images selected!";
+       valid=false;
+       modifyValidationSignal(valid);
+       SetMessage(mMessage);
+       return valid;
+  }
+
+  //======================================================================
+  ///Validates the dimension compliance of the images with the maximum and 
+  ///minimum given, and between their sizes
+  bool GimmickView::ValidateSelected (tree::Node* sel, int min_dim, int max_dim)
+  {
+       GimmickDebugMessage(2,"Validating selected"<<std::endl);
+       std::string mMessage;
+       
+       if(sel==0)
+       {
+               mMessage="Cannot have 0 images selected!";
+               valid=false;
+       }
+       else
+       {
+               boost::shared_ptr<ImageExtent> ie=boost::shared_ptr<ImageExtent>(new ImageExtent((*sel).GetAttribute("D0028_0010"),
+                                                                       (*sel).GetAttribute("D0028_0011"),
+                                                                       (*sel).GetAttribute("D0028_0012"), 
+                                                                       ""));
+       if(mImageExtent==0)
+       {
+               mImageExtent=ie;
+               if((mImageExtent->Get(min_dim-1)<2)||(mImageExtent->Get(max_dim)>1))
+               {
+                       valid=false;
+               }
+               else
+               {
+                       std::stringstream out;
+                       out << mImageExtent->GetDimension() << "D image " << mImageExtent->Get(0) << "x"<< mImageExtent->Get(1) << "x"<< mImageExtent->Get(2) <<" selected";
+                       mMessage = out.str();
+                       mImageExtent->SetDimension(2);
+                       valid=true;
+               }
+       }
+       else
+       {
+               if(mImageExtent->IsCompatible(*ie))
+               {
+                       if(mImageExtent->GetDimension()==max_dim && mImageExtent->Get(max_dim)>2)
+                       {
+                               std::stringstream out;
+                               out<<"Cannot add this image to selection : would result in a "<<mImageExtent->GetDimension()+1<<"D image!";
+                               mMessage=out.str();
+                               valid=false;
+                       }
+                       else if(max_dim<3)
+                       {
+                               std::stringstream out;
+                               out<<"Selecting "<<mImageExtent->GetDimension()<<"D images is not allowed !";
+                               mMessage=out.str();
+                               valid=false;
+                       }
+                       else if(min_dim==3 && (ie->Get(2)+mImageExtent->Get(2))<2)
+                       {
+                               std::stringstream out;
+                               out << "Cannot build the selection as it would result in a ";
+                               out << mImageExtent->GetDimension();
+                               out << "D image, and the minimum is ";
+                               out << min_dim;
+                               out << "D!";
+                               mMessage=out.str();
+                               valid=false;
+                       }
+                       else
+                       {
+                               mImageExtent->Add(*ie);
+                               std::stringstream out;
+                               out << mImageExtent->GetDimension() << "D image " << mImageExtent->Get(0) << "x"<< mImageExtent->Get(1) << "x"<< mImageExtent->Get(2) <<" selected";
+                               mMessage = out.str();
+                       }
+               }
+               else
+               {
+                       mMessage="The selected images are not compatible.";
+                       valid=false;
+               }
+         }
+       }
+
+       modifyValidationSignal(valid);
+       SetMessage(mMessage);
+       return valid;
+  }
+
+  //======================================================================
+  void GimmickView::modifyValidationSignal(bool ivalid)
+  {
+         mValidationSignal(ivalid);
+  }
+
+   //======================================================================
+  ///Reads Images (Non Threaded)
+void GimmickView::ReadImagesNotThreaded(std::vector<vtkImageData*>& s, std::vector<std::string> im, int dimension)
+{
+       mReader.Stop();
+/* remember!
+
+#define GIMMICK_NO_IMAGE_SELECTION 0
+#define GIMMICK_2D_IMAGE_SELECTION 2
+#define GIMMICK_3D_IMAGE_SELECTION 3
+#define GIMMICK_4D_IMAGE_SELECTION 4
+
+#define NATIVE 0
+#define _2D    2
+#define _3D    3
+
+*/
+       // Create the output data
+       if (im.size()==1) 
+       {
+               vtkImageData * out=vtkImageData::New();
+               out->ShallowCopy(mReader.GetImage(im.front()));
+               s.push_back(out);
+       }
+    else if (im.size()>1) // Test inutile ? JPR
+       {
+               vtkImageData* first = mReader.GetImage( im.front());
+               if (dimension == 2)
+               {
+                // n3D
+                   std::vector<std::string>::iterator it;
+                       for (it=im.begin(); it!=im.end(); ++it) 
+                       {
+                               vtkImageData* out = vtkImageData::New();
+                               out->ShallowCopy(mReader.GetImage(*it));
+                               s.push_back(out);
+                       }
+               }         
+               else 
+               {
+                       // n*2D to 3D
+                       vtkImageData* out = vtkImageData::New();
+//                     out->CopyStructure(first);      
+                       out->SetScalarType(first->GetScalarType());
+                       out->SetNumberOfScalarComponents(first->GetNumberOfScalarComponents());
+                       int ext[6];
+                       //first->GetExtent(ext);  // JPR
+                       first->GetWholeExtent(ext);  // renvoie egalement 0,0 en Z // JPR
+
+                       if(ext[5] == 0)
+                       {
+                               ext[5] = im.size()-1;
+                       }
+                       else
+                       {
+                               ext[5] = ext[5] * im.size()-1; // to deal with multiframes - JPR
+                       }
+                       out->SetExtent(ext);
+
+                       // LG : TODO : Z Spacing  ?
+
+                       int dim[3];
+                       first->GetDimensions(dim);
+
+                       out->SetDimensions(dim[0], dim[1], im.size() );
+                       out->AllocateScalars();
+                       out->Update();
+
+                       unsigned long imsize = dim[0] * dim[1];
+                       imsize = imsize * dim[2] ;  // deal with multiframes // JPR
+
+
+//EED 03-11-2009
+                       // differents formats char , short, etc...
+                       // differents components 1..3  ex. jpg ->RGB 3
+                       imsize = imsize * first->GetScalarSize() * first->GetNumberOfScalarComponents();
+
+
+                       // Order the file name vector
+
+                       double spc[3];
+                       first->GetSpacing(spc);
+                       spc[2]=OrderTheFileNameVector(im);      
+
+                       out->SetSpacing(spc);
+
+                       int slice = 0;
+                       std::vector<std::string>::iterator it;
+
+                       for (it=im.begin(); it!=im.end(); ++it) 
+                       {
+                               vtkImageData* cur = mReader.GetImage( (*it) );
+                               memcpy(out->GetScalarPointer(0,0,slice), cur->GetScalarPointer(0,0,0), imsize);
+                               slice++;
+                       }       
+                       s.push_back(out);
+
+               }  // dimension == 3
+
+       }  // size >1
+
+}
+  //======================================================================
+
+#if defined(USE_GDCM)
+       double GimmickView::OrderTheFileNameVector(std::vector<std::string> &im)
+{
+       double spacing=1;
+       typedef std::vector<GDCM_NAME_SPACE::File* > FileList;
+       FileList fileVector;
+       //GDCM_NAME_SPACE::File *f = GDCM_NAME_SPACE::File::New();
+       GDCM_NAME_SPACE::SerieHelper *sh = GDCM_NAME_SPACE::SerieHelper::New();
+       std::vector<std::string> lstAux;
+       std::vector<std::string>::iterator it;
+       for (it=im.begin(); it!=im.end(); ++it)
+       {
+               ///\TODO liberer les GDCM_NAME_SPACE::File a la fin!  // JPR
+               GDCM_NAME_SPACE::File *f = GDCM_NAME_SPACE::File::New();
+               f->SetFileName(*it);
+               f->Load();
+               if (f->IsReadable())
+               {
+                       fileVector.push_back(f);
+               } else {
+                       lstAux.push_back(*it);
+               }
+       } // for
+                       
+       
+       if ((fileVector.size()>1) && (sh->IsCoherent( &fileVector )))
+       {
+                       sh->OrderFileList(&fileVector);
+                       spacing= sh->GetZSpacing();
+                       im.clear();
+                       int i;
+                       for (i=0; i<fileVector.size(); i++)
+                       {
+                               im.push_back( (fileVector[i])->GetFileName() );
+                       }
+                       for (i=0; i<lstAux.size(); i++)
+                       {
+                               im.push_back( lstAux[i] );
+                       }
+       }else {
+               std::sort( im.begin(), im.end() );
+       }
+                       
+   return spacing;
+}
+
+
+#endif
+
+#if defined(USE_GDCM2)
+       // TO DO
+       double GimmickView::OrderTheFileNameVector(std::vector<std::string> &im)
+       {
+               return 1;
+       }
+#endif
+//======================================================================
+
+
+void GimmickView::ReadImagesNotThreadedInVector(std::vector<vtkImageData*>& s, std::vector<std::string> im, int dimension)
+{
+       // Create the output data
+       if (im.size()==1)
+       {
+               // Only one image : give it
+               vtkImageData* out = vtkImageData::New();
+               GimmickDebugMessage(3, "State Check: Full Filename: "
+                                               <<im.front()
+                                               <<std::endl);
+               out->ShallowCopy(mReader.GetImage(im.front()));
+               s.push_back( out );
+       }
+       else if (im.size()>1) // Test inutile ? JPR
+       {
+               vtkImageData* first = mReader.GetImage( im.front());
+               if (dimension == 2)
+               {
+                // n3D
+                 std::vector<std::string>::iterator it;
+                       for (it=im.begin(); it!=im.end(); ++it)
+                       {
+                               vtkImageData* out = vtkImageData::New();
+                               out->ShallowCopy(mReader.GetImage(*it));
+                               s.push_back(out);
+                       }
+               }
+               else
+               {
+                       // n2D to 3D // NO!
+                       // n *2D + T in a vector :
+                       
+                       std::vector<std::string>::iterator it;
+                       for (it=im.begin(); it!=im.end(); ++it) 
+                       {
+                               vtkImageData* out = mReader.GetImage( (*it));
+                               s.push_back(out);
+                       }
+               }
+       }
+}
+  //======================================================================
+
+  //======================================================================
+  ///Requests the reading of an image
+  void GimmickView::RequestReading(tree::Node* n, 
+         int prio, int selection_index, boost::shared_ptr<ImagePointerHolder> p)
+  {
+         if(!mReaderStarted)
+         {
+               mReader.Start();
+               mReaderStarted=true;
+         }
+    ImageEventType t(n,selection_index);
+       t.pointerHolder = p;
+    mImageEventMap[n->GetAttribute("FullFileName")] = t;    
+    mReader.Request(this,n->GetAttribute("FullFileName"),prio);
+  }
+  //======================================================================
+
+  //======================================================================
+  void GimmickView::
+  OnMultiThreadImageReaderEvent(const std::string& filename,
+                               MultiThreadImageReaderUser::EventType e,
+                               vtkImageData* image)
+  {
+    GimmickDebugMessage(7,
+                       "MultiThreadImageReader event : "<<e<<std::endl);
+       if (e==ImageLoaded)
+       {
+               if (filename.size()==0)
+               {
+                 //What to do in this case?
+                 /*
+                       GimmickDebugMessage(5,
+                                       "Pushing unknown image in queue"
+                                       <<std::endl);
+                       mImageEventQueue.push_back(ImageEventType(image));*/
+                       return;
+               }
+               ImageEventTypeMap::iterator i;
+//JCP 22-06-2009, test mImageEventMap.size() > 0
+               if(mImageEventMap.size()>0){
+                       i = mImageEventMap.find(filename);
+                       if (i!=mImageEventMap.end())
+                       {
+                               GimmickDebugMessage(5,
+                                               "Putting image of file '"<<filename<<"' on pointer"
+                                               <<std::endl);
+                               ImageEventType ie(i->second);
+                               ie.image = image;
+                               ie.pointerHolder->Set(ie.image);
+                               //mImageEventMap.erase(i);
+                       }
+               }    
+       }
+       else if (e==Error)
+       {
+               std::string mess="ERROR: MultiThreadImageReader: Cannot read image in file ";
+               mess+=filename;
+               mess+="\n";
+               GimmickMessage(1,mess);
+               ImageEventTypeMap::iterator i;
+               i = mImageEventMap.find(filename);
+               if (i!=mImageEventMap.end())
+               {
+               ImageEventType ie(i->second);
+               ie.image = image;
+               ie.pointerHolder->Set(GetDefaultImage());
+               //mImageEventMap.erase(i);
+               }
+       }
+
+       else if (e==ImageUnloaded)
+       {
+               std::string mess="Unloaded image in file ";
+               mess+=filename;
+               mess+="\n";
+               GimmickMessage(1,mess);
+                               ImageEventTypeMap::iterator i;
+               i = mImageEventMap.find(filename);
+               if (i!=mImageEventMap.end())
+               {
+               ImageEventType ie(i->second);
+               ie.image = image;
+               ie.pointerHolder->Set(GetDefaultImage());
+               //mImageEventMap.erase(i);
+               }
+       }
+  }
+
+  //====================================================================
+
+  //====================================================================
+  void GimmickView::ConnectValidationObserver(ValidationCallbackType callback)
+  {
+    mValidationSignal.connect(callback);
+  }      
+  
+} // EO namespace creaImageIO
+
+//////////////////////////////////////////////////////////////////////
+//void GimmickView::Anonymize(std::vector<std::string> i_filenames, int type)
+//     {
+               //if(type == 0)
+               //{
+               //   // Get private key/certificate
+        //    gdcm::CryptographicMessageSyntax cms;
+               //if( !dumb_mode )
+  //  {
+  //  if( !GetRSAKeys(cms, rsa_path.c_str(), cert_path.c_str() ) )
+  //    {
+  //    return 1;
+  //    }
+  //  cms.SetCipherType( ciphertype );
+  //  }
+
+  //// Setup gdcm::Anonymizer
+  //gdcm::Anonymizer anon;
+  //if( !dumb_mode )
+  //  anon.SetCryptographicMessageSyntax( &cms );
+
+  //if( dumb_mode )
+  //  {
+  //  for(unsigned int i = 0; i < nfiles; ++i)
+  //    {
+  //    const char *in  = filenames[i].c_str();
+  //    const char *out = outfilenames[i].c_str();
+  //    if( !AnonymizeOneFileDumb(anon, in, out, empty_tags, remove_tags, replace_tags_value) )
+  //      {
+  //      //std::cerr << "Could not anonymize: " << in << std::endl;
+  //      return 1;
+  //      }
+  //    }
+  //  }
+  //else
+  //  {
+  //  for(unsigned int i = 0; i < nfiles; ++i)
+  //    {
+  //    const char *in  = filenames[i].c_str();
+  //    const char *out = outfilenames[i].c_str();
+  //    if( !AnonymizeOneFile(anon, in, out) )
+  //      {
+  //      //std::cerr << "Could not anonymize: " << in << std::endl;
+  //      return 1;
+  //      }
+  //    }
+  //  }
+//     }
\ No newline at end of file
diff --git a/src/creaImageIOGimmickView.h b/src/creaImageIOGimmickView.h
new file mode 100644 (file)
index 0000000..beb7bf2
--- /dev/null
@@ -0,0 +1,240 @@
+#ifndef __creaImageIOGimmickView_h_INCLUDED__
+#define __creaImageIOGimmickView_h_INCLUDED__
+
+#include <creaImageIOGimmick.h>
+#include <creaImageIOTreeView.h>
+#include <creaImageIOSystem.h>
+#include <creaImageIOImagePointerHolder.h>
+
+//#include <map>
+#include <vtkImageData.h>
+#include <creaImageIOMultiThreadImageReader.h>
+
+// Signal/slot mechanism for progress events
+#include <boost/signal.hpp>
+#include <boost/bind.hpp>
+
+#define GIMMICK_NO_IMAGE_SELECTION 0
+#define GIMMICK_2D_IMAGE_SELECTION 2
+#define GIMMICK_3D_IMAGE_SELECTION 3
+#define GIMMICK_4D_IMAGE_SELECTION 4
+
+#define NATIVE 0
+#define _2D    2
+#define _3D    3
+
+namespace creaImageIO
+{
+       /**
+       * \ingroup View
+       */
+        
+       class ImageExtent;
+    //=====================================================================
+    
+    //=====================================================================
+    ///Abstract class that handles views, attributes and previews (GUI) for Gimmick.
+       class GimmickView: public MultiThreadImageReaderUser
+    {
+    public:
+      /// Ctor
+      GimmickView(boost::shared_ptr<Gimmick>, int number_of_threads = 0 );
+      /// Virtual destructor
+      virtual ~GimmickView();
+      /// Initializes the view : 
+      /// Creates the TreeViews for all the TreeHandler of the Controller
+      /// 
+      virtual void Initialize();
+
+      /// Type of map from View name to TreeView* 
+      /// (This map is equivalent for Views of the TreeHandlerMap of Gimmick)
+      typedef std::map<std::string, TreeView*> TreeViewMapType;
+      
+      /// Returns the TreeViewMap (ref)
+      TreeViewMapType& GetTreeViewMap() { return mTreeViewMap; }
+      /// Returns the TreeViewMap (const ref)
+      const TreeViewMapType& GetTreeViewMap() const
+      { return mTreeViewMap; }
+
+      /// Finalize 
+      virtual void Finalize();
+
+         ///Returns the maximal priority
+      int GetMaximalPriority(){return mReader.GetMaximalPriority();}
+
+      ///Adds the selected Images to the given vector
+      virtual void GetSelectedImagesInVector(std::vector<vtkImageData*>& s, int dim)
+       { GimmickError("INTERNAL ERROR : GetSelectedImagesInVector not implemented"); }
+
+      ///Adds the selected Images to the given vector and validates to see if they comply with the given parameter (4D)
+      virtual void GetSelectedImages(std::vector<vtkImageData*>& s, int dim) 
+         { GimmickError("INTERNAL ERROR : GetSelectedImages not implemented"); }
+
+      virtual void GetSelectedFiles(std::vector<std::string>& s)
+      { GimmickError("INTERNAL ERROR : GetSelectedFiles not implemented"); }
+
+         virtual void GetImages(int dim, std::vector<std::string> files, std::vector<vtkImageData*>& s) 
+         { GimmickError("INTERNAL ERROR : GetImages not implemented"); }
+
+      virtual void OnSelectionChange(const std::vector<tree::Node*>& s, bool isSelection, int selection, bool mProcess)
+      { GimmickError("INTERNAL ERROR : OnSelectionChange not implemented"); }
+
+          virtual void ClearSelection()
+      { GimmickError("INTERNAL ERROR : ClearSelection not implemented"); }
+
+         ///Adds a file to ignore
+         virtual void AddIgnoreFile(tree::Node* toRemove)
+         { GimmickError("INTERNAL ERROR : AddIgnoreFile not implemented"); }
+      
+         ///Copies selected files
+         virtual void CopyFiles(const std::vector<std::string>& filenames)
+         { GimmickError("INTERNAL ERROR : CopyFiles not implemented"); }
+
+         ///Edits the fields of a given node
+         virtual void CreateEditFieldsDialog(tree::Node* node, std::vector<std::string> names, std::vector<std::string> keys)
+         { GimmickError("INTERNAL ERROR : EditFields not implemented"); }
+      
+         /// Anonymize or de-anonymize data
+         void Anonymize(std::vector<std::string> i_filenames, int type);
+         
+
+         /// Display all Dicom Tags
+         virtual void DumpTags(const std::string filename)
+         {GimmickError("INTERNAL ERROR : DumpTags not implemented"); }
+         
+           ///Edits the fields of a given node
+         virtual void ExportToStorage(const std::vector<std::string> keys)
+         { GimmickError("INTERNAL ERROR : ExportToStorage not implemented"); }
+      
+          ///Copies selected files
+         virtual void SaveAs(const std::vector<std::string>& filenames)
+         { GimmickError("INTERNAL ERROR : SaveAs not implemented"); }
+
+         /// No selected image
+         bool NoValidateSelected();
+
+      ///Validates the dimension compliance of the images with the maximum and minimum given, and between their sizes
+      bool ValidateSelected (tree::Node* sel, int min_dim, int max_dim);
+
+      ///Reads the vector of images, builds it in the dimension required and returns them in the supplied vector.
+         void ReadImagesNotThreaded(std::vector<vtkImageData*>& s,std::vector<std::string> files, int dim);
+
+      ///Reads the vector of images, builds it in the dimension required and returns them in the supplied vector.
+         void ReadImagesNotThreadedInVector(std::vector<vtkImageData*>& s,std::vector<std::string> files, int dim);
+
+///Requests the reading of an image with priority and index in the 
+      /// current selection (-1 if not in selection)
+      //void RequestReading(tree::Node* n, int prio, int selection_index , ImagePointerHolder *p);
+         void RequestReading(tree::Node* n, int prio, int selection_index , boost::shared_ptr<ImagePointerHolder> p);
+
+      ///Obtains the message of the state
+      std::string GetMessage(){return mMess;}
+
+     ///Obtains the message of the state
+      void SetMessage(std::string mess){mMess=mess;}
+
+         ///Resets the data of the extent and begins a new selection
+         void ResetExtent();
+
+      /// Create the tree views 
+      void CreateTreeViews();
+
+         /// Create a tree view with a given name
+         void CreateSingleTreeView(std::string &i_name);
+
+      /// Create the tree view for TreeHandler provided
+      virtual void CreateTreeView( TreeHandler* ) 
+      { GimmickError("INTERNAL ERROR : CreateTreeView not implemented"); }
+
+      /// Updates the TreeView of given name from level l to bottom
+      /// (calls the virtual method TreeView::UpdateLevel(l))
+      virtual void UpdateTreeViewLevel(const std::string&, int l);
+
+         // Multi-thread image reader callback
+         void OnMultiThreadImageReaderEvent(const std::string& filename,
+                                      MultiThreadImageReaderUser::EventType t,
+                                      vtkImageData* image);
+
+      vtkImageData* GetDefaultImage() { return mReader.GetImage(""); }
+
+      //=============================================
+      typedef boost::signal<void (bool)>  ValidationSignalType;
+      typedef ValidationSignalType::slot_function_type ValidationCallbackType;
+      //=============================================
+
+     //==================================================================
+      /// Adds the function f to the list of functions to call 
+      /// when the addition progresses.
+      /// f is of type ProgressCallbackType which is:
+      /// void (*ProgressCallbackType)(Progress&)
+      /// To pass a member function 'f' of an instance 'c' of a class 'C' 
+      /// as callback you have to 'bind' it, i.e. call:
+      /// ConnectValidationObserver ( boost::bind( &C::f , c, _1 ) );
+      void ConnectValidationObserver(ValidationCallbackType callback);
+     //==================================================================
+
+       void modifyValidationSignal(bool ivalid);
+
+    private:
+
+       double OrderTheFileNameVector(std::vector<std::string> &im);
+
+      /// Controller which manages the interaction with the model
+      boost::shared_ptr< Gimmick> mGimmick;
+
+      /// The views 
+      TreeViewMapType mTreeViewMap;
+
+      /// The message that results from the validation
+      std::string mMess;
+
+      /// Multi-thread image reader
+      MultiThreadImageReader mReader;
+
+      /// Internal type of image reading event
+      /// If the image pointer is non null then the image is available (loaded)
+      /// else it has been unloaded
+      struct ImageEventType
+      {
+       ImageEventType( tree::Node* no = 0,   
+                       int sel_index = -1)
+//                     ImagePointerHolder* ph= 0)
+          : node(no), index(sel_index){}//,  pointerHolder(ph){}
+        ImageEventType(vtkImageData* im )
+         : image(im) {}
+        tree::Node* node;
+        vtkImageData* image;
+               int index;
+               boost::shared_ptr<ImagePointerHolder> pointerHolder;
+      };
+      typedef std::map<std::string,ImageEventType> ImageEventTypeMap;
+      /// Map of images' names to ImageEventType
+      /// Used to associated a filename to a the data of a request
+      ImageEventTypeMap mImageEventMap;
+
+      // queue of image event 
+      typedef std::deque<ImageEventType> ImageEventQueueType;
+
+      //ImageEventQueueType mImageEventQueue;
+
+         ///The current image extent
+         boost::shared_ptr<ImageExtent> mImageExtent;
+
+         ///The validation signal
+         ValidationSignalType mValidationSignal;
+
+         ///Boolean that determines if the selection is valid
+         bool valid;
+
+         ///Boolean that determines if the reader has been started
+         bool mReaderStarted;
+
+       };
+  // EO class GimmickView
+    //=====================================================================
+
+} // EO namespace creaImageIO
+
+// EOF
+#endif
diff --git a/src/creaImageIOImagePointerHolder.h b/src/creaImageIOImagePointerHolder.h
new file mode 100644 (file)
index 0000000..98251b6
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __creaImageIOImagePointerHolder_INCLUDED__
+#define __creaImageIOImagePointerHolder_INCLUDED__
+
+#include <creaImageIOSystem.h>
+#include <vtkImageData.h>
+#include <boost/thread/mutex.hpp>
+
+
+namespace creaImageIO
+{
+         // The class that holds the pointer to the images to show
+               class ImagePointerHolder
+               {
+               public:
+                       ImagePointerHolder(vtkImageData* im):
+               mImage(im)
+               {}
+               ImagePointerHolder();
+               void Set(vtkImageData* im){boost::mutex::scoped_lock lock(mMutex);mImage=im;}
+               vtkImageData* Get(){boost::mutex::scoped_lock lock(mMutex);return mImage;}
+               private:
+                       vtkImageData* mImage;
+                       /// The mutex
+                       boost::mutex mMutex;
+               };
+}
+#endif
+
+
diff --git a/src/creaImageIOImageReader.cpp b/src/creaImageIOImageReader.cpp
new file mode 100644 (file)
index 0000000..4b67e04
--- /dev/null
@@ -0,0 +1,208 @@
+#include <creaImageIOImageReader.h>
+#include <creaImageIOTreeAttributeDescriptor.h>
+#include <creaImageIOSystem.h>
+
+#include <creaImageIOVtkImageReader.h>
+#if defined (USE_GDCM)
+       #include <creaImageIODicomImageReader.h>
+#endif
+#if defined(USE_GDCM2)
+       #include <creaImageIODicomImageReader2.h>
+#endif
+#include <creaImageIOUltrasonixImageReader.h>
+#include <vtkPNGReader.h>
+#include <vtkTIFFReader.h>
+#include <vtkJPEGReader.h>
+#include <vtkBMPReader.h>
+#include <vtkSLCReader.h>
+#include <vtkMetaImageReader.h>
+//#include <vtkGESignalReader.h>
+
+
+#include "boost/filesystem/path.hpp"
+
+namespace creaImageIO
+{
+  
+
+
+
+
+  //=====================================================================
+  ImageReader::ImageReader()
+    :   
+    mUnreadableImage(0),
+    mLastFilename("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
+  {
+    //    std::cout << "#### ImageReader::ImageReader()"<<std::endl;
+    if (mUnreadableImage!=0) return;
+       
+       Register( boost::shared_ptr<AbstractImageReader>(new VtkImageReader(vtkPNGReader::New(), "PNG", ".png")));
+    Register(boost::shared_ptr<AbstractImageReader>(new VtkImageReader(vtkTIFFReader::New(), "JPEG", ".jpeg")));
+    Register(boost::shared_ptr<AbstractImageReader>(new VtkImageReader(vtkJPEGReader::New())));
+    Register(boost::shared_ptr<AbstractImageReader>(new VtkImageReader(vtkBMPReader::New())));
+    Register(boost::shared_ptr<AbstractImageReader>(new VtkImageReader(vtkSLCReader::New())));
+    Register(boost::shared_ptr<AbstractImageReader>(new VtkImageReader(vtkMetaImageReader::New(),"MHD",".mhd")));
+    //   Register(new VtkImageReader(vtkGESignalReader::New()));
+    Register(boost::shared_ptr<AbstractImageReader>(new DicomImageReader));
+    Register(boost::shared_ptr<AbstractImageReader>(new UltrasonixImageReader));
+
+       UnRegister(".txt");
+    mUnreadableImage = vtkImageData::New();
+    int dim[3];
+    dim[0] = dim[1] = 128; 
+    dim[2] = 1; 
+    mUnreadableImage->SetDimensions ( dim );
+    mUnreadableImage->SetScalarTypeToUnsignedChar();
+    mUnreadableImage->AllocateScalars();    
+    for (int i=0;i<dim[0];i++) 
+      for (int j=0;j<dim[1];j++) 
+       mUnreadableImage->SetScalarComponentFromFloat(i,j,0,0,0);
+    for (int i=0;i<dim[0];i++) 
+      {
+       mUnreadableImage->SetScalarComponentFromFloat(i,i,0,0,255);
+       mUnreadableImage->SetScalarComponentFromFloat(dim[0]-1-i,i,0,0,255);
+      }
+
+
+    
+  }
+  //=====================================================================
+
+  //=====================================================================
+  ImageReader::~ImageReader()
+  {
+
+ //   for (i=mReader.begin(); i!=mReader.end(); i++)
+ //     {
+       //delete (*i);
+ //     }
+//    mReader.clear();
+    if (mUnreadableImage!=0) 
+      {
+       mUnreadableImage->Delete();
+       mUnreadableImage = 0;
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void ImageReader::Register(boost::shared_ptr<AbstractImageReader> r)
+  {
+    mReader.push_back(r);
+
+  }
+
+  void ImageReader::UnRegister(const std::string i_val)
+  {
+    mUnReader.push_back(i_val);
+
+  }
+  //=====================================================================
+
+   //=====================================================================
+  // Returns true iff the file is readable
+  bool ImageReader::ShallNotRead( const std::string& filename ) 
+  {
+    bool ok = true;
+       if(filename != "")
+       {
+               std::vector<std::string >::iterator i ;
+               for (i=mUnReader.begin(); i!=mUnReader.end(); i++)
+               {
+                       
+                       if ( (*i).c_str() == filename) 
+                       {
+                               ok = false;
+                               break;
+                       }
+               }
+       }
+       return ok;
+       
+  }
+
+
+  //=====================================================================
+  // Returns true iff the file is readable
+  bool ImageReader::CanRead( const std::string& filename ) 
+  {
+    bool ok = false;
+
+       if( !ShallNotRead(filename))
+       {
+               return ok;
+       }
+       if(filename != "")
+       {
+               std::vector<boost::shared_ptr<AbstractImageReader> >::iterator i;
+               for (i=mReader.begin(); i!=mReader.end(); i++)
+               {
+                       ok = (*i)->CanRead(filename);
+                       if (ok) 
+                       {
+                               mLastFilename = filename;
+                               mLastReader = *i;
+                               break;
+                       }
+               }
+       }
+       return ok;
+       
+  }
+  //=====================================================================
+
+  //=====================================================================
+  // Reads the file (CanRead must be called before : no test here)
+  vtkImageData*  ImageReader::ReadImage( const std::string& filename)
+  {
+         if (mLastFilename!=filename)
+      {
+       if (!CanRead(filename))  
+         { 
+           vtkImageData* im = vtkImageData::New();
+           im->ShallowCopy(mUnreadableImage);
+           return im;
+         }
+      }
+    vtkImageData* i = mLastReader->ReadImage(mLastFilename);
+    if (i==0) 
+      {
+       i = vtkImageData::New();
+       i->ShallowCopy(mUnreadableImage);
+      }
+    return i;
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+   void ImageReader::ReadAttributes(const std::string& filename, 
+                                   std::map<std::string,std::string>& attr)
+   {
+    if (mLastFilename!=filename)
+      {
+       if (!CanRead(filename)) 
+         { 
+           return;
+         }
+      }
+    mLastReader->ReadAttributes(mLastFilename,attr);
+   }
+  //=====================================================================
+
+
+  //=====================================================================
+  /// Pushes back all kwown extensions (without dot) in the vector given
+  void ImageReader::PushBackExtensions(std::vector<std::string>& v)
+  {
+         std::vector<boost::shared_ptr<AbstractImageReader> >::iterator i;
+    for (i=mReader.begin(); i!=mReader.end(); i++)
+      {
+       (*i)->PushBackExtensions(v);
+      }
+  }
+  //=====================================================================
+  
+} // namespace creaImageIO
diff --git a/src/creaImageIOImageReader.h b/src/creaImageIOImageReader.h
new file mode 100644 (file)
index 0000000..ab9fbe7
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __creaImageIOImageReader_h_INCLUDED__
+#define __creaImageIOImageReader_h_INCLUDED__
+
+#include <creaImageIOSystem.h>
+#include <creaImageIOAbstractImageReader.h>
+
+namespace creaImageIO
+{
+
+  /**
+   * \ingroup IO
+   * \brief Generic image reader which uses all the specific concrete image reader of the lib (tif, jpg, dicom, ...)
+   */
+  class CREAIMAGEIO_EXPORT ImageReader : virtual public AbstractImageReader
+  {
+  public:
+    ImageReader();
+    ~ImageReader();
+
+    /// Pushes back all kwown extensions (without dot) in the vector given
+    void PushBackExtensions(std::vector<std::string>&);
+
+    /// Returns true iff the file is readable
+    bool CanRead( const std::string& filename);
+    /// Reads and returns the image data. 
+    /// Returns an "Unreadable image" picture if fails
+    vtkImageData* ReadImage( const std::string& filename);
+    
+    /// Reads the attributes of the image.
+    /// Requested attributes names are provided as keys 
+    /// in a string to string map
+    /// On return, the values of the map are the values 
+    /// of the attributes (empty string if not available).
+    void ReadAttributes(const std::string& filename, 
+                       tree::AttributeMapType& attr);
+
+    /// Exclude specific readers 
+    /// TO DO...
+    
+
+  protected:
+    
+    /// Register a reader
+    void Register( boost::shared_ptr<AbstractImageReader> );
+
+       std::vector<boost::shared_ptr<AbstractImageReader> > mReader;
+    vtkImageData* mUnreadableImage;
+
+    std::string mLastFilename;
+       boost::shared_ptr<AbstractImageReader> mLastReader;
+
+       bool ShallNotRead( const std::string& filename );
+
+       void UnRegister(const std::string i_val);
+
+       std::vector <std::string> mUnReader;
+    
+  private:
+
+  }; // class ImageReader
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIOImageReader_h_INCLUDED__
diff --git a/src/creaImageIOIndexedHeap.h b/src/creaImageIOIndexedHeap.h
new file mode 100644 (file)
index 0000000..8568b67
--- /dev/null
@@ -0,0 +1,139 @@
+/* 
+
+*/
+/*! \file 
+       \brief Indexed priority queues handled by binary trees.
+*/
+#ifndef __creaImageIOIndexedHeap_h_INCLUDED__
+#define __creaImageIOIndexedHeap_h_INCLUDED__
+
+#include <vector>
+
+namespace creaImageIO 
+{
+
+       
+
+  template <class T, 
+           class Comparator/*=Less<T>*/,
+           class Indexer/*=Index<T> */> 
+  class IndexedHeap ;
+  template < class T, 
+            class C, 
+            class I> 
+  std::ostream& operator << (std::ostream&, const IndexedHeap<T,C,I>& );
+
+  //template <class T, class Comparator=std::less<T>, class Index=IndexIndex<T> > class SlicedIndexedHeap; 
+
+
+  //========================================================================
+  /// \brief Indexed priority queues handled by binary trees. 
+  /// 
+  ///  Heap Allows :
+  ///          - log(n) insertion
+  ///          - constant time acces to the first element
+  ///          - log(n) removal of the first element
+  ///          - log(n) priority change of a random element 
+  /// Indexation Allows :
+  ///          - constant time access to a random element (for priority change)
+  /// 
+  /// The Indexer is an unary_function<T,int&> whose operator()(T& t) 
+  /// returns a reference on an integer which 
+  /// is maintained by the IndexedHeap in order to provide at any time 
+  /// the position of the object t in the Heap 
+  /// (hence allowing constant time random access to an object). 
+  template <class T, 
+           class Comparator /*=Less<T>*/, 
+           class Indexer /*=Index<T>*/> 
+  class IndexedHeap 
+  {
+    //                 friend class SlicedIndexedHeap<T,Comparator,Index>;
+  public :
+               
+    //======================================================================
+    /// Constructor 
+    IndexedHeap () {}
+    /// Constructor 
+    IndexedHeap ( const Comparator& comp, const Indexer& ind ) ;
+    /// Destructor 
+    ~IndexedHeap() { }
+    /// Sets the comparator 
+    void set( const Comparator& comp );
+    /// Sets the Index 
+    void set( const Indexer& ind );
+    //======================================================================
+               
+    //======================================================================
+    /// inserts an element in the Heap and returns its position 
+    int insert(T);
+    /// return a reference on the first element of the Heap 
+    T& top(); 
+    /// return a constant reference on the first element of the Heap 
+    const T& top() const;  
+    /// removes and returns the first element of the Heap 
+    T remove_top();
+    /// removes and returns the nth element 
+    T remove(int n);
+    /// returns the size of the Heap 
+    inline int size() const {return m_p.size(); }
+    /// empties the Heap 
+       void clear();
+    //======================================================================
+       
+    //======================================================================
+    /// returns a constant on the stack of elements 
+    const std::vector<T> & stack() const {return m_p;}
+    /// returns a reference to the ith element of the stack 
+    T& operator [] (int i) { return m_p[i];}
+    /// returns a constant reference to the ith element of the stack 
+    const T& operator [] (int i) const { return m_p[i];}
+    /// returns the index (position) of t 
+    inline int index(T& t) { return (*m_i)(t); }
+    //======================================================================
+
+    //======================================================================
+    /// returns the position of the father of i 
+    inline int father( int i ) const;
+    /// returns the position of the right son of i 
+    inline int rightson( int i ) const;
+    /// returns the position of the leftson of i 
+    inline int leftson( int i ) const;
+    //======================================================================
+    /// swaps ith and jth elements 
+    inline void swap(int i, int j);
+    /// remonte un element dans le tas tant qu'il n'est pas a sa place. 
+    /// renvoie la position finale 
+    inline int upsort(int);
+    /// descend un element dans le tas tant qu'il n'est pas a sa place.
+    /// renvoie la position finale
+    inline int downsort(int);
+    //======================================================================
+                       
+  protected : 
+    /// binary tree handled by a vector 
+    std::vector<T> m_p;
+    /// comparator pointer 
+    const Comparator* m_c;
+    /// Index pointer 
+    const Indexer*  m_i;
+  };
+  //========================================================================
+  // EO class IndexedHeap
+  //========================================================================
+
+
+#include "creaImageIOIndexedHeap.txx"
+
+
+};
+//===========================================================================
+// EO namespace creaImageIO
+//===========================================================================
+
+
+
+//===========================================================================
+// EOF
+//===========================================================================
+#endif
diff --git a/src/creaImageIOIndexedHeap.txx b/src/creaImageIOIndexedHeap.txx
new file mode 100644 (file)
index 0000000..b5b5753
--- /dev/null
@@ -0,0 +1,235 @@
+/* 
+
+*/
+/*! \file 
+  \brief Code of IndexedHeap
+*/
+//============================================================================
+template <class T, class CT, class IT>
+std::ostream& operator << (std::ostream& s, const IndexedHeap<T,CT,IT>& t)
+{
+  s << "[";
+  for (int i=0; i<t.size(); i++) s << t[i] << " "  ;
+  s << "]";
+  return s;
+}
+//============================================================================
+
+
+//===========================================================
+template <class T, class CT, class IT>
+IndexedHeap<T,CT,IT>::IndexedHeap ( const CT& comp, const IT& index ) 
+  : m_c(&comp), m_i(&index) 
+{}
+//===========================================================
+
+
+//===========================================================
+template <class T, class CT, class IT>
+void IndexedHeap<T,CT,IT>::set( const CT& comp ) 
+{ 
+  m_c = &comp; 
+}
+//===========================================================
+
+//===========================================================
+template <class T, class CT, class IT>
+void IndexedHeap<T,CT,IT>::set ( const IT& index ) 
+{ 
+  m_i = &index; 
+}
+//===========================================================
+
+
+//===========================================================
+template <class T, class CT, class IT>
+int IndexedHeap<T,CT,IT>::insert(T t)
+{
+  m_p.push_back(t);
+  (*m_i)(t) = size()-1;
+  return upsort(size()-1);
+}
+//===========================================================
+
+//===========================================================
+template <class T, class CT, class IT>
+T& IndexedHeap<T,CT,IT>::top()
+{
+  //  lglASSERT( size() > 0)
+    return m_p.front();
+}
+//===========================================================
+
+
+//===========================================================
+template <class T, class CT, class IT>
+const T& IndexedHeap<T,CT,IT>::top() const
+{
+  //  lglASSERT( size() > 0)
+    return m_p.front();
+}
+//===========================================================
+
+//===========================================================
+template <class T, class CT, class IT>
+T IndexedHeap<T,CT,IT>::remove_top()
+{
+  //  lglASSERT( size() > 0 ) 
+    T f(m_p[0]);
+  (*m_i)(f) = -1;
+  T last = m_p.back();
+  m_p.pop_back();
+  if (m_p.size()>0) 
+    {
+    m_p[0] = last;
+    (*m_i)(last) = 0;
+    downsort(0);
+  }
+  return f;
+}
+//============================================================================
+
+
+
+//============================================================================
+template <class T, class CT, class IT>
+T IndexedHeap<T,CT,IT>::remove(int n)
+{
+  //  lglASSERT ( (n>=0)&&(n<size()) ) 
+    T f(m_p[n]);
+  (*m_i)(f) = -1;
+  T last = m_p.back();
+  m_p.pop_back();
+  if (m_p.size()>0) 
+    {
+    m_p[n] = last;
+    (*m_i)(last) = n;
+    downsort(n);
+  }
+  return f;
+}
+//============================================================================
+
+
+//============================================================================
+template <class T, class CT, class IT>
+void IndexedHeap<T,CT,IT>::clear()
+{
+  for (typename std::vector<T>::iterator i=m_p.begin(); i!=m_p.end(); ++i) 
+    { 
+      (*m_i)(*i)=-1; 
+    }
+  m_p.clear();
+}
+//============================================================================
+
+
+//============================================================================
+template <class T, class CT, class IT>
+int  IndexedHeap<T,CT,IT>::father( int  i) const
+{
+  return ((i-1)/2);
+}
+//============================================================================
+
+//============================================================================
+template <class T, class CT, class IT>
+int  IndexedHeap<T,CT,IT>::rightson( int  i) const
+{ 
+  return (i*2+2);
+}
+//============================================================================
+
+//============================================================================
+template <class T, class CT, class IT>
+int  IndexedHeap<T,CT,IT>::leftson( int  i) const
+{ 
+  return (i*2+1);
+}
+//============================================================================
+
+//============================================================================
+template <class T, class CT, class IT>
+void IndexedHeap<T,CT,IT>::swap(int i, int j)
+{
+  T tmp = m_p[i];
+  m_p[i] = m_p[j];
+  m_p[j] = tmp;
+  // update indices  
+  (*m_i)(m_p[i]) = i;
+  (*m_i)(m_p[j]) = j;
+}
+//============================================================================
+
+
+
+//============================================================================
+template <class T, class CT, class IT>
+int  IndexedHeap<T,CT,IT>::upsort(int  i)
+{
+  //if (i==0) return i;
+  int  j = father(i);
+  while ((i>0)&&(*m_c)(m_p[i],m_p[j])) 
+    {
+    swap(i,j);
+    i = j;
+    j = father(j);
+  }    
+  return i;
+}
+//============================================================================
+
+
+//============================================================================
+template <class T, class CT, class IT>
+int  IndexedHeap<T,CT,IT>::downsort(int  i)
+{
+  do 
+    {
+      
+      unsigned int  ls = leftson(i);
+      if (ls<m_p.size()) 
+       {
+      bool lc = ((*m_c)(m_p[i],m_p[ls]));
+      unsigned int  rs = ls + 1;
+      bool rc = true;
+      if (rs<m_p.size()) rc = ((*m_c)(m_p[i],m_p[rs]));
+      if  ( !lc ) 
+       { 
+       if ( !rc ) 
+         { 
+         if ((*m_c)(m_p[ls],m_p[rs])) 
+           { 
+           swap(i,ls);
+           i = ls;
+         }
+         else 
+           { 
+           swap(i,rs);
+           i = rs;
+         }
+       }
+       else 
+         {
+         swap(i,ls);
+         i = ls;
+       }
+      }
+      else if ( !rc ) 
+       { 
+       swap(i,rs);
+       i = rs;
+      }
+      else return i;
+    } 
+    else return i;
+  }
+  while (true);
+  return i;
+}
+//============================================================================
+
+
+//============================================================================
+// EOF
+//============================================================================
diff --git a/src/creaImageIOListener.cpp b/src/creaImageIOListener.cpp
new file mode 100644 (file)
index 0000000..33090d5
--- /dev/null
@@ -0,0 +1,104 @@
+#include <creaImageIOListener.h>
+#include <creaImageIOSystem.h>
+#include "boost/filesystem.hpp"
+#include <boost/filesystem/operations.hpp>
+#include <boost/utility.hpp>
+
+namespace fs = boost::filesystem;
+using boost::filesystem::path;
+
+using namespace crea;
+
+namespace creaImageIO
+{
+  //=====================================================================
+  // CTor
+  Listener::Listener()
+  {
+
+       boost::mutex::scoped_lock lock(mMutex);
+    GimmickDebugMessage(6,"Listener::Listener"
+                       <<std::endl);
+       mDrive="E:";
+       mMounted=false;
+       mAddFiles=false;
+       mRemoveFiles=true;
+
+  }
+  //=====================================================================
+
+  //=====================================================================
+  /// Destructor
+  Listener::~Listener()
+  {
+    boost::mutex::scoped_lock lock(mMutex);
+    GimmickDebugMessage(6,"Listener::~Listener"
+                       <<std::endl);
+  }
+  //=====================================================================
+
+  void*  Listener::Entry()
+  {      
+    GimmickDebugMessage(6,"Listener::Entry()"<<std::endl);
+       while(!TestDestroy())
+         { 
+               try  
+               {
+                       fs::exists( mDrive );
+                       if(!mMounted && mAddFiles)
+                       {
+                               mMounted=true;
+                               SendSignal(mMounted);           
+                       }
+                       else if(!mMounted)
+                       {
+                               mMounted=true;
+                       }
+                       
+               }
+               catch (...)
+               {
+                       if(mMounted && mRemoveFiles)
+                       {
+                         mMounted=false;
+                         SendSignal(mMounted);
+                       }
+                       else if(mMounted)
+                       {
+                               mMounted=false;
+                       }
+               }
+
+               clock_t endwait;
+               endwait = clock () + 0.001 * CLOCKS_PER_SEC ;
+               while (clock() < endwait ) {}
+                       
+      }
+    return 0;
+  }
+
+  //=====================================================================
+
+  //=====================================================================
+  void Listener::OnExit()
+  {
+    GimmickDebugMessage(6,"Listener::OnExit() "<<std::endl);
+  }
+
+   //====================================================================
+  void Listener::ConnectObserver(MountingCallbackType callback)
+  {
+    mMountingSignal.connect(callback);
+  }
+
+   //======================================================================
+  void Listener::SendSignal(bool mount)
+  {
+         mMountingSignal(mount);
+  }
+
+
+
+} // EO namespace creaImageIO
+
diff --git a/src/creaImageIOListener.h b/src/creaImageIOListener.h
new file mode 100644 (file)
index 0000000..fe65ed8
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __creaImageIOListener_h_INCLUDED__
+#define __creaImageIOListener_h_INCLUDED__
+
+#include <creaImageIOSystem.h>
+#include <stdio.h>
+#include <time.h>
+#include <wx/thread.h>
+// Signal/slot mechanism
+#include <boost/signal.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+
+namespace creaImageIO
+{
+
+  class Listener : public wxThread
+  {
+  public:
+    /// Ctors 
+    Listener();
+    /// Dtor
+    virtual ~Listener();
+       ///Thread method that is executed once create is called
+       void* Entry();
+       ///Thread method called upon exiting
+    void  OnExit();
+       ///Sets the new state of adding files
+       void SetAddFilesState(bool addFiles){boost::mutex::scoped_lock lock(mMutex);mAddFiles=addFiles;}
+       ///Sets the new state of removing files
+       void SetRemoveFilesState(bool removeFiles){boost::mutex::scoped_lock lock(mMutex);mRemoveFiles=removeFiles;}
+       ///Sets the new monitored drive
+       void SetMonitoredDrive(const std::string& dr){boost::mutex::scoped_lock lock(mMutex);mDrive=dr;}
+       ///Puts the name of the monitored drive in the given string
+       void GetMonitoredDrive(std::string& drive){drive=mDrive;}
+
+       ///Related with signals
+       //=============================================
+    typedef boost::signal<void (bool)>  MountingSignalType;
+    typedef MountingSignalType::slot_function_type MountingCallbackType;
+    //=============================================
+
+    //==================================================================
+    void ConnectObserver(MountingCallbackType callback);
+    //==================================================================
+
+       ///Sends a boost::signal to alert that the drive has changed its state (mounted/unmounted)
+       void SendSignal(bool ivalid);
+  
+
+  private:
+    /// The mutex
+    boost::mutex mMutex;
+    /// Boolean that declares if the files that are read on CD mount should be added
+    bool mAddFiles;
+       /// Boolean that declares if, on CD unmount, the files that were in the drive should be removed
+    bool mRemoveFiles;
+       ///Boolean that declares if a unit has been mounted
+       bool mMounted;
+       ///The monitored drive
+       std::string mDrive;
+       ///The validation signal
+       MountingSignalType mMountingSignal;
+  };
+
+}
+
+#endif  
diff --git a/src/creaImageIOMultiThreadImageReader.cpp b/src/creaImageIOMultiThreadImageReader.cpp
new file mode 100644 (file)
index 0000000..3ee50de
--- /dev/null
@@ -0,0 +1,638 @@
+#include <creaImageIOMultiThreadImageReader.h>
+#include <creaImageIOImageReader.h>
+#include <wx/utils.h>
+#include <creaImageIOSystem.h>
+
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+
+  //=====================================================================
+  void MultiThreadImageReaderUser::MultiThreadImageReaderSendEvent
+  ( const std::string& filename,
+    EventType type,
+    vtkImageData* image)
+  {
+    wxMutexLocker lock(mMultiThreadImageReaderUserMutex);
+
+    this->OnMultiThreadImageReaderEvent(filename,type,image);
+  }
+  //=====================================================================
+
+  //=====================================================================
+  class ThreadedImageReader: public wxThread
+  {
+  public:
+    ThreadedImageReader(MultiThreadImageReader* tir) :
+      mMultiThreadImageReader(tir)
+    {}
+
+    void* Entry();
+    void  OnExit();
+
+    vtkImageData* Read(const std::string& filename);
+    
+       struct deleter
+       {
+               void operator()(ThreadedImageReader* p)
+               {
+                       p->Delete();
+               }
+       };
+       friend struct deleter;
+
+
+  private:
+    ImageReader mReader;
+    MultiThreadImageReader* mMultiThreadImageReader;
+       
+  };
+
+  //=====================================================================
+
+  
+  //=====================================================================
+  MultiThreadImageReader::MultiThreadImageReader(int number_of_threads)
+    : //mDoNotSignal(false),
+      mReader(0),
+      mTotalMem(0),
+      mTotalMemMax(1000000)
+  {
+    //    std::cout << "#### MultiThreadImageReader::MultiThreadImageReader("
+    //       << " #threads= " << number_of_threads <<" )"<<std::endl;
+
+         mDone = false;
+    // Create the threads
+    for (int i=0; i<number_of_threads; i++) 
+      {
+                 //ThreadedImageReader* t = new ThreadedImageReader(this);
+                 boost::shared_ptr<ThreadedImageReader> t(new ThreadedImageReader(this), ThreadedImageReader::deleter());
+       mThreadedImageReaderList.push_back(t);
+        std::cout << "  ===> Thread "<<i
+                     <<" successfully added"<< std::endl;
+      }
+    mNumberOfThreadedReadersRunning = 0;
+    // Init the queue
+    mQueue.set(mComparator);
+    mQueue.set(mIndexer);
+    // 
+    // no thread : alloc self reader
+//    if (number_of_threads==0)
+//      {
+       mReader = new ImageReader();
+//      }
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  bool MultiThreadImageReader::Start()
+  {
+
+    //    std::cout << "#### MultiThreadImageReader::Start()"
+    //               <<std::endl;
+         if (mNumberOfThreadedReadersRunning > 0) return true;
+         
+    ThreadedImageReaderListType::iterator i;
+    for (i =mThreadedImageReaderList.begin();
+        i!=mThreadedImageReaderList.end();
+        i++)
+      {
+       (*i)->Create();
+       if ( (*i)->Run() != wxTHREAD_NO_ERROR )
+         {
+           std::cout << "ERROR starting a thread"<< std::endl;
+           return false;
+         }
+       else 
+         {
+                   std::cout << "  ===> Thread "<<(*i)->GetCurrentId()
+                             <<" successfully created"<< std::endl;
+           
+         }
+      }
+    wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
+    //    std::cout << "EO Start : #Threads running = "
+    //               << mNumberOfThreadedReadersRunning<<std::endl;
+
+    return true;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void MultiThreadImageReader::Stop()
+  { 
+//                 std::cout << "#### MultiThreadImageReader::Stop()"
+//           <<std::endl;
+  //  std::cout << "Sending stop order to the threads..."<<std::endl;
+         if (mDone) return;
+
+    ThreadedImageReaderListType::iterator i;
+    for (i =mThreadedImageReaderList.begin();
+        i!=mThreadedImageReaderList.end();
+        i++)
+      { std::cout << "  ===> Thread "<<(*i)->GetCurrentId()
+                             <<" successfully stopped"<< std::endl;
+                 if((*i)->IsAlive())
+                 {(*i)->Pause();
+                         (*i).reset();
+                        //                       (*i)->Delete();
+                 }
+      }
+   mThreadedImageReaderList.clear();
+    // Wait a little to be sure that all threads have stopped
+    // A better way to do this ?
+    //    wxMilliSleep(1000);
+    // New method : the threads generate a stop event when they have finished
+    // We wait until all threads have stopped
+//        std::cout << "Waiting for stop signals..."<<std::endl;
+    do 
+      {
+       // Sleep a little
+               wxMilliSleep(10);
+       // Lock
+       {
+         wxMutexLocker locker(GetMultiThreadImageReaderUserMutex());
+//               std::cout << "#Threads running = "
+//                         << mNumberOfThreadedReadersRunning<<std::endl;
+         // Break if all readers have stopped
+         if (mNumberOfThreadedReadersRunning <= 0) 
+           {
+             break;
+           }
+       }
+      } 
+    while (true);
+//        std::cout << "All threads stopped : OK "<<std::endl;
+
+    ImageMapType::iterator j;
+    for (j =mImages.begin();
+        j!=mImages.end();
+        ++j)
+
+      {
+       delete j->first;
+      }
+    mImages.clear();
+       mDone = true;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  MultiThreadImageReader::~MultiThreadImageReader()
+  {
+    //    std::cout << "#### MultiThreadImageReader::~MultiThreadImageReader()"
+    //       <<std::endl;
+    Stop();
+    if (mReader) delete mReader;
+       mThreadedImageReaderList.clear();
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void MultiThreadImageReader::UpdateUnloadPriority(ImageToLoadPtr p, 
+                                                   int priority)
+  {
+    // not in unload queue : ciao
+    if (p->UnloadIndex()<0) return;
+    int old_prio = p->GetPriority();
+    if (priority > old_prio) 
+      {
+       p->SetPriority(priority);
+       mUnloadQueue.downsort(p->UnloadIndex());
+      }
+    else if ( old_prio > priority )
+      {
+       p->SetPriority(priority);
+       mUnloadQueue.upsort(p->UnloadIndex());
+     }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void MultiThreadImageReader::Request( MultiThreadImageReaderUser* user,
+                                       const std::string& filename, 
+                                       int priority )
+  {
+       wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
+
+         if (mNumberOfThreadedReadersRunning==0)
+//    if (mThreadedImageReaderList.size()==0) 
+      {
+       // no detached reader : use self reader
+       ImageToLoad itl(user,filename);
+       ImageMapType::iterator i = mImages.find(&itl);
+       if (i!=mImages.end())
+         {
+           ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+           // Already inserted
+           if (pitl->GetImage() != 0)
+             {
+               // Already read
+               pitl->SetUser(user);
+               UpdateUnloadPriority(pitl,priority);
+               SignalImageRead(pitl,false);
+               return; // pitl->GetImage();
+             }
+         }
+       ImageToLoadPtr pitl = new ImageToLoad(user,filename,0);
+       mImages[pitl] = 0;
+       pitl->SetImage(mReader->ReadImage(filename));
+       UpdateUnloadPriority(pitl,priority);
+       SignalImageRead(pitl,true);
+       //      return pitl->GetImage();
+       return;
+      }
+
+    ImageToLoad itl(user,filename);
+    ImageMapType::iterator i = mImages.find(&itl);
+    if (i!=mImages.end())
+      {
+       // Already inserted
+       if (i->first->GetImage() != 0)
+         {
+           // Already read : ok :signal the user
+           UpdateUnloadPriority(i->first,priority);
+           SignalImageRead(i->first,false);
+           return;
+         }
+       /// Already requested : change the priority
+       ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+       pitl->SetPriority(priority);
+       // Already in queue
+       if (pitl->Index()>=0) 
+         {
+           // Re-sort the queue
+           mQueue.upsort(pitl->Index());
+         }
+       // Not read but not in queue = being read = ok
+       else 
+         {
+           
+         }
+      }
+    else 
+      {
+       // Never requested before or unloaded 
+       ImageToLoadPtr pitl = new ImageToLoad(user,filename,priority);
+       mImages[pitl] = 0;
+       mQueue.insert(pitl);
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void MultiThreadImageReader::OnMultiThreadImageReaderEvent
+  (const std::string& filename,
+   MultiThreadImageReaderUser::EventType e,
+   vtkImageData* image)
+  {
+    if ((e==MultiThreadImageReaderUser::ImageLoaded) &&
+       (filename == mRequestedFilename))
+      {
+       mRequestedImage = image;
+      }
+    else if (e==MultiThreadImageReaderUser::ThreadedReaderStarted)
+      {
+       mNumberOfThreadedReadersRunning++;
+       //      std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
+      }
+    else if (e==MultiThreadImageReaderUser::ThreadedReaderStopped)
+      {
+       
+                mNumberOfThreadedReadersRunning--;
+       //      std::cout << "#TR=" << mNumberOfThreadedReadersRunning << std::endl;
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  vtkImageData* MultiThreadImageReader::GetImage(const std::string& filename)
+  {
+        // Start();
+    //       std::cout << "** MultiThreadImageReader::GetImage('"<<filename<<"')"
+    //          <<std::endl;
+    
+    do 
+      {
+       //      wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
+               
+       //     std::cout << "** MultiThreadImageReader::GetImage('"<<filename
+       //             <<"') lock ok"
+       //               <<std::endl;
+    
+       //                if (mNumberOfThreadedReadersRunning==0)
+       //      if (mThreadedImageReaderList.size()==0)
+       if (true)
+         {
+           ImageToLoad itl(this,filename);
+           ImageMapType::iterator i = mImages.find(&itl);
+           if (i!=mImages.end())
+             {
+               ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+               // Already inserted
+               if (pitl->GetImage() != 0)
+                 {
+                   // Already read
+                   UpdateUnloadPriority(pitl,
+                                        GetMaximalPriorityWithoutLocking()+1);
+                   return pitl->GetImage();
+                 }
+             }
+           ImageToLoadPtr pitl = new ImageToLoad(this,filename,0);
+           mImages[pitl] = 0;
+           pitl->SetImage(mReader->ReadImage(filename));
+           UpdateUnloadPriority(pitl,
+                                GetMaximalPriorityWithoutLocking()+1);
+           return pitl->GetImage();
+         }
+
+       /*      
+       mRequestedFilename = filename;
+       mRequestedImage = 0;
+       ImageToLoad itl(this,filename);
+       ImageMapType::iterator i = mImages.find(&itl);
+       if (i!=mImages.end())
+         {
+           // Already inserted in queue
+           if (i->first->GetImage() != 0)
+             {
+               // Already read : ok : return it 
+               return i->first->GetImage();
+             }
+           /// Already requested : change the priority
+             ImageToLoadPtr pitl = const_cast<ImageToLoadPtr>(i->first);
+             pitl->SetPriority( GetMaximalPriorityWithoutLocking() + 1 );
+             pitl->SetUser( this );
+             // Already in queue
+             if (pitl->Index()>=0) 
+               {
+                 // Re-sort the queue
+                 mQueue.upsort(pitl->Index());
+               }
+             // Not read but not in queue = being read = ok
+             else 
+               {
+                 pitl->SetUser( this );
+               }
+         }
+       else 
+         {
+           
+           // Never requested before or unloaded 
+           ImageToLoadPtr pitl = 
+             new ImageToLoad(this,filename,
+                             GetMaximalPriorityWithoutLocking() + 1);
+           mImages[pitl] = 0;
+           mQueue.insert(pitl);
+         }
+       */
+      }
+    while (0);
+
+    //    std::cout << "Waiting..."<<std::endl;
+
+    /*
+    // Waiting that it is read
+    int n = 0;
+    do 
+      {
+       //      std::cout << n++ << std::endl;
+       wxMilliSleep(10);
+       do 
+         {
+           //      wxMutexLocker lock(mMutex);
+           wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
+           if (mRequestedImage!=0) 
+             {
+               return mRequestedImage;
+             } 
+         }
+       while (0);
+      }
+    while (true);
+    // 
+    */
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  void MultiThreadImageReader::SignalImageRead(ImageToLoadPtr p, 
+                                              bool purge)
+  {
+    
+//    std::cout << "MultiThreadImageReader::SignalImageRead" <<std::endl;
+    //    std::cout << "this="<<this <<std::endl;
+    //    std::cout << "user="<<p->GetUser() <<std::endl;
+
+    if ( p->GetUser() == this ) 
+      GetMultiThreadImageReaderUserMutex().Unlock();
+
+    p->GetUser()->MultiThreadImageReaderSendEvent
+      (p->GetFilename(),
+       MultiThreadImageReaderUser::ImageLoaded,
+       p->GetImage());
+
+    /*
+      AN ATTEMPT TO UNLOAD OLDEST IMAGE IF EXCEEDED A CERTAIN MEMORY QUOTA
+      BUGGY : TO FIX 
+    */
+    if (!purge)  return;
+    GimmickMessage(5,"Image '"<<p->GetFilename()<<"' read"<<std::endl);
+
+    //    wxMutexLocker lock(GetMultiThreadImageReaderUserMutex());
+          
+    mUnloadQueue.insert(p);
+    p->GetImage()->UpdateInformation();
+    p->GetImage()->PropagateUpdateExtent();
+    long ImMem = p->GetImage()->GetEstimatedMemorySize();
+    mTotalMem += ImMem;
+
+    GimmickMessage(5,"==> Image in memory = "<<mUnloadQueue.size()<<std::endl);
+    GimmickMessage(5,"==> Total mem       = "<<mTotalMem<<" Ko"<<std::endl);
+
+    //  return;
+
+    while (mTotalMem > mTotalMemMax)
+      {
+       GimmickMessage(5,
+                      "   ! Exceeded max of "
+                      << mTotalMemMax << " Ko : unloading oldest image ... "
+                      << std::endl);
+       if ( mUnloadQueue.size() <= 1 ) 
+         {
+            GimmickMessage(5,
+                           "   Only one image : cannot load AND unload it !!"
+                           <<std::endl);
+           break; 
+           
+         }
+       ImageToLoadPtr unload = mUnloadQueue.remove_top();
+       MultiThreadImageReaderUser* user = unload->GetUser();
+
+       /*
+       if ((user!=0)&&(user!=this)) 
+         {
+           user->GetMultiThreadImageReaderUserMutex().Lock();
+         }
+       */
+
+       std::string filename = unload->GetFilename();
+
+       GimmickMessage(5,"'" << filename << "'" << std::endl);
+       mTotalMem -= unload->GetImage()->GetEstimatedMemorySize();
+
+       GimmickMessage(5," ==> Total mem = "<<mTotalMem<<" Ko "<<std::endl);
+
+       if (user!=0) 
+         {
+           //      std::cout << "unlock..."<<std::endl;
+           //   user->GetMultiThreadImageReaderUserMutex().Unlock();
+           //      std::cout << "event"<<std::endl;
+           user->MultiThreadImageReaderSendEvent
+             (filename,
+              MultiThreadImageReaderUser::ImageUnloaded,
+              0);
+           //      std::cout << "event ok"<<std::endl;
+         }     
+
+       if (unload->Index()>=0)
+         {
+           // GimmickMessage(5,"still in queue"<<std::endl);
+         }
+       unload->Index() = -1;
+
+
+       ImageMapType::iterator it = mImages.find(unload);
+       if (it!=mImages.end())
+         {
+           mImages.erase(it);
+         }
+       //          std::cout << "delete..."<<std::endl;
+       delete unload;
+       //          std::cout << "delete ok."<<std::endl;
+
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  int MultiThreadImageReader::GetMaximalPriority()
+  { 
+    wxMutexLocker lock(GetMultiThreadImageReaderUserMutex()); //mMutex);
+    return GetMaximalPriorityWithoutLocking();
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  int MultiThreadImageReader::GetMaximalPriorityWithoutLocking()
+  { 
+    long max = 0;
+    if (mQueue.size()>0) 
+      {
+       max = mQueue.top()->GetPriority();
+      }
+    if (mUnloadQueue.size()>0)
+      {
+       int max2 = mUnloadQueue.top()->GetPriority();
+       if (max2>max) max=max2;
+      }
+    return max;
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  //=====================================================================
+  //=====================================================================
+  //=====================================================================
+
+  //=====================================================================
+  void*  ThreadedImageReader::Entry()
+  {
+    //    std::cout << "### Thread "<<GetCurrentId()<<"::Entry()"
+    //               << std::endl;
+
+    mMultiThreadImageReader->MultiThreadImageReaderSendEvent
+      ("",
+       MultiThreadImageReaderUser::ThreadedReaderStarted,
+       0);
+
+    // While was not deleted 
+    while (!TestDestroy())
+      {
+               //std::cout << "### Thread "<<GetCurrentId()<<" still alive"  << std::endl;
+         
+       // Lock the mutex
+       mMultiThreadImageReader->MultiThreadImageReaderEventLock();
+       //mMutex.Lock();
+       // If image in queue
+       if (mMultiThreadImageReader->mQueue.size()>0)
+         {
+           MultiThreadImageReader::ImageToLoadPtr i = 
+             mMultiThreadImageReader->mQueue.remove_top();
+
+           mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
+           //mMutex.Unlock();
+
+           
+           //      std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
+           //                << i->GetFilename() << "'" << std::endl;
+           
+           // Do the job
+           vtkImageData* im = Read(i->GetFilename());
+
+           // Store it in the map
+           mMultiThreadImageReader->MultiThreadImageReaderEventLock();
+           //mMutex.Lock();
+           MultiThreadImageReader::ImageToLoad itl(0,i->GetFilename());
+           MultiThreadImageReader::ImageMapType::iterator it = 
+             mMultiThreadImageReader->mImages.find(&itl);
+           MultiThreadImageReader::ImageToLoadPtr 
+             pitl = const_cast<MultiThreadImageReader::ImageToLoadPtr>
+             (it->first);
+           pitl->SetImage(im);
+           mMultiThreadImageReader->SignalImageRead(pitl,true);//i->GetFilename());
+           mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();           //mMutex.Unlock();
+           
+           //      std::cout << "### Thread "<<GetCurrentId()<<" : reading '"
+           //                << i->GetFilename() << "' : DONE" << std::endl;
+           
+         }
+       else 
+         {
+           mMultiThreadImageReader->MultiThreadImageReaderEventUnlock();
+           //mMutex.Unlock();
+           // Wait a little to avoid blocking 
+           Sleep(10);
+         }
+      };
+    //    std::cout << "### Thread "<<GetCurrentId()<<" stopping"
+    //               << std::endl;
+       
+    return 0;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void ThreadedImageReader::OnExit()
+  {
+    mMultiThreadImageReader->MultiThreadImageReaderSendEvent
+      ("",
+       MultiThreadImageReaderUser::ThreadedReaderStopped,
+       0);
+  }
+  //=====================================================================
+
+  //=====================================================================
+  vtkImageData* ThreadedImageReader::Read(const std::string& filename)
+  {
+    return mReader.ReadImage(filename);
+  }
+  //=====================================================================
+
+} // namespace creaImageIO
diff --git a/src/creaImageIOMultiThreadImageReader.h b/src/creaImageIOMultiThreadImageReader.h
new file mode 100644 (file)
index 0000000..c5a9ef9
--- /dev/null
@@ -0,0 +1,254 @@
+#ifndef __creaImageIOThreadedImageReader_h_INCLUDED__
+#define __creaImageIOThreadedImageReader_h_INCLUDED__
+
+#include <creaImageIOSystem.h>
+#include <creaImageIOImageReader.h>
+#include <creaImageIOIndexedHeap.h>
+#include <map>
+#include <deque>
+#include <wx/thread.h>
+#include <queue>
+
+
+
+namespace creaImageIO
+{
+       /**
+       * \ingroup IO
+       */
+  //=====================================================================
+  class ThreadedImageReader;
+  class MultiThreadImageReader;
+  //=====================================================================
+  
+  //=====================================================================
+  class CREAIMAGEIO_EXPORT MultiThreadImageReaderUser
+  {
+  public:
+    friend class ThreadedImageReader;
+    friend class MultiThreadImageReader;
+
+    MultiThreadImageReaderUser() {}
+    virtual ~MultiThreadImageReaderUser() {}
+
+    typedef enum 
+      {
+       ThreadedReaderStarted,
+       ThreadedReaderStopped,
+       ImageLoaded,
+       ImageUnloaded,
+       Error
+      }
+      EventType;
+    /// The virtual method to overload by MultiThreadImageReader users
+      /// It is called when an image has been loaded or unloaded 
+      /// Provides :
+      /// * The image file name which was requested 
+      /// * The type of event 
+      /// * If type==ImageLoaded the image pointer, else NULL pointer 
+    virtual void OnMultiThreadImageReaderEvent( const std::string& filename,
+                                               EventType type,
+                                               vtkImageData* image) 
+    {}
+    inline void MultiThreadImageReaderEventLock() 
+    { mMultiThreadImageReaderUserMutex.Lock(); }
+    inline void MultiThreadImageReaderEventUnlock() 
+    { mMultiThreadImageReaderUserMutex.Unlock(); }
+    inline wxMutex& GetMultiThreadImageReaderUserMutex() 
+    { return mMultiThreadImageReaderUserMutex; }
+  private:
+    /// 
+    void MultiThreadImageReaderSendEvent( const std::string& filename,
+                                         EventType type,
+                                         vtkImageData* image);
+    wxMutex mMultiThreadImageReaderUserMutex;
+  };
+  //=====================================================================
+
+  //=====================================================================
+  /// 
+  /// TAKE CARE : For the moment it only supports a **SINGLE USER** 
+
+   ///Class that allows parallel lectures of several images
+  class MultiThreadImageReader : public MultiThreadImageReaderUser
+  {
+  public:
+    friend class ThreadedImageReader;
+
+    /// Ctor with the number of threads to use
+    MultiThreadImageReader(int number_of_threads = 1);
+    /// Dtor 
+    ~MultiThreadImageReader();
+
+    /// Starts the reader = create the threads which start to check 
+    /// periodically the queue of requested images to read
+    bool Start();
+    /// Stops the reader = stops the threads and delete the images loaded
+    void Stop();
+
+    /// Request the image "filename" with a given priority 
+    /// When the image is ready (or an error occurred) 
+    /// The observer's callback is invoked 
+    void Request( MultiThreadImageReaderUser* user,
+                 const std::string& filename, 
+                 int priority );
+    
+    /// Request the image "filename" immediately 
+       /// Blocks until image loaded
+    /// (no user callback but image returned)
+    vtkImageData* GetImage(const std::string& filename);
+
+    /// 
+    int GetMaximalPriority(); 
+    
+    ///
+    void OnMultiThreadImageReaderEvent( const std::string& filename,
+                                       EventType type,
+                                       vtkImageData* image);
+    
+  protected:
+         bool mDone;
+    int GetMaximalPriorityWithoutLocking();
+    ///Class that represents an image to be loaded
+    class ImageToLoad
+    {
+    public:
+      ImageToLoad( MultiThreadImageReaderUser* user,
+                  const std::string& filename, 
+                  int prio=0) 
+       : mUser(user),
+         mFilename(filename), 
+         mPriority(prio), 
+         mIndex(-1), 
+         mUnloadIndex(-1), 
+         mImage(0)
+      {}
+      ~ImageToLoad()
+      {
+       if (mImage>0) 
+         {
+           //      std::cout << "Refs = "<<mImage->GetReferenceCount()<<std::endl;
+           mImage->Delete();
+         }
+      }
+      MultiThreadImageReaderUser* GetUser() const { return mUser; }
+      void SetUser( MultiThreadImageReaderUser* u ) { mUser = u; }
+      const std::string& GetFilename() const { return mFilename; }
+      int GetPriority() const { return mPriority; }
+      void SetPriority(int p) { mPriority=p; }
+      int& Index() { return mIndex; }
+      int& UnloadIndex() { return mUnloadIndex; }
+      vtkImageData* GetImage() const { return mImage; }
+      void SetImage( vtkImageData* i ) { mImage=i; }
+    private:
+      MultiThreadImageReaderUser* mUser;
+      std::string mFilename;
+      int mPriority;
+      int mIndex;
+      int mUnloadIndex;
+      vtkImageData* mImage;
+    };
+    // 
+
+    /// Type of pointer on an ImageToLoad struct
+    typedef ImageToLoad* ImageToLoadPtr;
+
+    /// ImageToLoadPtr comparator on priority (for image queue)
+    struct ImageToLoadPtrPriorityComparator
+    {
+      bool operator() (ImageToLoadPtr const & a, ImageToLoadPtr const & b)
+       const 
+      {
+       return ( a->GetPriority() > b->GetPriority() );
+      }
+    };
+    /// ImageToLoadPtr comparator on inverse priority (for image to unload queue)
+    struct ImageToLoadPtrInversePriorityComparator
+    {
+      bool operator() (ImageToLoadPtr const & a, ImageToLoadPtr const & b)
+       const 
+      {
+       return ( a->GetPriority() < b->GetPriority() );
+      }
+    };
+
+
+    /// ImageToLoadPtr comparator on filename (for image map)
+    struct ImageToLoadPtrFilenameComparator
+    {
+      bool operator() (ImageToLoadPtr const & a, ImageToLoadPtr const & b)
+       const 
+      {
+       return ( a->GetFilename() < b->GetFilename() );
+      }
+    };
+
+    /// ImageToLoadPtr indexer for image queue
+    struct ImageToLoadPtrIndexer
+    {
+      int& operator()(ImageToLoadPtr & t) const { return t->Index(); }
+    };
+    /// ImageToLoadPtr indexer for to unload image queue
+    struct ImageToUnloadPtrIndexer
+    {
+      int& operator()(ImageToLoadPtr & t) const { return t->UnloadIndex(); }
+    };
+
+    /// The callback from threaded readers when an image is read
+    void SignalImageRead(ImageToLoadPtr p, bool purge);
+  
+    /// The type of map of images 
+    typedef std::map<ImageToLoadPtr,vtkImageData*,
+                    ImageToLoadPtrFilenameComparator> ImageMapType;
+    /// The map of images
+    ImageMapType mImages;
+    /// Comparator for the image to load queue
+    ImageToLoadPtrPriorityComparator mComparator;
+    /// Indexer for the image to load queue 
+    ImageToLoadPtrIndexer mIndexer;
+    /// The image to load priority queue
+    IndexedHeap<ImageToLoadPtr,
+               ImageToLoadPtrPriorityComparator,
+               ImageToLoadPtrIndexer> mQueue;
+
+    /// The type of list of threaded readers
+       typedef std::vector<boost::shared_ptr<ThreadedImageReader> > ThreadedImageReaderListType;
+       //typedef std::vector<ThreadedImageReader* > ThreadedImageReaderListType;
+    ThreadedImageReaderListType mThreadedImageReaderList;
+    /// The number of currently running threaded readers
+    int mNumberOfThreadedReadersRunning;
+    /// The mutex used to access safely internal data from any thread
+    /// LG : Removed ! We now use the embedded mutex in User from which 
+    /// we inherit...
+    //  wxMutex mMutex;
+
+    /// For GetImage : the filename requested
+    std::string mRequestedFilename;
+    /// For GetImage : the image requested
+    vtkImageData* mRequestedImage;
+
+    /// If number of threads == 0 then uses an internal non-threaded reader
+    ImageReader* mReader;
+
+    /// The type of list of images loaded 
+    /// used to unload oldest image when memory limit exceeded
+   /// The image to unload priority queue
+    IndexedHeap<ImageToLoadPtr,
+               ImageToLoadPtrInversePriorityComparator,
+               ImageToUnloadPtrIndexer> mUnloadQueue;
+
+    void UpdateUnloadPriority(ImageToLoadPtr p, int priority);
+    long mTotalMem;
+    long mTotalMemMax;
+
+
+  }; // class MultiThreadImageReader
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIOThreadedImageReader_h_INCLUDED__
diff --git a/src/creaImageIOPACSConnection.cpp b/src/creaImageIOPACSConnection.cpp
new file mode 100644 (file)
index 0000000..ffa6571
--- /dev/null
@@ -0,0 +1,49 @@
+
+#include <creaImageIOPACSConnection.h>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+//#include <boost/asio.hpp>
+
+//using boost::asio::ip::tcp;
+
+enum { max_length = 3086 };
+using namespace std; 
+namespace creaImageIO
+{
+       PACSConnection::PACSConnection(std::string command)
+       {
+       /*
+       try
+       {
+
+               boost::asio::io_service io_service;
+
+               tcp::resolver resolver(io_service);
+               tcp::resolver::query query(tcp::v4(), "localhost", "3306");
+               tcp::resolver::iterator iterator = resolver.resolve(query);
+
+               tcp::socket s(io_service);
+               s.connect(*iterator);
+
+               size_t request_length = strlen(command.c_str());
+               boost::asio::write(s, boost::asio::buffer(command.c_str(), request_length));
+
+               char reply[max_length];
+               size_t reply_length = boost::asio::read(s,
+                       boost::asio::buffer(reply, request_length));
+               std::cout << "Reply is: ";
+               std::cout.write(reply, reply_length);
+               std::cout << "\n";
+       }
+       catch (std::exception& e)
+       {
+               std::cerr << "Exception: " << e.what() << "\n";
+       }
+       */
+       }
+       
+}
+
+
+
diff --git a/src/creaImageIOPACSConnection.h b/src/creaImageIOPACSConnection.h
new file mode 100644 (file)
index 0000000..02e659a
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __creaImageIOPACSConnection_h_INCLUDED__
+#define __creaImageIOPACSConnection_h_INCLUDED__
+#include <string>
+
+namespace creaImageIO
+{
+class PACSConnection
+  {
+  public:
+    /// Ctor
+         PACSConnection(std::string command);
+  };// EO PACSConnection
+} // EO namespace creaImageIO
+
+// EOF
+#endif
+
diff --git a/src/creaImageIOSQLiteTreeHandler.cpp b/src/creaImageIOSQLiteTreeHandler.cpp
new file mode 100644 (file)
index 0000000..627db08
--- /dev/null
@@ -0,0 +1,1017 @@
+#include <creaImageIOSQLiteTreeHandler.h>
+#include <creaImageIOSystem.h>
+#include <creaImageIOGimmick.h>
+#include <creaImageIOTree.h>
+
+#include "CppSQLite3.h"
+
+#include <sys/stat.h>
+
+#include <deque>
+
+#include <creaWx.h>
+#include <boost/algorithm/string.hpp>
+using namespace crea;
+
+
+
+namespace creaImageIO
+{
+  using namespace tree;
+
+
+  //=============================================================
+  SQLiteTreeHandler::SQLiteTreeHandler(const std::string& filename)
+    : mFileName(filename)
+  {
+    mDB = new CppSQLite3DB;
+       mIsAdding=false;
+    //GimmickMessage(1,"SQLite version : "                <<std::string(mDB->SQLiteVersion())<< std::endl);
+  }
+  //=============================================================
+
+  //=============================================================
+  SQLiteTreeHandler::~SQLiteTreeHandler()
+  {
+    delete mDB;
+  }
+  //=============================================================
+  
+
+  //=====================================================================
+
+
+  //=====================================================================
+  bool SQLiteTreeHandler::Open(bool writable)
+  {
+    //    std::cout << "***> SQLiteTreeHandler::Open('"<<GetFileName()<<"')"<<std::endl;
+    SetWritable(writable);
+    return DBOpen();
+  }
+
+  //=====================================================================
+  bool SQLiteTreeHandler::Create(bool writable)
+  {
+    //    std::cout << "***> SQLiteTreeHandler::New('"<<GetFileName()<<"')"<<std::endl;
+    SetWritable(writable);
+    return DBCreate();
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  bool SQLiteTreeHandler::Close()
+  {
+    return true;
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  bool SQLiteTreeHandler::Destroy()
+  {
+    return false;
+  }
+  
+  //===================================================================== 
+
+  //===================================================================== 
+  int SQLiteTreeHandler::LoadChildren(tree::Node* parent, int maxlevel)
+  {
+    if (parent==0) parent = GetTree().GetTree();
+    return DBLoadChildren(parent,maxlevel);
+  }
+  //===================================================================== 
+
+
+
+
+  //===================================================================== 
+  void SQLiteTreeHandler::UnLoad(tree::Node* n)
+  {
+  }
+  //===================================================================== 
+
+  //===================================================================== 
+  int SQLiteTreeHandler::AddBranch( const AttributeMapType& attr )
+  {
+    tree::Node* parent = DBGetParent(attr);
+    DBGraftToParent(parent,attr);
+    return (parent->GetLevel()+1);
+         
+  }
+  //===================================================================== 
+
+  //===================================================================== 
+   bool SQLiteTreeHandler::Remove(tree::Node* node)
+   {
+   DBRecursiveRemoveNode(node);
+    //    std::cout << "DELETE"<<std::endl;
+   bool remove=false;
+   tree::Node* parent=node->GetParent();
+    if (parent)
+      {
+       int nC = parent->RemoveChildrenFromList(node);
+       if(nC>0 && parent->GetLevel()>0)
+       {       
+               std::stringstream out;
+               out <<nC;
+               SetAttribute(parent,"NumberOfChildren",out.str());
+       }
+       else
+       {
+               remove=true;
+       }
+
+      }
+    delete node;
+       if(remove&&parent->GetLevel()>0)
+       {
+               Remove(parent);
+       }
+    //    std::cout << "DELETE OK"<<std::endl;
+    return true;
+   }
+  
+  //===================================================================== 
+
+  //===================================================================== 
+  /// Sets an attribute of a Node
+  bool SQLiteTreeHandler::SetAttribute(tree::Node* n, 
+                                      const std::string& key,
+                                      const std::string& value)
+  {
+    if (n==0) n=GetTree().GetTree();
+    return DBSetAttribute(n,key,value);
+  }
+  //===================================================================== 
+   //===================================================================== 
+  /// Sets an attribute
+  void SQLiteTreeHandler::SetAttribute(const std::string& levelDescriptor, 
+                             const std::string& key,
+                             const std::string& value,
+                                 const std::string& searchParam, 
+                                 const std::string& searchVal)
+  {
+       DBSetAttribute(levelDescriptor,key,value,searchParam, searchVal);
+  }
+  //===================================================================== 
+  /// Deletes a tuple
+  void SQLiteTreeHandler::DeleteTuple(std::string levelDescriptor, 
+                                                               std::string key, std::string value)
+  {
+    DBDelete(levelDescriptor,key,value);
+  }
+  //===================================================================== 
+
+
+
+
+
+
+
+
+
+
+
+
+
+  //=====================================================================
+  // SQLite DB specific methods
+  //=====================================================================
+
+
+
+
+  //=====================================================================
+  char* format_sql(const std::string& s)
+  { 
+    return sqlite3_mprintf("%q",s.c_str());
+  }
+  //=====================================================================
+
+  
+  //=====================================================================
+#define QUERYDB(QUER,RES)                                              \
+    try                                                                        \
+      {                                                                        \
+       GimmickMessage(2,"SQL query: '"<<QUER<<"'"<<std::endl);         \
+       RES = mDB->execQuery(QUER.c_str());                             \
+      }                                                                        \
+    catch (CppSQLite3Exception& e)                                     \
+      {                                                                        \
+       GimmickError("SQLite query '"<<QUER<<"' : "                     \
+                    << e.errorCode() << ":"                            \
+                    << e.errorMessage() );                             \
+      }                                                                        \
+    
+  //=====================================================================
+  
+  //=====================================================================
+#define UPDATEDB(UP)                                                   \
+  try                                                                  \
+    {                                                                  \
+      GimmickMessage(2,"SQL update: '"<<UP<<"'"<<std::endl);           \
+      mDB->execDML(UP.c_str());                                                \
+    }                                                                  \
+  catch (CppSQLite3Exception& e)                                       \
+    {                                                                  \
+      GimmickError("SQLite update '"<<UP<<"' Error : "                 \
+                  << e.errorCode() << ":"                              \
+                  << e.errorMessage() );                               \
+    }                                                                  
+  //=====================================================================
+
+
+  //=====================================================================
+  bool SQLiteTreeHandler::DBOpen()
+  {
+    GimmickMessage(1,"Opening SQLite database '"<<GetFileName()
+                  <<"' ... "<<std::endl);
+    // OPENING FILE
+    if (!boost::filesystem::exists(GetFileName())) 
+      {
+       return false;
+      }
+
+    try
+      {
+       mDB->open(GetFileName().c_str());
+      }
+    catch (CppSQLite3Exception& e)
+      {
+       GimmickError("Opening '"<<GetFileName()<<"' : "
+                    << e.errorCode() << ":" 
+                    << e.errorMessage());
+       return false;
+      }
+    // IMPORT TREE DESCRIPTION (AND TEST DB VALIDITY)
+    if (!DBImportTreeDescription())
+      {
+       return false;
+      }
+
+    GimmickDebugMessage(1,"Opening SQLite database '"<<GetFileName()
+                  <<"' ... OK"<<std::endl);
+    return true;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  bool SQLiteTreeHandler::DBCreate()
+  {
+    GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
+                  <<"' ... "<<std::endl);
+
+    if (boost::filesystem::exists(GetFileName())) 
+      {
+       GimmickError(GetFileName()<<"' : "
+                    << "file already exists");
+       return false;
+      }
+    
+    // OPENING
+    try
+      {
+       mDB->open(GetFileName().c_str());
+      }
+    catch (CppSQLite3Exception& e)
+      {
+       GimmickError(e.errorCode() << ":" 
+                    << e.errorMessage() <<std::endl);
+       return false;
+      }
+    
+     
+    // CREATING TABLES
+    
+    std::string command;
+    // Create LEVELS table
+    command = "create table LEVELS\n";
+    command += "( Name text )\n";
+    UPDATEDB(command);
+    int l;
+    // Iterate the Levels
+    for (l=0; l<GetTree().GetNumberOfLevels(); l++)
+      {
+       command = "INSERT INTO LEVELS (Name) VALUES ('";
+       command += GetTree().GetLevelDescriptor(l).GetName();
+       command += "')";
+       UPDATEDB(command);
+       
+       // Create table of level (for level>0, i.e. not Root)
+       if (l>=0)
+         {
+           command = "CREATE TABLE ";
+           command += GetTree().GetLevelDescriptor(l).GetName();
+           command += "\n(\nID INTEGER PRIMARY KEY";
+           if (l>1) 
+             {
+               command += ",\nPARENT_ID int not null"; 
+             }
+           SQLAppendAttributesDefinition(l,command);
+           if (l>1) 
+             {
+               command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
+               command += GetTree().GetLevelDescriptor(l-1).GetName();
+               command += "(ID) on delete restrict on update restrict";
+             }
+           command += "\n)";
+           UPDATEDB(command);
+           
+           
+           // Add Attribute 'ID' to Description
+           GetTree().GetDescriptor().Add
+             (AttributeDescriptor( "ID",
+                                   "Database Identifier",
+                                   0,0,
+                                   AttributeDescriptor::PRIVATE
+                                   ),l);
+           
+           if (l>1) 
+             {
+               // Add Attribute 'PARENT_ID' to Description
+               GetTree().GetDescriptor().Add
+                 (AttributeDescriptor( "PARENT_ID",
+                                       "Database Parent Identifier",
+                                       0,0,
+                                       AttributeDescriptor::PRIVATE
+                                       ),l);
+             }
+           
+         }
+       
+       // Create table *_ATTRIBUTES
+       
+       command = "CREATE TABLE ";
+       command += GetTree().GetLevelDescriptor(l).GetName();
+       command += "_Attributes\n(\n";
+       command += "Key text,\n";
+       command += "Name text,\n";          
+       command += "DicomGroup int,\n";
+       command += "DicomElement int,\n";           
+       command += "Flags int\n";           
+       command += "\n)";
+       UPDATEDB(command);
+
+       // Fill the table *_ATTRIBUTES
+       LevelDescriptor::AttributeDescriptorListType::const_iterator i;
+       for (i  = GetTree().GetAttributeDescriptorList(l).begin();
+            i != GetTree().GetAttributeDescriptorList(l).end();
+            ++i)
+         {
+           
+           std::stringstream insert;
+           insert << "INSERT INTO "
+                  << GetTree().GetLevelDescriptor(l).GetName()
+                  << "_Attributes (Key,Name,DicomGroup,DicomElement,Flags) "
+                  << "VALUES ('"
+                  << i->GetKey() << "','"
+                  << i->GetName() << "',"
+                  << i->GetGroup() << ","
+                  << i->GetElement() << ","
+                  << i->GetFlags() << ");";
+           UPDATEDB(insert.str());
+         }
+
+      } // For l=0...
+
+    // Initialize the root attributes
+    GetTree().InitializeAttributeMap();
+    // Insert the root in the level 0 table 
+    DBInsert(GetTree().GetTree());
+    
+    
+    GetTree().SetChildrenLoaded(true);
+    GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
+                  <<"' ... OK"<<std::endl);
+    return true;
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  void SQLiteTreeHandler::SQLAppendAttributesDefinition(int level,
+                                                       std::string& s)
+  {
+    LevelDescriptor::AttributeDescriptorListType::const_iterator i;
+    for (i  = GetTree().GetAttributeDescriptorList(level).begin();
+        i != GetTree().GetAttributeDescriptorList(level).end();
+        ++i)
+      {
+       //      if (i->second.flags==1) continue;
+       s += ",\n";
+       s += i->GetKey();
+       s += " text";
+      }
+  }
+  //=====================================================================
+  
+  
+  //=====================================================================
+  bool SQLiteTreeHandler::DBImportTreeDescription()
+  {
+    GimmickMessage(1,"Importing tree description for database ..."
+                  <<std::endl);
+
+    // Test table 'LEVELS' existence
+    if ( ! mDB->tableExists("LEVELS") )
+      {
+       GimmickMessage(1,"!! ERROR : Table 'LEVELS' does not exist"
+                      <<std::endl);
+       return false;
+      }
+
+    tree::Descriptor& desc = GetTree().GetDescriptor();
+    // clears the existing one
+    desc.Clear();
+     
+    int nblevel = 0;
+    std::string query = "SELECT * FROM LEVELS";
+    CppSQLite3Query q;
+    QUERYDB(query,q);
+
+    while (!q.eof())
+      {
+       std::string name = q.getStringField(0);
+       GimmickMessage(2," * Importing level '"<<name<<"'"<<std::endl);
+       desc.Add(LevelDescriptor(name));
+       nblevel++;
+       q.nextRow();
+      }   
+    
+    for (int level = 0; level < nblevel; ++level )
+      {
+       std::string table = GetTree().GetLevelDescriptor(level).GetName();
+       table += "_Attributes";
+       // Test table 'LEVELS' existence
+       if ( ! mDB->tableExists(table.c_str()) )
+         {
+           GimmickMessage(1,"!! ERROR : Table '"<<table<<"' does not exist"
+                          <<std::endl);
+           return false;
+         }
+       
+       std::string query = "SELECT * FROM ";
+       query += table;
+       CppSQLite3Query q;
+       QUERYDB(query,q);
+       
+       GimmickMessage(2," * Level '"
+                      <<GetTree().GetLevelDescriptor(level).GetName()
+                      <<"'"<<std::endl);
+
+       // Test that ID and PARENT_ID mandatory attributes exist
+       bool ID_found = false;
+       bool PARENT_ID_found = false;
+       if (level==0) ID_found = true;
+       if (level<=1) PARENT_ID_found = true;
+
+       while (!q.eof())
+         {
+           std::string key(q.getStringField(0));
+           std::string name(q.getStringField(1));
+           GimmickMessage(2,"  - Importing attribute '"<<key<<"' '"<<name
+                          <<"'"<<std::endl);
+           desc.Add
+             (AttributeDescriptor( key, // Key
+                                   name, // Name
+                                   q.getIntField(2), // Group
+                                   q.getIntField(3), // Element 
+                                   q.getIntField(4) // Flags
+                                   ),level);
+           if ( key == "ID" ) 
+             {
+               ID_found = true;
+             }
+           if ( key == "PARENT_ID" ) 
+             {
+               PARENT_ID_found = true;
+             }
+           q.nextRow();
+         }
+       
+       if ( ! (ID_found || PARENT_ID_found ) )
+         {
+           GimmickMessage(1,"!! ERROR : Table '"<<table
+                          <<"' does not contain mandatory attribute ID or PARENT_ID"
+                          <<std::endl);
+           return false;
+         }
+      }
+
+       
+    // Create the attributes table for Root (i.e. Tree)
+    LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+    for (a = GetTree().GetAttributeDescriptorList(0).begin();
+        a!= GetTree().GetAttributeDescriptorList(0).end();
+        ++a)
+      {
+
+       GetTree().UnsafeSetAttribute( a->GetKey(), "" );
+      }
+
+    // Reading Root attributes
+    // Query DB
+    query = "SELECT * FROM ";
+    query += GetTree().GetLevelDescriptor(0).GetName();
+    QUERYDB(query,q);
+
+    for (int fld = 0; fld < q.numFields(); fld++)
+      {
+       GetTree().UnsafeSetAttribute(q.fieldName(fld),
+                                    q.getStringField(fld));        
+      }
+
+    GimmickMessage(1,"Importing tree description from database ... OK"
+                  <<std::endl);
+    return true;
+  }
+  //=====================================================================
+
+  //========================================================================
+  /// 
+  void SQLformat(std::string i_str, std::string &o_str)
+  {
+               // quote must be doubled
+               boost::algorithm::replace_all(i_str,"'","''");
+               // Found strange strings which contained NULL char INSIDE string 
+               int i,size=i_str.size();
+               for (i=0;i<size;++i) 
+               {
+                       if (i_str[i]==0) 
+                       {
+                               i_str = i_str.substr(0,i);
+                               break;
+                         }
+               }
+               o_str = i_str;
+  }
+  //========================================================================
+  
+  //=====================================================================
+  void SQLiteTreeHandler::SQLAppendAttributesValues(tree::Node* n, 
+                                                   std::string& str)
+  {
+    GimmickMessage(4,"SQLAppendAttributesValues"<<std::endl);
+    std::string atts="";
+    std::string values="";
+       std::string out ="";
+    tree::Node::AttributeMapType::iterator i;
+    for (i =  n->GetAttributeMap().begin();
+        i != n->GetAttributeMap().end();
+        i++)
+      {
+       if (i->first=="ID") 
+         {
+           continue;
+         }
+
+       atts += "'" + i->first + "'";
+       SQLformat(i->second, out);
+       values += "'" + out + "'"; 
+       atts += ",";
+       values += ",";
+       GimmickMessage(4,"'"<<i->first<<"' = '"<<i->second<<"'"<<std::endl);
+      }
+    atts[atts.size()-1]=' ';
+    values[values.size()-1]=' ';
+
+    str = "("+atts+") VALUES ("+values+")";
+    GimmickMessage(4,"Result = '"<<str<<"'"<<std::endl);
+  }
+  //=====================================================================
+
+  //=====================================================================
+  tree::Node* SQLiteTreeHandler::DBGetParent( const AttributeMapType& attr) 
+  {
+    Node* parent = GetTree().GetTree();
+    bool go_down;
+    do 
+      {
+       go_down = false;
+       // Load the children of the current parent
+       DBLoadChildren(parent);
+       // Iterate the children 
+       tree::Node::ChildrenListType::const_iterator i;
+       for (i = parent->GetChildrenList().begin();
+            i!= parent->GetChildrenList().end();
+            ++i)
+         {
+           if ( (*i)->Matches( attr ) ) 
+             {
+               go_down = true;
+               parent = *i;
+               break;
+             }
+         }     
+      }
+    while (go_down);
+    return parent;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  int SQLiteTreeHandler::DBLoadChildren(tree::Node* node, 
+                                       int numberoflevels)
+  {
+    if (node->GetLevel()+1 >= node->GetTree()->GetNumberOfLevels() ) 
+      return 0;
+
+    GimmickMessage(2,"Loading children of '"<<node->GetLabel()
+                  <<"'"<<std::endl);
+
+    int nbloaded = 0;
+    // If children loaded we do not have to do it but we need to recurse
+    // in order to load the children's children if necessary, and so on...
+    if (node->GetChildrenLoaded()) 
+      {
+       // Iterate the children 
+
+       tree::Node::ChildrenListType::iterator i;
+       for (i = node->GetChildrenList().begin();
+            i!= node->GetChildrenList().end();
+            ++i)
+         {
+           nbloaded += DBLoadChildren(*i,numberoflevels-1);
+         }
+       node->SetChildrenLoaded(true);
+       return nbloaded;
+
+      }
+       else
+       {
+    /// If children not loaded : do it and recurse
+
+    // Query DB
+    int level = node->GetLevel();
+    std::string query = "SELECT * FROM ";
+       
+    query += GetTree().GetLevelDescriptor(level+1).GetName();
+    if (level>0)
+      {
+       query += " WHERE PARENT_ID='" + node->GetAttribute("ID") 
+         + "'";
+      }
+GimmickDebugMessage(1,                                 "query : '"                         <<query                                         <<std::endl);
+    CppSQLite3Query q;
+    QUERYDB(query,q);
+
+       int p=0;
+    while (!q.eof())
+      {
+
+       //      std::cout << "DBLoadCh : creating node level "<<level+1<<std::endl;
+
+       nbloaded++;
+       Node* n = new Node(node);
+       for (int fld = 0; fld < q.numFields(); fld++)
+         {
+           n->UnsafeSetAttribute(q.fieldName(fld),q.getStringField(fld));          
+         }
+
+       // recurse 
+       if ( numberoflevels != 1 ) 
+         {
+           //  msw[2].Pause();
+           nbloaded += DBLoadChildren(n, numberoflevels-1);
+           //      msw[2].Resume();
+         }
+       // next entry in db
+       q.nextRow();
+      }
+
+    node->SetChildrenLoaded(true);
+       
+    
+    //    msw[2].Pause();
+    return nbloaded;
+       }
+  }
+  //=====================================================================
+
+  //======================================================================
+  void SQLiteTreeHandler::DBInsert(tree::Node* n)
+  {
+    GimmickMessage(2,"Inserting in DB '"<<n->GetLabel()
+                  <<"'"<<std::endl);
+    std::string val;
+    SQLAppendAttributesValues(n,val);
+    std::string insert("INSERT INTO ");
+    insert += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
+    insert += " " + val + ";";
+
+    UPDATEDB(insert);
+       
+    // Store DB id of newly created node;
+    long lastrow = mDB->lastRowId();
+    std::stringstream ri;
+    ri << mDB->lastRowId();
+    n->SetAttribute("ID",ri.str());
+  }
+  //======================================================================
+
+  //======================================================================
+  /// Graft the branch defined by the attributes to the parent
+  void SQLiteTreeHandler::DBGraftToParent( tree::Node* parent, 
+                                           const AttributeMapType& attr)
+  {
+    //    std::cout <<"Grafting to parent '"<<parent->GetLabel()
+    //            <<"'"<<std::endl;
+
+    for (int level = parent->GetLevel()+1;
+        level < GetTree().GetNumberOfLevels();
+        level++)
+      {
+       // Create Node
+       tree::Node* child = new tree::Node(parent,attr);
+       child->SetChildrenLoaded(true);
+       if (level>1)
+         {
+           int nc = GetNumberOfChildren(parent)+1;
+           
+           //  std::cout<<"Number of children "<<parent->GetNumberOfChildren()<<std::endl;
+           std::stringstream out;
+           out << nc;
+           SetAttribute(parent,"NumberOfChildren",out.str());
+         }
+
+       // Set PARENT_ID if necessary 
+       if ( parent->GetLevel()>0 )
+         child->SetAttribute("PARENT_ID",parent->GetAttribute("ID"));
+       
+       // Insert in DB
+       DBInsert(child);
+       
+       // Down one level
+       parent = child;
+         }
+  }
+  //======================================================================
+
+
+  //===================================================================== 
+  /// Sets an attribute of a Node
+  bool SQLiteTreeHandler::DBSetAttribute(tree::Node* n, 
+                                        const std::string& key,
+                                        const std::string& value)
+  {
+    GimmickMessage(3,"Setting Attribute of '"<<n->GetLabel()<<
+                  "' "<<key<<"='"<<value<<"'"<<std::endl);
+
+    n->SetAttribute(key,value);
+    std::string sql = "UPDATE ";
+    sql += GetTree().GetLevelDescriptor(n->GetLevel()).GetName();
+    sql += " SET ";
+    sql += key;
+    sql += " = '";
+    sql += value;
+    sql += "' WHERE ID = '";
+    sql += n->GetAttribute("ID");
+       sql +="'";
+    //    sql += " LIMIT 1";
+    UPDATEDB(sql);
+       return true;
+  }
+
+  //===================================================================== 
+  /// Sets an attribute of a Node
+  void SQLiteTreeHandler::DBSetAttribute(const std::string& levelDescriptor, 
+                             const std::string& key,
+                             const std::string& value,
+                                 const std::string& searchParam, 
+                                 const std::string& searchVal)
+  {
+
+    std::string sql = "UPDATE ";
+    sql += levelDescriptor;
+    sql += " SET ";
+    sql += key;
+    sql += " = '";
+    sql += value;
+    sql += "' WHERE ";
+       sql += searchParam;
+       sql += " = '";
+    sql += searchVal;
+       sql += "'";
+       std::cout<<sql<<std::endl;
+    UPDATEDB(sql);
+  }
+   //=====================================================================
+  void SQLiteTreeHandler::DBRecursiveRemoveNode(Node* node)
+  {
+       
+    std::string query = "DELETE FROM ";
+   
+
+       query += GetTree().GetLevelDescriptor(node->GetLevel()).GetName();
+       
+    query += " WHERE ID='"+ node->GetAttribute("ID") + "';";
+    UPDATEDB(query);
+       GimmickDebugMessage(2,
+                           " Deleting '"
+                               <<node->GetLabel()<<"' with ID '"
+                           <<node->GetAttribute("ID")
+                           <<"' in level "<< GetTree().GetLevelDescriptor(node->GetLevel()).GetName()
+                           <<std::endl);
+
+
+       if(node->GetNumberOfChildren()!=0)
+       {
+               Node::ChildrenListType::iterator i;
+               for (i  = node->GetChildrenList().begin();
+               i != node->GetChildrenList().end();
+               i++)
+               {
+               DBRecursiveRemoveNode((*i));
+               }
+       }
+       else if(node->GetLevel()<GetTree().GetNumberOfLevels()-1)
+       {
+               DBRecursiveRemoveNode(node->GetLevel()+1,node->GetAttribute("ID"));
+    }
+  }
+
+  //=====================================================================
+  void SQLiteTreeHandler::DBRecursiveRemoveNode(int level, std::string parentId)
+  {
+    std::stringstream out;
+       std::stringstream result;
+       out<<"SELECT ID FROM "<<GetTree().GetLevelDescriptor(level).GetName()<<" WHERE PARENT_ID='"<<parentId<<"'";
+               
+       CppSQLite3Query q;
+       QUERYDB(out.str(),q);
+       
+       while (!q.eof())
+         {
+           for (int fld = 0; fld < q.numFields(); fld++)
+             {
+                         result<<q.getStringField(fld)<<"#";
+             }
+           q.nextRow();
+         }
+         std::string res=result.str();
+         size_t ini=0;
+         size_t fin=0;
+         while(fin<res.size()-1)
+         {
+          fin=res.find('#',ini);
+          DBDelete(GetTree().GetLevelDescriptor(level).GetName(),"ID",res.substr(ini,fin-ini));
+         if(level<GetTree().GetNumberOfLevels()-1)
+         {
+               DBRecursiveRemoveNode(level+1,res.substr(ini,fin-ini));
+         } 
+          ini=fin+1;
+         }
+         
+    
+  }
+
+  //=====================================================================
+  void SQLiteTreeHandler::DBDelete(std::string levelDescriptor, std::string key, std::string value)
+  {
+       
+    std::stringstream query;
+       query<<"DELETE FROM "<<levelDescriptor<<" WHERE "<<key<<"='"<<value<<"';";
+    UPDATEDB(query.str());
+       GimmickDebugMessage(2," Deleting: Query: "<<query.str()<<std::endl);
+  }
+
+
+  //===================================================================== 
+  void SQLiteTreeHandler::GetAttribute(std::string levelDescriptor,
+                                                                          std::string searchParam, 
+                                                                          std::string searchVal, 
+                                                                          std::string key, 
+                                                                          std::string& result) 
+  { 
+       std::stringstream out;
+       std::stringstream results;
+       out<<"SELECT "<<key<<" FROM "<<levelDescriptor;
+       if(searchParam!="")
+       {
+               out<<" WHERE "<<searchParam<<"='"<<searchVal<<"'";
+       }
+       
+       CppSQLite3Query q;
+       QUERYDB(out.str(),q);
+       
+       
+       while (!q.eof())
+         {
+           for (int fld = 0; fld < q.numFields(); fld++)
+             {
+                         results<<q.getStringField(fld);
+                         if(searchParam=="")
+                         {
+                                 results<<"#";
+                         }
+             }
+           q.nextRow();
+         }
+       result=results.str();
+      
+  }
+  //===================================================================== 
+  unsigned int SQLiteTreeHandler::GetNumberOfChildren(tree::Node* n) 
+  { 
+    // Query DB
+    int nb=0;
+    int level = n->GetLevel();
+
+    if(level<GetTree().GetNumberOfLevels()&& level>0)
+      {
+       std::string query = "SELECT NumberOfChildren FROM ";
+       query += GetTree().GetLevelDescriptor(level).GetName();
+       if (level>0)
+         {
+           query += " WHERE ID='" + n->GetAttribute("ID") 
+             + "'";
+         }
+       CppSQLite3Query q;
+       QUERYDB(query,q);
+       
+       
+       while (!q.eof())
+         {
+           for (int fld = 0; fld < q.numFields(); fld++)
+             {
+               nb=q.getIntField(fld);  
+             }
+           q.nextRow();
+         }
+      }
+    /*
+    if(nb==0)
+      { 
+       nb=1;
+      }
+    */
+    return nb; 
+  }
+
+  //===================================================================== 
+  void SQLiteTreeHandler::GetTopLevelNodeId(const std::string& searchParam, const std::string& searchValue, std::string& parent_id) 
+  {
+         int level=GetTree().GetNumberOfLevels()-1;
+         std::string sp=searchParam.c_str();
+         std::string sv=searchValue.c_str();
+
+         while(level>1)
+         {
+               std::stringstream out;
+               std::stringstream results;
+               out<<"SELECT PARENT_ID FROM "<<GetTree().GetLevelDescriptor(level).GetName();
+               out<<" WHERE "<<sp<<"='"<<sv<<"'";      
+               CppSQLite3Query q;
+               QUERYDB(out.str(),q);
+               
+               
+               while (!q.eof())
+               {
+                       for (int fld = 0; fld < q.numFields(); fld++)
+                       {
+                               results<<q.getStringField(fld);
+                       }
+                       q.nextRow();
+               }
+               level=level-1;
+               sp="ID";
+               sv=results.str();
+         }
+         parent_id=sv;
+
+  }
+
+  //=====================================================================
+  void SQLiteTreeHandler::RemoveEntries(const std::string i_table, 
+               const std::string i_attribute, 
+               const std::string i_operand, 
+               const std::string i_val)
+    {
+        std::stringstream query;
+               query<<"DELETE  FROM "<<i_table<<" WHERE "<<i_attribute<<" "<<i_operand<<" '"<<i_val<<"'";
+        UPDATEDB(query.str());
+       }
+
+       //=====================================================================
+  void SQLiteTreeHandler::BeginTransaction()
+    {
+               std::stringstream out;
+               out<<"begin transaction;";
+        UPDATEDB(out.str());
+       }
+
+       //=====================================================================
+  void SQLiteTreeHandler::EndTransaction()
+    {
+       std::stringstream out;
+               out<<"commit transaction;";
+        UPDATEDB(out.str());
+       }
+
+} // namespace creaImageIO
diff --git a/src/creaImageIOSQLiteTreeHandler.h b/src/creaImageIOSQLiteTreeHandler.h
new file mode 100644 (file)
index 0000000..1172298
--- /dev/null
@@ -0,0 +1,242 @@
+#ifndef __creaImageIOSQLiteTreeHandler_h_INCLUDED__
+#define __creaImageIOSQLiteTreeHandler_h_INCLUDED__
+
+#include <creaImageIOTreeHandler.h>
+
+class CppSQLite3DB;
+
+namespace creaImageIO
+{
+
+  
+  /**
+   * \ingroup Model
+   */
+  //=======================================================================
+  /// Concrete TreeHandler which manages a Tree stored in a sqlite database
+  class SQLiteTreeHandler : virtual public TreeHandler
+  {
+  public:
+    //====================================================================
+    /// Ctor with database file name 
+    SQLiteTreeHandler(const std::string& filename);
+    /// Dtor
+    virtual ~SQLiteTreeHandler();
+    //====================================================================
+
+    //====================================================================
+    /// Returns the sqlite db file name 
+    const std::string& GetFileName() const { return mFileName; }
+    //====================================================================
+    //====================================================================
+    // QUERY METHODS
+    /// Is the 'source' readable ?
+    virtual bool IsReadable() { return true; }
+    /// Is the 'source' writable ?
+    virtual bool IsWritable() { return true; }
+    //====================================================================
+
+
+    //====================================================================
+    // INITIALIZATION / FINALIZATION
+    //====================================================================
+
+    //====================================================================
+    /// Opens an existing 'source' 
+    // Default mode is read only 
+    // If IsWritable and writable==true then opens in read/write mode
+    virtual bool Open(bool writable = false);
+    /// Closes the 'source'
+    virtual bool Close();
+    /// Creates a new 'source' 
+    // Default mode is read only 
+    // If IsWritable and writable==true then opens in read/write mode
+    virtual bool Create(bool writable = false);
+    /// Destroys the 'source'
+    virtual bool Destroy();
+       /// Begins a transaction
+       virtual void BeginTransaction();
+       ///Commits results and ends transaction
+       virtual void EndTransaction();
+    //====================================================================
+
+
+    //====================================================================
+    // READ METHODS
+    //====================================================================
+
+
+    //====================================================================
+    /// Returns the number of children of the Node *WITHOUT LOADING THEM*
+    // REM : The Tree itself is a Node and asking for its number of 
+    //       children returns the number of children of level 1.
+    virtual unsigned int GetNumberOfChildren(tree::Node* n);
+    //====================================================================
+
+       //====================================================================
+    /// Returns the attribute requested. Useful for synchronization.
+       virtual void GetAttribute(std::string levelDescriptor,
+                                                                          std::string searchParam, 
+                                                                          std::string searchVal, 
+                                                                          std::string key, 
+                                                                          std::string& result);
+    //====================================================================
+
+
+    //====================================================================
+    /// Recursively loads the children of node 'parent' until maxlevel 
+    // is reached.
+    // If parent == NULL or parent == tree then starts with the 'children' of 
+    // the tree itself.
+    // Returns the total number of children loaded.
+    virtual int LoadChildren(tree::Node* parent, int maxlevel);
+    //====================================================================
+
+    //====================================================================
+    /// Unloads the Node and its descendants
+    // WITHOUT altering the source, e.g. the database
+    virtual void UnLoad(tree::Node* n);
+    ///====================================================================
+       
+       //====================================================================
+    /// Returns the top level node id for the given search param and search value
+    virtual void GetTopLevelNodeId(const std::string& searchParam, 
+                                                                                       const std::string& searchValue, 
+                                                                                       std::string& parent_id);
+    ///====================================================================
+
+    //====================================================================
+    // WRITE METHODS : WORK ONLY IN WRITE MODE
+    //====================================================================
+    /// Adds a branch in the tree with the attributes provided
+    // returns the Level in the tree where the branch was connected 
+    // (-1 for error, 0 for top level, etc. ) 
+    // Of course the branch is loaded on exit
+    virtual int AddBranch( const AttributeMapType& attr );
+    // Removes the node and its descendants 
+    virtual bool Remove(tree::Node*);
+    // Sets an attribute of a Node
+    virtual bool SetAttribute(tree::Node*, 
+                             const std::string& key,
+                             const std::string& value);
+       // Sets an attribute
+    virtual void SetAttribute(const std::string& levelDescriptor, 
+                             const std::string& key,
+                             const std::string& value,
+                                 const std::string& searchParam, 
+                                 const std::string& searchVal);
+       //Deletes the tuple that matches the parameters given
+       virtual void DeleteTuple(std::string levelDescriptor, std::string key, std::string value);
+       //Deletes the entries that match the parameters given
+       virtual void RemoveEntries(const std::string i_table, 
+               const std::string i_attribute, 
+               const std::string i_operand, 
+               const std::string i_val);
+    //====================================================================
+    
+
+    
+  protected:
+    //======================================================================
+    /// Open the database
+    bool DBOpen();
+    /// Import the Tree::Description from database (verifies the structure)
+    bool DBImportTreeDescription();
+    //======================================================================
+    //======================================================================
+    // Creation
+    /// Creates a new database on disk and the tables
+    bool DBCreate();
+    /// Appends to string s the SQL command to create the attributes of a given level
+    void SQLAppendAttributesDefinition(int level, std::string& s);
+    //======================================================================
+
+    //======================================================================
+
+    /// Returns the parent to which the branch defined by the attributes 
+    // provided must be grafted 
+    tree::Node* DBGetParent( const AttributeMapType& attr);
+    //======================================================================
+
+    //======================================================================
+
+    /// Loads the children of Node parent
+    // Can recurse to numberoflevels levels
+    // \return The total number of Node loaded (may be at different levels)
+    int DBLoadChildren( tree::Node* parent, int numberoflevels = 1);
+    //======================================================================
+
+    //======================================================================
+
+    /// Appends to string s the SQL command to set the attributes values 
+    // of node n
+    void SQLAppendAttributesValues(tree::Node* n, std::string& s);
+    //======================================================================
+
+    //======================================================================
+
+    /// Graft the branch defined by the attributes to the parent
+    void DBGraftToParent( tree::Node* parent, const AttributeMapType& attr);
+    //======================================================================
+    //======================================================================
+
+    /// Sets an attribute of a Node and updates the database
+    bool DBSetAttribute(tree::Node*, 
+                       const std::string& key,
+                       const std::string& value);
+    //======================================================================
+    //======================================================================
+       /// Sets an attribute and updates the database
+       void DBSetAttribute(const std::string& levelDescriptor, 
+                             const std::string& key,
+                             const std::string& value,
+                                 const std::string& searchParam, 
+                                 const std::string& searchVal);
+    //======================================================================
+    //======================================================================
+       
+    /// Inserts the Node in the database
+    void DBInsert(tree::Node* n);
+    //======================================================================
+
+       
+       //======================================================================
+
+    /// Deletes the tuple that matches the value specified in the given key and that belongs to the given level
+       void DBDelete(std::string levelDescriptor, std::string key, std::string value);
+    //======================================================================
+
+       //======================================================================
+
+       /// Recursively Removes the nodes whose parent is given as a parameter
+    void DBRecursiveRemoveNode(tree::Node* node);
+       /// Recursively Removes the nodes found in the given level with the given parent id
+       void DBRecursiveRemoveNode(int level, std::string parentId);
+       //======================================================================
+
+  
+  private:
+    /// The DB
+    CppSQLite3DB* mDB;
+   /// The physical location associated to the DicomDatabase (directory, db file...)
+    std::string mFileName;
+    /// Is the DB writable ?
+    bool mWritable;
+    void SetWritable(bool w) { mWritable = w; }
+    bool GetWritable() const { return mWritable; }
+       bool mIsAdding;
+
+   
+  };
+  // EO class SQLiteTreeHandler
+  //=======================================================================
+
+
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
+
diff --git a/src/creaImageIOSettings.cpp b/src/creaImageIOSettings.cpp
new file mode 100644 (file)
index 0000000..770a802
--- /dev/null
@@ -0,0 +1,156 @@
+#include <creaImageIOSettings.h>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <iostream>
+#include <fstream>
+
+// Memory tracking allocation
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+using namespace boost;
+namespace po = boost::program_options;
+
+namespace creaImageIO
+{
+    Settings::Settings(const std::string i_path)
+    {
+        //need to position path in user directory first.
+        m_SettingsFileName = i_path + "\\.gimmick\\Shared\\gimmick\\app.config";
+        //Test if Settings File exist
+        if(!boost::filesystem::exists(m_SettingsFileName) )
+        {
+            createFile();
+        }
+        std::ifstream ifs(m_SettingsFileName.c_str());
+               std::string line;
+               std::string sets;
+           if (ifs.is_open())
+               {
+                       while (! ifs.eof() )
+                       {
+                               getline(ifs,line);
+                               sets += line;
+                       }
+                       ifs.close();
+               }
+       std::vector<std::string> Keys;
+               Keys.push_back(SETTINGS_SYNC_EVENT);
+               Keys.push_back(SETTINGS_DBPATH);
+               Keys.push_back(SETTINGS_SYNC_FREQ);
+               Keys.push_back(SETTINGS_COPY_PATH);
+               Keys.push_back(SETTINGS_REMOVE_PATIENT_DISPLAY);
+               readSettings(Keys, sets);
+
+    }
+
+    Settings::~Settings()
+    {
+        
+    }
+
+
+   ////////////////////////////////////////////////////////////////////////////////////////////////
+    // create the config file                                                                                 //
+    //@param : -                                                                                               //
+    // return  : -                                                                                                // 
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+   void Settings::createFile()
+   {
+       m_SettingsMap[SETTINGS_SYNC_FREQ] = "12";
+       m_SettingsMap[SETTINGS_SYNC_EVENT] = "end";
+       m_SettingsMap[SETTINGS_DBPATH] = "";
+       m_SettingsMap[SETTINGS_DICOM_LIBRARY] = "gdcm";
+          m_SettingsMap[SETTINGS_COPY_PATH] = m_SettingsFileName.substr(0,m_SettingsFileName.find_last_of('\\')+1)+"Copied files";
+          m_SettingsMap[SETTINGS_REMOVE_PATIENT_DISPLAY] = "0";
+       writeSettingsFile();
+   }
+
+       ////////////////////////////////////////////////////////////////////////////////////////////////
+    // read Settings from config file                                                             //
+    // @param i_keys : list of keys                                                               //
+    // @param  i_file : text from config file                                                     //
+       // return : -
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+       void Settings::readSettings(std::vector<std::string> &i_Keys, const std::string &i_file)
+       {
+               std::vector<std::string>::iterator it_key = i_Keys.begin();
+               for(;  it_key< i_Keys.end(); ++it_key)
+               {
+                       size_t fpos = i_file.find(it_key->c_str());
+                       size_t lpos = i_file.rfind(it_key->c_str());
+                       if(fpos != std::string::npos && lpos != std::string::npos)
+                       {
+                               m_SettingsMap[it_key->c_str()] = i_file.substr(fpos + it_key->size(),lpos-fpos - it_key->size());
+                       }
+               }
+       }
+
+       ////////////////////////////////////////////////////////////////////////////////////////////////
+    // Update settings in config file                                                             //
+    // @param key : Key to update                                                                 //
+    // @param value: New value to set                                                             //
+       // return : -
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+       void Settings::updateSetting(const std::string& key, const std::string &val)
+       {
+               m_SettingsMap[key.c_str()] = val;
+       }
+
+       ////////////////////////////////////////////////////////////////////////////////////////////////
+    // add a path to a DB                                                                                    //
+    // @param i_path : DB path to add                                                             //
+    // return : -                                                                                                                                                                //
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+       void Settings::addDB(const std::string &i_path)
+       {
+               if(m_SettingsMap[SETTINGS_DBPATH].find(i_path) == std::string::npos)
+               {
+                       m_SettingsMap[SETTINGS_DBPATH] += i_path + ";";
+               }
+       }
+
+       ////////////////////////////////////////////////////////////////////////////////////////////////
+    // remove a path to a DB                                                                             //
+    // @param i_path : DB path to delete (don't exist anymore)                                    //
+    // return : -
+       ///////////////////////////////////////////////////////////////////////////////////////////////
+       
+       void Settings::removeDB(const std::string &i_path)
+       {
+               boost::algorithm::replace_all(m_SettingsMap[SETTINGS_DBPATH],i_path + ";","");
+       }
+
+       ///////////////////////////////////////////////////////////////////////////////////////////////
+    // write Settings buffer from                                                                //
+    // @param o_file : settings buffer                                                           //
+    //                                                                                                                                                                                  //
+       // return : -                                                                                                                                                            //
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+       void Settings::writeSettings(std::ofstream &o_file)
+       {
+               std::map<std::string, std::string>::iterator it_map = m_SettingsMap.begin();
+               std::stringstream st;
+               for(; it_map != m_SettingsMap.end(); ++it_map)
+               {
+                       o_file << it_map->first.c_str();
+                       o_file <<  it_map->second.c_str();
+                       o_file << it_map->first.c_str();
+                       o_file << std::endl;
+               }
+       }
+
+       ////////////////////////////////////////////////////////////////////////////////////////////////
+    // write Settings file                                                             //
+    // @param : -                                                               //
+    // return : -
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+       void Settings::writeSettingsFile()
+       {       
+           std::ofstream ofs(m_SettingsFileName.c_str());
+               ofs.clear();
+               writeSettings(ofs);
+               ofs.close();
+       }  
+}
+
diff --git a/src/creaImageIOSettings.h b/src/creaImageIOSettings.h
new file mode 100644 (file)
index 0000000..8d13d36
--- /dev/null
@@ -0,0 +1,44 @@
+#include <boost/program_options.hpp>
+#include <map>
+
+#define SETTINGS_DICOM_LIBRARY                 "<DICOM Library>"
+#define SETTINGS_SYNC_EVENT                            "<syncro_event>"
+#define SETTINGS_SYNC_FREQ                             "<syncro_frequency>"
+#define SETTINGS_DBPATH                                        "<dbpath>"
+#define SETTINGS_COPY_PATH                             "<copy_path>"
+#define SETTINGS_REMOVE_PATIENT_DISPLAY "<remove_patient>"
+
+
+namespace creaImageIO
+{
+    class Settings{
+    public :
+        Settings(const std::string i_path);
+        ~Settings();
+
+        //get the value for a given option
+               const std::string getValue(const std::string i_key){return m_SettingsMap[i_key];}
+       
+               void addDB(const std::string &i_path);
+
+               void removeDB(const std::string &i_path);
+
+               void updateSetting(const std::string& key, const std::string &val);
+       
+               //write configuration file
+               void writeSettingsFile();
+               
+    private :
+               // Settings Key-Value Map
+               std::map<std::string, std::string> m_SettingsMap;
+               
+               //read the configuration file
+               void readSettings(std::vector<std::string> &i_Keys, const std::string &i_file);
+        // create the configuration file
+        void createFile();
+               void writeSettings(std::ofstream &o_filebuf);
+               std::string m_SettingsFileName;
+               
+               
+    };
+}
diff --git a/src/creaImageIOSynchron.cpp b/src/creaImageIOSynchron.cpp
new file mode 100644 (file)
index 0000000..0955ffa
--- /dev/null
@@ -0,0 +1,451 @@
+#include <creaImageIOSynchron.h>
+#include <creaImageIOSystem.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+
+
+//namespace fs = boost::filesystem;
+
+//=====================================================================
+
+namespace creaImageIO
+{
+
+    //=====================================================================
+    #define QUERYSYNCDB(QUER,RES)                                      \
+    try                                                                        \
+    {                                                                  \
+       RES = mDB->execQuery(QUER.c_str());                             \
+    }                                                                  \
+    catch (CppSQLite3Exception& e)                                     \
+    {                                                                  \
+      GimmickError("SQLite query '"<<QUER<<"' Error : "                        \
+                  << e.errorCode() << ":"                              \
+                  << e.errorMessage() );                               \
+    }                                                                                                                                     
+   //=====================================================================
+    #define UPDATESYNCDB(UP)                                           \
+    try                                                                        \
+    {                                                                  \
+      mDB->execDML(UP.c_str());                                                \
+    }                                                                  \
+    catch (CppSQLite3Exception& e)                                     \
+    {                                                                  \
+      GimmickError("SQLite update '"<<UP<<"' Error : "                 \
+                  << e.errorCode() << ":"                              \
+                  << e.errorMessage() );                               \
+    }                          
+   //=====================================================================
+
+    Synchronizer::Synchronizer(const std::string& path)
+    {
+               pathDB = path + "maintenance_database.db3";
+               mDB = new CppSQLite3DB;
+               Initialize();
+    }
+
+   //=====================================================================
+    Synchronizer::~Synchronizer()
+    {
+       delete mDB;
+    }
+
+       //=====================================================================
+       void Synchronizer::Initialize()
+       {    
+               if (!boost::filesystem::exists(pathDB)) 
+               {
+                       CreateDB();
+               }
+    
+               // OPENING
+               else
+               {
+               try
+               {
+               mDB->open(pathDB.c_str());
+               }
+               catch (CppSQLite3Exception& e)
+               {
+               GimmickError("Opening '"<<pathDB<<"' : "
+                    << e.errorCode() << ":" 
+                    << e.errorMessage());
+               }
+               }
+               // get the ADD operations List 
+               //UpdateAddList(pathDB);
+       }
+
+   //=====================================================================
+    void Synchronizer::CreateDB()
+    {
+               mDB->open(pathDB.c_str());
+        // CREATING TABLES
+       std::string command;
+       command = "CREATE TABLE ";
+       command += "ADD_OPS";
+       command += "\n(\nADD_KEY INTEGER PRIMARY KEY";
+       command += ",\nPATH text";
+       command += ",\nRECURSIVE boolean";
+       command += ",\nFILES_ADDED int";
+       command += ",\nREFERENCEDDB text";
+       command += "\n)";
+       UPDATESYNCDB(command);
+
+       command = "CREATE TABLE ";
+       command += "IGNORED_FILES";
+       command += "\n(\nID INTEGER PRIMARY KEY";
+       command += ",\nADD_KEY integer";
+       command += ",\nPATH text";
+       command += ",\nREMOVE boolean";
+       command += ",\nTIME datetext";
+       command += "\n)";
+       UPDATESYNCDB(command);
+    }
+
+       //=====================================================================
+       void Synchronizer::CleanName(std::string& str) const
+       {
+               size_t pos;
+               do
+               {
+                       pos = str.find('\\');
+                       if (pos!=-1)  
+                       {
+                               str.replace(pos, 1, "/");
+                       }
+               }
+               while (pos!=-1);
+       }
+
+       //=====================================================================
+    void Synchronizer::GetFileList(std::vector<AddList> & list, const std::string& refdb)
+    {
+       CleanList(refdb);
+       list=mAddList;
+    }
+
+       //=====================================================================
+   void Synchronizer::GetIgnoredFiles(const std::string& key, std::vector<std::string> &ignoreList)
+   {
+        ignoreList=GetIgnoreList(key);
+   }
+
+//=====================================================================
+    void Synchronizer::UpdateAddList(const std::string& refdb)
+    {
+        std::string query = "SELECT * FROM ADD_OPS WHERE REFERENCEDDB = '"+refdb+"';";
+        CppSQLite3Query res;
+        QUERYSYNCDB(query, res);
+       while (!res.eof())
+        {
+           AddList temp = AddList(res);
+            mAddList.push_back(temp);
+           res.nextRow();
+        }
+    }
+
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // remove an entry of the DB
+    //@param i_table : table where to do the remove
+    // @param i_key : the add_key reference (one entry to remove for ADD_OP table, many for IGNORED_FILES table
+    //@result : -
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    void Synchronizer::RemoveEntry(const std::string i_table, const std::string i_key)
+    {
+        std::string query = "DELETE  FROM " + i_table + " WHERE ADD_KEY = '" + i_key +"'";
+        UPDATESYNCDB(query);
+    }
+
+       /////////////////////////////////////////////////////////////////////////////////////////////////
+    // remove several entries of the DB
+    // @param i_table : table where to do the remove
+    // @param i_attribute: attribute to match
+    // @param i_operand : operand to use
+    // @param i_val : the reference
+    //@result : -
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    void Synchronizer::RemoveEntries(const std::string i_table, 
+               const std::string i_attribute, 
+               const std::string i_operand, 
+               const std::string i_val)
+    {
+        std::stringstream query;
+       query<<"DELETE  FROM "<<i_table<<" WHERE "<<i_attribute<<" "<<i_operand<<" '"<<i_val<<"'";
+        UPDATESYNCDB(query.str());
+       }
+
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // clean DataBase if an operation has no child anymore
+       // @param refdb: the database segement to clean
+    // @result : -
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    void Synchronizer::CleanList(const std::string& refdb)
+    {
+       mAddList.clear();
+       UpdateAddList(refdb);
+        std::vector<AddList>::iterator it_add = mAddList.begin();
+        for(;it_add <mAddList.end(); ++it_add)
+        {
+                if(it_add->nbFiles == "0")
+                {
+                       RemoveEntry("ADD_OPS", it_add->key);
+                       RemoveEntry("IGNORED_FILES", it_add->key);
+
+                }
+        }
+               mAddList.clear();
+               UpdateAddList(refdb);
+    }
+
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // Inserts a new add operation in the database
+    // @param path: the path of the directory that was added
+    // @param recursive: shows if the action was called recursively or not
+    // @param nChildren: the number of files affected by the operation
+    // @param refdb: the referenced database
+    // @result : The operation has been added
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+       void Synchronizer::InsertAddOp(const std::string& path, const std::string& recursive, const std::string& nChildren, const std::string& refdb)
+       {
+               std::string insert;
+               std::string pat=path.c_str();
+               CleanName(pat);
+               insert="INSERT INTO ADD_OPS (PATH,RECURSIVE,FILES_ADDED,REFERENCEDDB) VALUES('";
+               insert+=pat+"','";
+               insert+=recursive+"',";
+               insert+=nChildren+",'";
+               insert+=refdb+"');";
+               UPDATESYNCDB(insert);
+       }
+
+       /////////////////////////////////////////////////////////////////////////////////////////////////
+    // Inserts a new ignored file in the database
+       // @param add_key: the key of the add_op to which it corresponds
+    // @param path: the path of the directory that was added
+       // @param remove: shows if the file was removed or not
+       // @param time: the time in which the file was removed
+    // @result : The file has been inserted
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+
+       void Synchronizer::InsertIgnoreFile(const std::string& addKey, const std::string& path, const std::string& remove, const std::string& time, const std::string& refdb )
+       {
+               std::string pat=path.c_str();
+               CleanName(pat);
+               std::string id=GetAttribute("ID","IGNORED_FILES","PATH",pat,refdb);
+               if(id.compare("")==0)
+               {
+                       std::string insert;
+                       insert="INSERT INTO IGNORED_FILES (ADD_KEY,PATH,REMOVE,TIME) VALUES('";
+                       insert+=addKey+"','";
+                       insert+=pat+"','";
+                       insert+=remove+"',";
+                       insert+=time+");";
+                       UPDATESYNCDB(insert);
+               }
+               else
+               {
+                       //Gets the add key
+                       std::string ak=GetAttribute("ADD_KEY","IGNORED_FILES","ID",id,refdb);
+                       //gets the parent database to check if the file has been added to the current database
+                       std::string parentDB=GetAttribute("*","ADD_OPS","ADD_KEY",ak,refdb);
+                       //If there is no such entry, add it
+                       if(parentDB.compare("")==0)
+                       {
+                               std::string insert;
+                               insert="INSERT INTO IGNORED_FILES (ADD_KEY,PATH,REMOVE,TIME) VALUES('";
+                               insert+=addKey+"','";
+                               insert+=pat+"','";
+                               insert+=remove+"',";
+                               insert+=time+");";
+                               UPDATESYNCDB(insert);
+                       }
+                       else
+                       {
+                               //Sets the new add key attribute for the file
+                               SetAttribute("ADD_KEY","IGNORED_FILES",addKey,"ID", id,refdb);
+                               //Sets the new remove attribute for the file
+                               SetAttribute("REMOVE","IGNORED_FILES",remove,"ID", id,refdb);
+                               //Sets the new time attribute for the file
+                               SetAttribute("TIME","IGNORED_FILES",time,"ID", id,refdb);
+                       }
+               }
+       }
+
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // get the files name to ignore for a add operation synchronization
+    // @param : the add key
+    //@result : list (path) of ignore files
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    std::vector<std::string> Synchronizer::GetIgnoreList(const std::string &i_key)
+    {
+        mIgnoreList.clear();
+        std::vector<std::string> i_names;
+       std::string query = "SELECT * FROM IGNORED_FILES WHERE ADD_KEY = ";
+       query+=i_key;
+        CppSQLite3Query res;
+        QUERYSYNCDB(query, res);
+       while (!res.eof())
+        {
+               RemoveList temp = RemoveList(res);
+               if(temp.remove.compare("0")==0)
+               {
+                   mIgnoreList.push_back(temp);
+               }
+               res.nextRow();
+        }
+        std::vector<RemoveList>::iterator it;
+
+        for(it = mIgnoreList.begin();it != mIgnoreList.end(); ++it)
+        {
+            i_names.push_back((*it).path);
+        }
+       return i_names;
+    }
+
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // Gets the required attribute in the required table
+    // @param attribute: the attribute to look for
+    // @param table: the table to look in
+    // @param searchParam: the search parameter
+    // @param searchValue: the search value
+    // @result : required attribute
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    std::string Synchronizer::GetAttribute(const std::string& attribute, 
+                                       const std::string& table, 
+                                       const std::string& searchParam,
+                                       const std::string& searchValue, 
+                                       const std::string& refdb)
+    {
+        std::stringstream query;
+       std::string result;
+       std::string sVal=searchValue.c_str();
+       CleanName(sVal);
+       query<<"SELECT "<<attribute<<" FROM "<<table<<" WHERE "<<searchParam<<" = '"<<sVal;
+       if(table.compare("ADD_OPS")==0)
+       {
+               query<<"' AND REFERENCEDDB = '"<<refdb<<"';";
+       }
+       else
+       {
+               query<<"';";
+       }
+        CppSQLite3Query res;
+        QUERYSYNCDB(query.str(), res);
+       while (!res.eof())
+        {
+               result=res.getStringField(0);
+               res.nextRow();
+        }
+       return result;
+    }
+
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // Sets the attribute value in the required table and column
+    // @param attribute: the attribute to look for
+    // @param table: the table to look in
+    // @param value: the value to set
+    // @param searchParam: the search parameter
+    // @param searchValue: the search value
+    // @result : attribute value changed
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    void Synchronizer::SetAttribute(const std::string& attribute, 
+                               const std::string& table, 
+                               const std::string& value,
+                               const std::string& searchParam,
+                               const std::string& searchValue,
+                               const std::string& refdb)
+    {
+       std::string val=value.c_str();
+       std::string sVal=searchValue.c_str();
+       CleanName(val);
+       CleanName(sVal);
+       std::string sql = "UPDATE ";
+       sql+=table;
+       sql+=" SET ";
+       sql += attribute;
+       sql += " = '";
+       sql += val;
+       sql += "' WHERE ";
+       sql += searchParam;
+       sql += " = '";
+       sql += sVal;
+       if(table.compare("ADD_OPS")==0)
+       {
+               sql += "' AND REFERENCEDDB = '";
+               sql += refdb;
+       }
+       sql += "';";
+       UPDATESYNCDB(sql);
+    }
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+    // get the files name to ignore for a add operation synchronization
+    // @param : the add key
+    //@result : list (path) of ignore files
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+       void Synchronizer::GetList(const std::string i_db)
+    {
+               mList.clear();
+        std::vector<std::string> i_names;
+               std::vector<std::string> keys;
+               CppSQLite3Query res;
+               std::string query ="SELECT ADD_KEY, REFERENCEDDB FROM  ADD_OPS";
+               QUERYSYNCDB(query, res);
+               keys.clear();
+               while (!res.eof())
+        {
+                       std::string key(res.getStringField(0));
+                       std::string db(res.getStringField(1));
+                       if (db == i_db)
+                       {
+                               keys.push_back(key);
+                       }
+                       res.nextRow();
+               }
+               query = "SELECT PATH, REMOVE FROM IGNORED_FILES WHERE";
+               if(keys.size() > 0)
+               {
+                       for (int i=0; i < keys.size(); i++)
+                       {
+                               query += " ADD_KEY = " + keys[i];
+                               query += " AND";
+                       }
+                       query = query.substr(0,query.size() - 4);
+               }
+               else 
+               {
+                       query += " ADD_KEY = -1";
+               }
+        QUERYSYNCDB(query, res);
+               while (!res.eof())
+        {
+               std::string file(res.getStringField(0));
+               std::string ignore(res.getStringField(1));
+               mList[file] = ignore == "0"? true : false;
+               res.nextRow();
+        }
+    }
+
+       bool Synchronizer::isIndexed(const std::string filename)
+       {
+               bool valid = true;
+               std::string name(filename);
+               boost::algorithm::replace_all( name,"\\" , "/");
+               std::map <std::string, bool>::iterator it_list = mList.begin();
+               for(;it_list != mList.end(); it_list++)
+               {
+                       if(it_list->first == name)
+                       {
+                               valid = false;
+                               break;
+                       }
+               }
+               return valid;
+       }
+}
+
+
diff --git a/src/creaImageIOSynchron.h b/src/creaImageIOSynchron.h
new file mode 100644 (file)
index 0000000..ab101f6
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef __creaImageIOSynchron_h_INCLUDED__
+#define __creaImageIOSynchron_h_INCLUDED__
+
+#include <string>
+#include <map>
+#include <iostream>
+#include <vector>
+#include "CppSQLite3.h"
+
+namespace creaImageIO
+{
+       using namespace std;
+   //================================================================================================================
+       ///Represents the list of currently added files
+    class AddList
+    {
+      public :
+                 ///Key to be added into the database
+              std::string key;
+                         ///Path of the directory
+              std::string path;
+                         /// Defines if the operation was recursive or not
+              std::string recursive;
+                         ///Number of added files
+              std::string nbFiles;
+                         ///Ctor
+              AddList(CppSQLite3Query& res):
+                         key(res.getStringField(0)), 
+                         path(res.getStringField(1)),
+                         recursive(res.getStringField(2)),
+                         nbFiles(res.getStringField(3))
+              {}
+    };
+   //================================================================================================================
+
+   //================================================================================================================
+       ///Represents the list of currently removed files
+       class RemoveList
+    {
+      public :
+                 ///Key to be added into the database
+              std::string key;
+                         ///Path of the remove file
+              std::string path;
+                         ///Defines if the file was removed or not
+              std::string remove;
+                         ///Time of the last change of the file
+              std::string time;
+             ///Ctor
+              RemoveList(CppSQLite3Query& res):
+                         key(res.getStringField(1)), 
+                         path(res.getStringField(2)),
+                         remove(res.getStringField(3)),
+                         time(res.getStringField(4))
+                         {}
+    };
+   //================================================================================================================
+  
+   //================================================================================================================
+       ///In charge of the synchronization of the database and the disk state.
+    class Synchronizer
+    {
+      public:
+                 ///Ctor
+              Synchronizer(const std::string& path);
+                         ///Dtor
+              virtual ~Synchronizer();
+                         ///Initializes the database
+                         void Initialize();
+                         ///Inserts an add operation to the database
+                         void InsertAddOp(const std::string& path, 
+                                                       const std::string& recursive,
+                                                       const std::string& nChildren, 
+                                                       const std::string& refdb);
+                         ///Inserts a file to be ignored
+                         void InsertIgnoreFile(const std::string& addKey,
+                                                       const std::string& path, 
+                                                       const std::string& remove,
+                                                       const std::string& time,
+                                                       const std::string& refdb);
+                         ///Removes an entry that matches the given parameter
+                         void RemoveEntry(const std::string i_table, const std::string i_key);
+                         ///Removes several entries
+                         void RemoveEntries(const std::string i_table, 
+                                                                                       const std::string i_attribute, 
+                                                                                       const std::string i_operand, 
+                                                                                       const std::string i_key);
+                         ///Gets the list of AddFiles
+                         void GetFileList(std::vector<AddList>& files , const std::string& refdb);
+                         ///Gets the list of ignored files
+                         void GetIgnoredFiles(const std::string& key, std::vector<std::string> &ignoreList);
+                         ///Gets the attribute that matches the parameters
+                         std::string GetAttribute(const std::string& attribute, 
+                                                                               const std::string& table, 
+                                                                               const std::string& searchParam,
+                                                                               const std::string& searchValue,
+                                                                               const std::string& refdb);
+                         ///Sets an attribute to an entry that matches the given parameters
+                         void SetAttribute(const std::string& attribute, 
+                                                                               const std::string& table, 
+                                                                               const std::string& value,
+                                                                               const std::string& searchParam,
+                                                                               const std::string& searchValue, 
+                                                                               const std::string& refdb);
+                         // Get the List of indexed files (removed or not)
+                         void GetList(const std::string i_db);
+                         // Test to not if a file is indexed on db or not
+                         bool isIndexed(const std::string filename);
+                         // List of all indexed files
+                         std::map <std::string, bool> mList;
+                         ///The current AddList
+              std::vector<AddList>  mAddList;
+                         ///The current RemoveList
+              std::vector<RemoveList>  mIgnoreList;
+      private :
+             
+              /// The DB
+              CppSQLite3DB* mDB;
+                         ///Path of the current database
+              std::string pathDB;
+                         ///Creates a new database
+              void CreateDB();
+                         ///Updates the AddList
+              void UpdateAddList(const std::string& refdb);
+                         ///Cleans the list in case operations are no longer useful (0 added files)
+              void CleanList(const std::string& refdb);
+                         ///Cleans the name (changes slashes and backslashes according to the system)
+                         void CleanName(std::string& str) const;
+                         ///Gets the ignore list
+                     std::vector<std::string> GetIgnoreList(const std::string &i_key);
+
+    };
+   //================================================================================================================
+
+       
+} 
+// EOF
+#endif
+
diff --git a/src/creaImageIOSynchronizer.cpp b/src/creaImageIOSynchronizer.cpp
new file mode 100644 (file)
index 0000000..8ab3009
--- /dev/null
@@ -0,0 +1,114 @@
+#include <creaImageIOSystem.h>
+#include <creaImageIOSynchronizer.h>
+#include "boost/filesystem.hpp"
+
+namespace fs = boost::filesystem;
+
+namespace creaImageIO
+{
+
+  //==============================================================
+       Synchronizer::Synchronizer(TreeHandler * th)
+    : mHandler(th)
+  {    
+   
+  }
+  //==============================================================
+  //==============================================================
+       Synchronizer::~Synchronizer()
+  {    
+   
+  }
+  //==============================================================
+
+  //==============================================================
+  std::string Synchronizer::Synchronize(bool update)
+  {
+         GimmickMessage(1,"Synchronizing "<<std::endl);
+         int id=1;
+         std::stringstream mess;
+         std::string file;
+         mHandler->GetAttribute("Image","","","FullFileName",file);
+         size_t ini=0;
+         size_t fin=0;
+         while(fin<file.size()-1)
+         {
+          fin=file.find('#',ini);
+          SynchronizeFile(update,file.substr(ini,fin-ini),mess);
+          ini=fin+1;
+         }
+         if(mess.str()=="")
+         {
+                 mess<<"Database up to date"<<std::endl;
+         }
+         GimmickMessage(1,mess.str());
+         return mess.str();
+  }
+  //==============================================================
+
+  //==============================================================
+  void Synchronizer::SynchronizeFile(bool update, std::string file, std::stringstream& mess)
+  {
+       if(!FileExists(file))
+       {
+               if(update)
+               {
+                       mHandler->DeleteTuple("Image","FullFileName",file);
+                       mess<<file<<" has been removed from the DB"<<std::endl;
+               }
+               else
+               {
+                       mess<<file<<" State: Non existant"<<std::endl;
+               }
+       }
+       else 
+       {
+               AttributesMatch(update,file,mess);
+       } 
+  }
+  //==============================================================
+
+  //==============================================================
+  bool Synchronizer::FileExists(std::string file)
+  {
+         GimmickDebugMessage(4,"Verifying if file "<<file<<" exists"<<std::endl);
+         bool exists=true;
+         if ( !fs::exists( file ) )
+         {
+                 exists=false;
+         }
+         return exists;
+  }
+  //==============================================================
+
+  //==============================================================
+  void Synchronizer::AttributesMatch(bool update, std::string file, std::stringstream& mess)
+  {
+         std::map< std::string, std::string>  attr;
+         mHandler->GetTree().GetDescriptor().BuildAttributeMap(attr);
+      mReader.ReadAttributes(file,attr);
+         tree::LevelDescriptor::AttributeDescriptorListType adl= mHandler->GetTree().GetAttributeDescriptorList(mHandler->GetTree().GetNumberOfLevels()-1);    
+         tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+         for (a = adl.begin();a!=adl.end();++a)
+         {
+          std::string databaseVal;
+          mHandler->GetAttribute("Image","FullFileName",file,a->GetKey(),databaseVal);
+          std::string fileVal=attr.find(a->GetKey())->second;
+          if ( a->GetFlags()==0 && databaseVal.compare(fileVal)!=0 ) 
+           {
+                 if(update)
+                       {
+                               mHandler->SetAttribute("Image",a->GetKey(),fileVal,"FullFileName", file);
+                               mess<<file<<" has been updated in the DB"<<std::endl;
+                       }
+                       else
+                       {
+                               mess<<file<<" State: Attributes differ"<<std::endl;
+                       }
+           }
+         }
+  }
+  //==============================================================
+
+}
\ No newline at end of file
diff --git a/src/creaImageIOSynchronizer.h b/src/creaImageIOSynchronizer.h
new file mode 100644 (file)
index 0000000..fa3ae37
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __creaImageIOSynchronizer_h_INCLUDED__
+#define __creaImageIOSynchronizer_h_INCLUDED__
+
+#include <creaImageIOSQLiteTreeHandler.h>
+#include <creaImageIOImageReader.h>
+
+namespace creaImageIO
+{
+
+//=======================================================================
+/// Synchronizes a given database with disk
+class Synchronizer
+  {
+  public:
+      /// Ctor
+      Synchronizer(TreeHandler* th);
+      /// Dtor
+      ~Synchronizer();
+         ///Sets the tree handler to use in order to synchronize with a given database
+         void SetTreeHandler(TreeHandler * handler){mHandler=handler;}
+         ///Synchronizes the database in the current tree handler with disk by doing the passed action. If it is true,
+         ///the database will be updated, otherwise a warning message will be returned.
+         std::string Synchronize(bool update);
+         ///Checks if the file given as a parameter exists in the drive
+         bool FileExists(std::string file);
+         ///Checks if the attributes of the node given as a parameter matchwith it correspondent file in disk 
+         ///NB: This method doesn't check the existence of the file, so FileExists should be called before.
+         void AttributesMatch(bool update, std::string file, std::stringstream& mess);
+
+
+  private:
+         ///The tree handler
+         TreeHandler* mHandler;
+         ///The image reader
+         ImageReader mReader;
+         ///Synchronizes the given file, doing the action required and returning the result on the string supplied
+         void SynchronizeFile(bool update, std::string file, std::stringstream& message);
+
+  };
+} // EO namespace creaImageIO
+
+// EOF
+#endif 
\ No newline at end of file
diff --git a/src/creaImageIOSystem.cpp b/src/creaImageIOSystem.cpp
new file mode 100644 (file)
index 0000000..8a9662d
--- /dev/null
@@ -0,0 +1,7 @@
+#include "creaImageIOSystem.h"
+
+namespace creaImageIO
+{
+
+
+} // namespace
\ No newline at end of file
diff --git a/src/creaImageIOSystem.h b/src/creaImageIOSystem.h
new file mode 100644 (file)
index 0000000..1ecda73
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __creaImageIOSystem_INCLUDED__
+#define __creaImageIOSystem_INCLUDED__
+
+#include "creaMessageManager.h"
+
+
+
+#if defined(_WIN32)
+
+  #ifdef CREAIMAGEIO_EXPORT_SYMBOLS
+    #define CREAIMAGEIO_EXPORT __declspec( dllexport )
+#else
+    #define CREAIMAGEIO_EXPORT __declspec( dllimport )
+  #endif
+  #define CREAIMAGEIO_CDECL __cdecl
+#else
+  #define CREAIMAGEIO_EXPORT
+  #define CREAIMAGEIO_CDECL
+#endif // defined(_WIN32)
+
+
+namespace creaImageIO
+{
+  //==============================================================
+  inline void RegisterGimmickMessageTypes()
+  {
+    static bool first_time = true;
+    if (first_time)
+      {
+       crea::MessageManager::RegisterMessageType("Gimmick!",
+                                                 "Gimmick",1);
+       crea::MessageManager::RegisterMessageType("Gimmick! DEBUG",
+                                                 "Gimmick",0);
+       first_time = false;
+      }
+  }
+  //==============================================================
+  inline void SetGimmickMessageLevel(int l)
+  {
+    RegisterGimmickMessageTypes();                     
+    crea::MessageManager::SetMessageLevel("Gimmick!",l);
+  }
+  //==============================================================
+  inline void SetGimmickDebugMessageLevel(int l)               
+  {
+    RegisterGimmickMessageTypes();                     
+    crea::MessageManager::SetMessageLevel("Gimmick! DEBUG",l);
+  }
+  //==============================================================
+  
+       inline void deleteGimmickDebugMessage()
+       {
+               delete crea::MessageManager::GetInstance();
+       }
+  
+
+#define GimmickMessage(LEV,MESS)                       \
+  creaMessage("Gimmick!",LEV,"[Gimmick!] "<<MESS);
+#define GimmickDebugMessage(LEV,MESS)                                  \
+  creaDebugMessage("Gimmick! DEBUG",LEV,"[Gimmick!] DEBUG: "<<MESS);
+#define GimmickError(MESS)                     \
+  creaError("[Gimmick!] "<<MESS);
+
+} // namespace
+
+#endif
+
diff --git a/src/creaImageIOTimestampDatabaseHandler.cpp b/src/creaImageIOTimestampDatabaseHandler.cpp
new file mode 100644 (file)
index 0000000..a0a522b
--- /dev/null
@@ -0,0 +1,435 @@
+#include <creaImageIOTimestampDatabaseHandler.h>
+#include <creaImageIOSystem.h>
+
+#include "CppSQLite3.h"
+
+#include <sys/stat.h>
+
+#include <deque>
+
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string/replace.hpp>
+
+namespace creaImageIO
+{
+       using namespace tree;
+  //=============================================================
+  TimestampDatabaseHandler::TimestampDatabaseHandler(const std::string& filename)
+    : mFileName(filename)
+  {
+    mDB = new CppSQLite3DB;
+    GimmickMessage(1,"SQLite version : "
+                  <<std::string(mDB->SQLiteVersion())<< std::endl);
+  }
+  //=============================================================
+
+  //=============================================================
+  TimestampDatabaseHandler::~TimestampDatabaseHandler()
+  {
+    delete mDB;
+  }
+  //=============================================================
+  //=====================================================================
+  bool TimestampDatabaseHandler::Open()
+  {
+    return DBOpen();
+  }
+
+  //=====================================================================
+  bool TimestampDatabaseHandler::Create()
+  {
+    return DBCreate();
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  bool TimestampDatabaseHandler::Close()
+  {
+    return true;
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  bool TimestampDatabaseHandler::Destroy()
+  {
+    return false;
+  }
+
+
+
+
+
+
+  //=====================================================================
+  // SQLite DB specific methods
+  //=====================================================================
+  //=====================================================================
+#define QUERYTIMESTAMPDB(QUER,RES)                                             \
+    try                                                                        \
+      {                                                                        \
+       GimmickMessage(2,"SQL query: '"<<QUER<<"'"<<std::endl);         \
+       RES = mDB->execQuery(QUER.c_str());                             \
+      }                                                                        \
+    catch (CppSQLite3Exception& e)                                     \
+      {                                                                        \
+       GimmickError("SQLite query '"<<QUER<<"' : "                     \
+                    << e.errorCode() << ":"                            \
+                    << e.errorMessage() );                             \
+      }                                                                        \
+  //=====================================================================
+#define UPDATETIMESTAMPDB(UP)                                                  \
+  try                                                                  \
+    {                                                                  \
+      GimmickMessage(2,"SQL update: '"<<UP<<"'"<<std::endl);           \
+      mDB->execDML(UP.c_str());                                                \
+    }                                                                  \
+  catch (CppSQLite3Exception& e)                                       \
+    {                                                                  \
+      GimmickError("SQLite update '"<<UP<<"' Error : "                 \
+                  << e.errorCode() << ":"                              \
+                  << e.errorMessage() );                               \
+    }                                                                  
+  //=====================================================================
+
+
+   //=====================================================================
+  bool TimestampDatabaseHandler::DBOpen()
+  {
+    GimmickMessage(1,"Opening SQLite database '"<<GetFileName()
+                  <<"' ... "<<std::endl);
+    // OPENING FILE
+    if (!boost::filesystem::exists(GetFileName())) 
+      {
+       return false;
+      }
+
+    try
+      {
+       mDB->open(GetFileName().c_str());
+      }
+    catch (CppSQLite3Exception& e)
+      {
+       GimmickError("Opening '"<<GetFileName()<<"' : "
+                    << e.errorCode() << ":" 
+                    << e.errorMessage());
+       return false;
+      }
+
+    GimmickDebugMessage(1,"Opening SQLite database '"<<GetFileName()
+                  <<"' ... OK"<<std::endl);
+    return true;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  bool TimestampDatabaseHandler::DBCreate()
+  {
+    GimmickMessage(1,"Creating SQLite database '"<<GetFileName()
+                  <<"' ... "<<std::endl);
+
+    if (boost::filesystem::exists(GetFileName())) 
+      {
+       GimmickError(GetFileName()<<"' : "
+                    << "file already exists");
+       return false;
+      }
+    
+    // OPENING
+    try
+      {
+       mDB->open(GetFileName().c_str());
+      }
+    catch (CppSQLite3Exception& e)
+      {
+       GimmickError(e.errorCode() << ":" 
+                    << e.errorMessage() <<std::endl);
+       return false;
+      }
+    
+     
+    // CREATING TABLES
+    
+    std::string command;
+  
+    
+           command = "CREATE TABLE ";
+           command += "FILES";
+           command += "\n(\nID INTEGER PRIMARY KEY";
+               command += ",\nPARENT_ID int not null"; 
+           command += ",\nPATH text";
+               command += ",\nLastModified datetext";
+               command += ",\nLastRead datetext";
+               command += ",\nTopLevelNodeId text";
+               command += ",\nReferencedDB text";
+               command += ",\nconstraint FK_PARENT foreign key (PARENT_ID) references ";
+               command += "FILES";
+               command += "(ID) on delete restrict on update restrict";
+             
+           command += "\n)";
+           UPDATETIMESTAMPDB(command);
+           
+    return true;
+  }
+
+
+
+  //=====================================================================
+  void TimestampDatabaseHandler::CleanPath(std::string& str) const
+  {
+        size_t pos;
+        do
+     {
+         pos = str.find('\\');
+         if ((int)pos!=-1)  
+                {
+                        str.replace(pos, 1, "/");
+                }
+     }
+     while ((int)pos!=-1);
+  }
+  //=====================================================================
+
+  bool TimestampDatabaseHandler::AddDirectory(const std::string& parent,
+                                                                                  const std::string& path, 
+                                                                                  const time_t lastModif, 
+                                                                                  const time_t lastRead,
+                                                                                  const std::string& refdb)
+  {
+        bool valid=false;
+        std::string par=parent.c_str();
+        std::string pat=path.c_str();
+        CleanPath(par);
+        CleanPath(pat);
+
+        std::string pathId=IsIndexed(pat,refdb);
+        //Case: It is a root parent
+        if(parent.compare("")==0)
+        {
+                if(pathId.compare("")==0)
+                {
+                       AddFile(pat,lastModif,lastRead,refdb);
+                       valid=true;
+                }
+                else
+                {
+                        valid=CheckTimestamp(pathId, lastModif, refdb);
+                }
+        }
+        else 
+        {
+                std::string parentId=IsIndexed(par,refdb);
+                //Case: Parent is not in database
+                if(parentId.compare("")==0)
+               {
+                       AddFile(par,lastModif,lastRead,refdb);
+                       parentId=IsIndexed(par,refdb);
+               }
+
+               //Case path is not in database
+               if(pathId.compare("")==0)
+               {
+                   AddFile(parentId,pat,lastModif,lastRead,refdb);
+                       valid=true;
+               }
+               //Parent and path are in the database
+               else
+               {
+                       SetAttribute("PARENT_ID",parentId,"ID", pathId);
+                       valid=CheckTimestamp(pathId, lastModif, refdb);
+               }
+        }
+        return valid;
+       
+  }
+
+  //=====================================================================
+
+  void TimestampDatabaseHandler::AddFile(const std::string& path, const time_t lastModif, const time_t lastRead,  const std::string& refdb)
+  {
+       std::stringstream out;
+       out<<"INSERT INTO FILES (PARENT_ID,PATH,LastModified,LastRead,ReferencedDB) VALUES(0,'"<<path<<"',";
+       out<<lastModif<<","<<lastRead<<",'"<<refdb<<"');";
+    UPDATETIMESTAMPDB(out.str());
+       
+  }
+
+   //=====================================================================
+
+  void TimestampDatabaseHandler::AddFile(const std::string& parentId, 
+                                                                                const std::string& path, 
+                                                                                const time_t lastModif, 
+                                                                                const time_t lastRead,  
+                                                                                const std::string& refdb)
+  {
+       std::stringstream out;
+       out<<"INSERT INTO FILES (PARENT_ID,PATH,LastModified,LastRead,ReferencedDB) VALUES("<<parentId<<",'"<<path<<"',";
+       out<<lastModif<<","<<lastRead<<",'"<<refdb<<"');";
+    UPDATETIMESTAMPDB(out.str());
+  }
+
+  //=====================================================================
+  std::string TimestampDatabaseHandler::IsIndexed(const std::string& path, const std::string& refdb)
+  {
+       std::string pat=path.c_str();
+       CleanPath(pat);
+       std::stringstream out;
+       std::stringstream result;
+       out<<"SELECT ID FROM FILES WHERE PATH='"<<pat<<"' AND REFERENCEDDB='"<<refdb<<"';";
+               
+       CppSQLite3Query q;
+       QUERYTIMESTAMPDB(out.str(),q);
+       
+       
+       while (!q.eof())
+         {
+           for (int fld = 0; fld < q.numFields(); fld++)
+             {
+                         result<<q.getStringField(fld);
+             }
+           q.nextRow();
+         }
+
+         return result.str();
+  }
+
+  //=====================================================================
+  void TimestampDatabaseHandler::SetAttribute(const std::string& attName, 
+                                                                                       const std::string& attValue,
+                                                                                       const std::string& searchParam,
+                                                                                       const std::string& searchValue)
+  {
+       std::string av=attValue.c_str();
+       std::string sv=searchValue.c_str();
+       CleanPath(av);
+       CleanPath(sv);
+
+       std::string sql = "UPDATE FILES SET ";
+    sql += attName;
+    sql += " = '";
+    sql += av;
+    sql += "' WHERE ";
+       sql += searchParam;
+       sql += " = '";
+    sql += sv;
+       sql += "'";
+    UPDATETIMESTAMPDB(sql);
+  }
+  //=====================================================================
+  void TimestampDatabaseHandler::RemoveNode(const std::string& searchAtt, const tree::Node* node, const std::string& refdb)
+  {
+         int n=node->GetNumberOfChildren();
+         if(n>0)
+         {
+                 std::vector<tree::Node*> children=node->GetChildrenList();
+                 std::vector<tree::Node*>::iterator it;
+                 for(it=children.begin();it!=children.end();++it)
+                 {
+                         RemoveNode(searchAtt,(*it),refdb);
+                 }
+         }
+         else if(node->GetLevel()==3)
+         {
+                 RemoveFile(searchAtt,node->GetAttribute("FullFileName"),refdb);
+         }
+         else
+         {
+                 DBRemove("TopLevelNodeId",node->GetAttribute("ID"),refdb);
+         }
+
+
+  }
+  //=====================================================================
+  void TimestampDatabaseHandler::RemoveFile(const std::string& searchAtt, const std::string& searchVal, const std::string& refdb )
+  {
+         
+         std::stringstream result;
+         std::string sel="SELECT PARENT_ID FROM FILES WHERE "+searchAtt+"='"+searchVal+"' AND REFERENCEDDB='"+refdb+"';";
+               
+         CppSQLite3Query q;
+         QUERYTIMESTAMPDB(sel,q);
+       
+         while (!q.eof())
+         {
+           for (int fld = 0; fld < q.numFields(); fld++)
+             {
+                         result<<q.getStringField(fld);
+             }
+           q.nextRow();
+         }
+         DBRemove(searchAtt,searchVal,refdb);
+         
+                 int nChildren=0;
+                 sel="SELECT ID FROM FILES WHERE PARENT_ID='"+result.str()+"'";
+                 CppSQLite3Query q2;
+                 QUERYTIMESTAMPDB(sel,q2);
+                 while (!q2.eof())
+                       {
+                               nChildren++;
+                               q2.nextRow();
+                       }
+                       if(nChildren<1)
+                       {
+                               if(!result.str().compare("0"))
+                               {
+                               RemoveFile("ID",result.str(),refdb);
+                               }
+                               else
+                               {
+                               DBRemove("ID",result.str(),refdb);
+                               }
+                       }
+  }
+
+  //=====================================================================
+  void TimestampDatabaseHandler::DBRemove(const std::string& searchAtt, const std::string& searchVal, const std::string& refdb)
+  {
+       
+    std::string query = "DELETE FROM FILES WHERE "+searchAtt+"='"+ searchVal + "' AND REFERENCEDDB='"+refdb+"';";
+    UPDATETIMESTAMPDB(query);
+  }
+
+   //=====================================================================
+  bool TimestampDatabaseHandler::CheckTimestamp(const std::string pathId, const time_t lastModif, const std::string& refdb)
+  {
+       std::string sel="SELECT LastModified FROM FILES WHERE ID='"+pathId+"' AND REFERENCEDDB='"+refdb+"';";
+       CppSQLite3Query q;
+       QUERYTIMESTAMPDB(sel,q);
+       double timestamp;
+       
+       while (!q.eof())
+         {
+           for (int fld = 0; fld < q.numFields(); fld++)
+             {
+                         timestamp=q.getFloatField(fld);
+             }
+           q.nextRow();
+         }
+
+         
+         std::stringstream lm;
+         lm<<lastModif;
+         double modif=atof((lm.str()).c_str());
+         if(timestamp<modif)
+         {
+                 SetAttribute("LastModified",lm.str(),"ID",pathId);
+                 return true;
+         }
+         return false;  
+  }
+
+  //=====================================================================
+  void TimestampDatabaseHandler::RemoveEntries(const std::string i_table, 
+               const std::string i_attribute, 
+               const std::string i_operand, 
+               const std::string i_val)
+    {
+        std::stringstream query;
+               query<<"DELETE  FROM "<<i_table<<" WHERE "<<i_attribute<<" "<<i_operand<<" '"<<i_val<<"'";
+        UPDATETIMESTAMPDB(query.str());
+       }
+
+}// namespace creaImageIO
+
diff --git a/src/creaImageIOTimestampDatabaseHandler.h b/src/creaImageIOTimestampDatabaseHandler.h
new file mode 100644 (file)
index 0000000..0566141
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef __creaImageIOTimestampDatabaseHandler_h_INCLUDED__
+#define __creaImageIOTimestampDatabaseHandler_h_INCLUDED__
+#include <vector>
+#include <map>
+#include <creaImageIOTree.h>
+class CppSQLite3DB;
+
+namespace creaImageIO
+{
+       using namespace std;
+//=======================================================================
+  /// Concrete TreeHandler which manages a Tree stored in a sqlite database
+  class TimestampDatabaseHandler 
+  {
+  public:
+    //====================================================================
+    /// Ctor with database file name 
+    TimestampDatabaseHandler(const std::string& filename);
+    /// Dtor
+    virtual ~TimestampDatabaseHandler();
+    //====================================================================
+
+    //====================================================================
+    /// Returns the sqlite db file name 
+    const std::string& GetFileName() const { return mFileName; }
+    //====================================================================
+    //====================================================================
+    // INITIALIZATION / FINALIZATION
+    //====================================================================
+
+    //====================================================================
+    /// Opens an existing 'source' 
+     bool Open();
+    /// Closes the 'source'
+    bool Close();
+    /// Creates a new 'source' 
+    bool Create();
+    /// Destroys the 'source'
+    bool Destroy();
+    //====================================================================
+
+       //====================================================================
+    // READ / WRITE
+    //====================================================================
+       //====================================================================
+       ///Returns the id of the path if it's indexed, blank otherwise
+       std::string IsIndexed(const std::string& path, const std::string& refdb);
+    ///Sets the current path's parent
+       bool AddDirectory(const std::string& parent,
+                                  const std::string& path, 
+                                  const time_t lastModif, 
+                                  const time_t lastRead,
+                                  const std::string& refdb);
+       ///Adds a new file to the database without a parent
+       void AddFile(const std::string& path, const time_t lastModif, const time_t lastRead, const std::string& refdb);
+       ///Adds a new file to the database with a parent
+       void AddFile(const std::string& parentId,const std::string& path, const time_t lastModif, const time_t lastRead, const std::string& refdb);
+       ///Sets the attribute to the value passed as parameter where the searchParameter is searchValue
+       void SetAttribute(const std::string& attName, 
+                                       const std::string& attValue,
+                                       const std::string& searchParam,
+                                       const std::string& searchValue);
+       ///Removes the given node
+       void RemoveNode(const std::string& searchAtt, const tree::Node* node, const std::string& refdb);
+       ///Removes the filename with the given pathname
+       void RemoveFile(const std::string& searchAtt, const std::string& searchVal, const std::string& refdb);
+       ///Cleans the path name
+       void CleanPath(std::string& str) const;
+       ///Checks the timestamp in the database and compares it with the given one. 
+       //If there is a difference, it will return false, otherwise it will return true.
+       bool CheckTimestamp(const std::string pathId, const time_t lastModif, const std::string& refdb);
+       ///Removes the entries that match the given parameters
+       void RemoveEntries(const std::string i_table, 
+               const std::string i_attribute, 
+               const std::string i_operand, 
+               const std::string i_val);
+
+       //====================================================================
+
+
+  protected:
+    //======================================================================
+    /// Open the database
+    bool DBOpen();
+    //======================================================================
+    //======================================================================
+    // Creation
+    /// Creates a new database on disk and the tables
+    bool DBCreate();
+    //======================================================================
+       //======================================================================
+    // Removes a file from the database
+       void DBRemove(const std::string& searchAtt, const std::string& searchVal, const std::string& refdb);
+  private:
+    /// The DB
+    CppSQLite3DB* mDB;
+   /// The physical location associated to the DicomDatabase (directory, db file...)
+    std::string mFileName;
+  
+  };
+  // EO class
+  //=======================================================================
+
+
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
+
diff --git a/src/creaImageIOTree.cpp b/src/creaImageIOTree.cpp
new file mode 100644 (file)
index 0000000..c2456a0
--- /dev/null
@@ -0,0 +1,34 @@
+#include <creaImageIOTree.h>
+#include <creaImageIOSystem.h>
+
+
+namespace creaImageIO
+{
+  namespace tree
+  {
+    
+    Tree::Tree()
+      : Node(0)
+    {
+      GimmickMessage(5,"Default Tree constructor"
+                    << std::endl);
+    
+    }
+    
+    Tree::~Tree()
+    {
+      
+    }
+
+    void Tree::Print() const
+    {
+      GimmickMessage(1,GetLabel()<<std::endl);
+      ChildrenListType::const_iterator i;
+      for (i=GetChildrenList().begin(); i!=GetChildrenList().end(); i++)
+       {
+         (*i)->Print();
+       }
+      
+    }
+  }
+}
diff --git a/src/creaImageIOTree.h b/src/creaImageIOTree.h
new file mode 100644 (file)
index 0000000..de5b94a
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef __creaImageIOTree_h_INCLUDED__
+#define __creaImageIOTree_h_INCLUDED__
+
+#include <creaImageIOTreeNode.h>
+
+namespace creaImageIO
+{
+
+  namespace tree
+  {
+    /**
+     * \ingroup Tree
+     */
+    //=====================================================================
+    /// Abstract class to store user data on a Tree
+    struct TreeData
+    { 
+      TreeData() {}
+      virtual ~TreeData() {}
+    };
+    //=====================================================================
+    
+    //=====================================================================
+    /// An attributed Tree structure
+    /** \ingroup Tree
+     */
+    class Tree : public Node
+    {
+    public:
+      /// Ctor
+      Tree();
+      /// Virtual destructor
+      virtual ~Tree();
+      
+      /// Returns the descriptor of the tree
+    
+      /// Returns the tree to which the node belongs
+      virtual Tree* GetTree() { return this; }
+      /// Returns the tree to which the node belongs
+      virtual const Tree* GetTree() const { return this; }
+      /// Returns the level of the node in the tree
+      virtual int GetLevel() const { return 0; }
+      
+      /// Returns the Descriptor of the tree (const)
+      const Descriptor& GetDescriptor() const { return mDescriptor; }
+      /// Returns the descriptor of the tree 
+      Descriptor& GetDescriptor() { return mDescriptor; }
+
+     /// Returns the number of levels of the tree
+      unsigned int GetNumberOfLevels() 
+      { return GetDescriptor().GetNumberOfLevels(); }
+
+      /// Returns the LevelDescriptor of a given level (const ref)
+      const LevelDescriptor& GetLevelDescriptor(int level) const
+      { return GetDescriptor().GetLevelDescriptor(level); }
+
+      /// Returns the AttributeDescriptorList of a given level (const ref)
+      const LevelDescriptor::AttributeDescriptorListType& 
+      GetAttributeDescriptorList(int level) const
+      { return GetDescriptor().GetAttributeDescriptorList(level); }
+  
+      virtual void Print() const;
+
+    private:
+      Descriptor mDescriptor;
+
+    };
+    // EO class Tree
+    //=====================================================================
+
+  } // EO namespace tree
+  
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
diff --git a/src/creaImageIOTreeAttributeDescriptor.cpp b/src/creaImageIOTreeAttributeDescriptor.cpp
new file mode 100644 (file)
index 0000000..3e09a4f
--- /dev/null
@@ -0,0 +1,274 @@
+#include <creaImageIOTreeAttributeDescriptor.h>
+#include <creaImageIOSystem.h>
+
+
+#if defined(USE_GDCM)
+#include <gdcmGlobal.h>
+#include <gdcmDictSet.h>
+#endif
+
+#if defined(USE_GDCM2)
+#include <gdcmGlobal.h>
+#include <gdcmDicts.h>
+#include <gdcmDict.h>
+#endif
+
+#include <boost/algorithm/string/replace.hpp>
+
+namespace creaImageIO
+{
+
+  namespace tree
+  {
+
+    //========================================================================
+    void AttributeDescriptor::CleanName(std::string& str) const
+    {
+      // quote must be doubled for SQL
+      //    crea::Utils::Replace( str, "'", "''" );
+      boost::algorithm::replace_all(str,"'","''");
+      // Found strange strings which contained NULL char INSIDE string 
+      int i,size=str.size();
+      for (i=0;i<size;++i) 
+       {
+         if (str[i]==0) 
+           {
+             str = str.substr(0,i);
+             break;
+           }
+       }
+    }
+    //========================================================================
+
+    //=====================================================================
+    // Ctor with key, name and flags
+     AttributeDescriptor::AttributeDescriptor(const std::string& key,
+                                            const std::string& name,
+                                            unsigned int flags)
+      : mKey(key), mName(name), mGroup(0), mElement(0), mFlags(flags)
+    {
+
+      CleanName(mName);
+      GimmickDebugMessage(3,"AttributeDescriptor : '"<<key
+                         <<"' ["<<flags<<"]"<<std::endl);
+      GimmickDebugMessage(3,"='"<<mName<<"'"<<std::endl);
+    }
+
+    //=====================================================================
+
+     //=====================================================================
+   // Ctor with dicom group, elem and flags
+    // The key is built as 'Dgroup_elem'
+    // The user name is retreived from dicom dictionnary
+    AttributeDescriptor::AttributeDescriptor(unsigned short group,
+                                            unsigned short element,
+                                            unsigned int flags)
+      : mGroup(group), mElement(element), mFlags(flags)
+    {
+      
+      //GDCM_NAME_SPACE::TagKey tag(group,element);
+      char ctag[12];
+      sprintf(ctag,"D%04x_%04x",group,element);
+      mKey = ctag;
+
+      GimmickDebugMessage(3,"AttributeDescriptor : '"<<mKey
+                         <<"' ["<<flags<<"]"<<std::endl);
+
+#if defined(USE_GDCM)
+      // Retrieve the name from gdcm dict
+      GDCM_NAME_SPACE::DictEntry* entry =
+       GDCM_NAME_SPACE::Global::GetDicts()
+       ->GetDefaultPubDict()->GetEntry(mGroup,mElement);
+         
+      if (entry)
+       {
+         mName = entry->GetName();
+         CleanName(mName);
+         GimmickDebugMessage(3,"='"<<mName<<"'"<<std::endl);
+       }
+      else
+       {
+         GimmickMessage(1,"!! WARNING : tag '"<<mKey
+                        <<"' is not in DICOM dictionnary ! "
+                        <<"Considering it as a user attribute"
+                        << std::endl);
+         mName = "UNKNOWN";
+         mGroup = mElement = 0;
+       }
+#endif
+
+
+         
+         
+#if defined(USE_GDCM2)
+      // Retrieve the name from gdcm dict
+       const gdcm::Global& g = gdcm::Global::GetInstance(); 
+        const gdcm::Dicts &dicts = g.GetDicts();
+  const gdcm::Dict &dict = dicts.GetPublicDict();
+         gdcm::DictEntry dictentry =  dict.GetDictEntry(gdcm::Tag(mGroup, mElement));
+         
+      mName = dictentry.GetName();
+         if(!mName.empty())
+         {
+                 CleanName(mName);
+                 GimmickDebugMessage(3,"='"<<mName<<"'"<<std::endl);
+         }
+      else
+         {
+               GimmickMessage(1,"!! WARNING : tag '"<<mKey
+                        <<"' is not in DICOM dictionnary ! "
+                        <<"Considering it as a user attribute"
+                        << std::endl);
+               mName = "UNKNOWN";
+               mGroup = mElement = 0;
+               }
+#endif
+
+    }
+    //=====================================================================
+
+
+    //=====================================================================
+    /// Extracts group and element from a key of the form "Dgroup_elem" 
+    void AttributeDescriptor::GetDicomGroupElementFromKey(const std::string& key,
+                                                         unsigned short& group,
+                                                         unsigned short& elem)
+    {
+      group = elem = 0;
+      if ( (key.size()==10) &&
+          (key[0] == 'D') &&
+          (key[5] == '_') )
+         {
+        sscanf(key.c_str(),"D%04hx_%04hx ",&group,&elem);  
+         GimmickDebugMessage(3,"GetDicomGroupElementFromKey '"<<key<<"' : "                     <<group<<"|"<<elem<<std::endl);
+       }
+      else 
+       { 
+         GimmickMessage(5,"GetDicomGroupElementFromKey '"<<key<<"' : "
+                        <<" not a DICOM key format"<<std::endl);
+       }
+      return;
+    }
+
+       //=====================================================================
+       /// test if the type is a date
+       bool AttributeDescriptor::isDateEntry() const
+       {
+                
+               bool btest = false;
+               // Retrieve the name from gdcm dict
+#if defined(USE_GDCM)
+               GDCM_NAME_SPACE::DictEntry* entry =     GDCM_NAME_SPACE::Global::GetDicts()->GetDefaultPubDict()->GetEntry(GetGroup(),GetElement());
+               if(     entry != 0)
+               {
+                       if( entry->GetVR().str() == "DA" )
+                       {
+                               btest = true;
+                       }
+               }
+#endif
+#if defined(USE_GDCM2)
+        const gdcm::Global& g = gdcm::Global::GetInstance(); 
+        const gdcm::Dicts &dicts = g.GetDicts();
+  const gdcm::Dict &dict = dicts.GetPublicDict();
+         if(mGroup != 0 && mElement != 0)
+         {
+                 gdcm::DictEntry dictentry =  dict.GetDictEntry(gdcm::Tag(GetGroup(), GetElement()));
+               if( gdcm::VR::GetVRString(dictentry.GetVR()) == "DA")
+               {
+                               btest = true;
+               }
+         }
+#endif
+               return btest;
+       }
+
+       //=====================================================================
+       /// test if the type is a time
+       bool AttributeDescriptor::isTimeEntry() const
+       {
+                
+               bool btest = false;
+#if defined(USE_GDCM)
+               // Retrieve the name from gdcm dict
+               GDCM_NAME_SPACE::DictEntry* entry =     GDCM_NAME_SPACE::Global::GetDicts()->GetDefaultPubDict()->GetEntry(GetGroup(),GetElement());
+               if(     entry != 0)
+               {
+                       if( entry->GetVR().str() == "TM" )
+                       {
+                               btest = true;
+                       }
+               }
+#endif
+
+#if defined(USE_GDCM2)
+        const gdcm::Global& g = gdcm::Global::GetInstance(); // sum of all knowledge !
+        const gdcm::Dicts &dicts = g.GetDicts();
+  const gdcm::Dict &dict = dicts.GetPublicDict(); // Part 6
+         if(mGroup != 0 && mElement != 0)
+         {
+               gdcm::DictEntry dictentry =  dict.GetDictEntry(gdcm::Tag(mGroup, mElement));
+               if(gdcm::VR::GetVRString(dictentry.GetVR()) == "TM")
+               {
+                               btest = true;
+               }
+         }
+#endif
+
+               return btest;
+       }
+
+
+    //=====================================================================
+       /// Decodes the type of the attribute
+     void AttributeDescriptor::DecodeType(unsigned int& typ) const
+         {
+                std::string type=""; 
+#if defined(USE_GDCM)  
+                 // Retrieve the name from gdcm dict
+               GDCM_NAME_SPACE::DictEntry* entry =
+               GDCM_NAME_SPACE::Global::GetDicts()
+               ->GetDefaultPubDict()->GetEntry(GetGroup(),GetElement());
+
+               if (entry==0) 
+               {
+                       typ = 2;
+                       return;
+               }
+                type = entry->GetVR().str();
+#endif
+#if defined(USE_GDCM2)
+        const gdcm::Global& g = gdcm::Global::GetInstance(); // sum of all knowledge !
+        const gdcm::Dicts &dicts = g.GetDicts();
+  const gdcm::Dict &dict = dicts.GetPublicDict(); // Part 6
+         gdcm::DictEntry dictentry =  dict.GetDictEntry(gdcm::Tag(mGroup, mElement));
+         type = gdcm::VR::GetVRString(dictentry.GetVR());
+#endif
+
+               GimmickDebugMessage(3,"VR Value is "<<type<<"!"<<std::endl);
+               if(type=="AS" ||
+               type=="DA" ||
+               type=="FL" ||
+               type=="FD" ||
+               type=="IS" ||
+               type=="SL" ||
+               type=="SS" ||
+               type=="UI" ||
+               type=="US" ||
+               type=="SH")
+               {
+                       // Numerical 
+                       typ = 1;
+               }
+               else
+               {
+                       // String
+                       typ = 2;
+               }
+               
+         }
+         //=====================================================================
+
+  } // EO namespace tree
+
+} // EO namespace creaImageIO
diff --git a/src/creaImageIOTreeAttributeDescriptor.h b/src/creaImageIOTreeAttributeDescriptor.h
new file mode 100644 (file)
index 0000000..1ae86dd
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef __creaImageIOTreeAttributeDescriptor_h_INCLUDED__
+#define __creaImageIOTreeAttributeDescriptor_h_INCLUDED__
+
+#include <string>
+//#include <iostream>
+
+namespace creaImageIO
+{
+
+  namespace tree
+  {
+         /**
+       * \ingroup Tree
+       */
+    //=====================================================================
+    /// Descriptor of an attribute of a node of a Tree (name, dicom group/element)
+    class AttributeDescriptor
+    {    
+    public:
+      /// Flags
+      /// The attribute is hidden (not visible to user)
+      static const unsigned int PRIVATE;
+      /// The attribute enters in unique identifier constitution 
+      static const unsigned int IDENTIFIER;
+      /// The attribute enters in label constitution (for printing)
+      static const unsigned int LABEL;
+          /// The attribute can be edited
+      static const unsigned int EDITABLE;
+
+         /// Types
+      /// The attribute is of numeric type
+      static const int NUMBER=1;
+      /// The attribute is of string type
+      static const int STRING=2;
+         /// The attribute's type is unknown
+      static const int UNKNOWN=0;
+
+      /// Default ctor
+      AttributeDescriptor()
+       : mKey(""), mName(""), mGroup(0), mElement(0), mFlags(0)
+      {
+      }
+      /// Ctor with all explicitely
+      AttributeDescriptor(const std::string& key,
+                         const std::string& name,
+                         unsigned short group,
+                         unsigned short element,
+                         unsigned int flags)
+       : mKey(key), mName(name), mGroup(group), mElement(element), 
+         mFlags(flags)
+      {
+      }
+
+      // Ctor with key, name and flags
+      AttributeDescriptor(const std::string& key,
+                         const std::string& name,
+                         unsigned int flags = 0);
+      // Ctor with dicom group, elem and flags
+      // The key is built as 'Dgroup_elem'
+      // The user name is retreived from dicom dictionnary
+      AttributeDescriptor(unsigned short group,
+                         unsigned short element,
+                         unsigned int flags = 0);
+      /// Returns the key of the attribute
+      const std::string& GetKey() const { return mKey; }
+      /// Returns the name of the attribute
+      const std::string& GetName() const { return mName; }
+      /// Returns the DICOM group code of the attribute
+      unsigned short GetGroup() const { return mGroup; }
+      /// Returns the DICOM element code of the attribute
+      unsigned short GetElement() const { return mElement; }
+      /// Returns the flags of the attribute
+      unsigned int GetFlags() const { return mFlags; }
+         
+      /// Extracts group and element from a key of the form "Dgroup_elem" 
+      static void GetDicomGroupElementFromKey(const std::string& key,
+                                             unsigned short& group,
+                                             unsigned short& elem);
+      /// Cleans the name:
+      /// Replace simple quote by double quotes
+      /// Cut string at NULL chars 
+      void CleanName(std::string& str) const;
+         ///Decodes the type of attribute into the existing ones
+         void DecodeType(unsigned int& type) const;
+
+         /// Determines if Attribute is a date
+         bool isDateEntry() const;
+
+         /// Determines if Attribute is a time
+         bool isTimeEntry() const;
+
+    private:
+      std::string mKey;
+      std::string mName;
+      unsigned short mGroup;
+      unsigned short mElement;
+      unsigned int mFlags;
+    };
+    // EO class AttributeDescriptor
+    //=====================================================================
+
+   
+
+  } // EO namespace tree
+
+} // EO namespace creaImageIO
+
+
+
+
+
+#endif // #ifndef __creaImageIOTreeAttributeDescriptor_h_INCLUDED__
diff --git a/src/creaImageIOTreeAttributeMapType.h b/src/creaImageIOTreeAttributeMapType.h
new file mode 100644 (file)
index 0000000..16cac8c
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __creaImageIOTreeAttributeMapType_h_INCLUDED__
+#define __creaImageIOTreeAttributeMapType_h_INCLUDED__
+
+#include <map>
+#include <string>
+#include <iostream>
+
+namespace creaImageIO
+{
+
+       /**
+       * \ingroup Tree
+       */
+  namespace tree
+  {
+    typedef std::map<std::string,std::string> AttributeMapType;
+
+
+
+
+  }
+
+}
+
+//=====================================================================
+inline std::ostream& operator<<(std::ostream& s, 
+                               const creaImageIO::tree::AttributeMapType& d)
+{
+  creaImageIO::tree::AttributeMapType::const_iterator i;
+  for (i=d.begin();i!=d.end();++i)
+    {
+      s << "'" << i->first << "'='" << i->second << "'" << std::endl;
+    }
+  return s;
+}
+//=====================================================================
+
+
+#endif
diff --git a/src/creaImageIOTreeComparators.cpp b/src/creaImageIOTreeComparators.cpp
new file mode 100644 (file)
index 0000000..7d64496
--- /dev/null
@@ -0,0 +1 @@
+#include <creaImageIOTreeComparators.h>
diff --git a/src/creaImageIOTreeComparators.h b/src/creaImageIOTreeComparators.h
new file mode 100644 (file)
index 0000000..f606470
--- /dev/null
@@ -0,0 +1,225 @@
+#ifndef __creaImageIOTreeNodeComparators_h_INCLUDED__
+#define __creaImageIOTreeNodeComparators_h_INCLUDED__
+
+#include <vector>
+#include <iostream>
+
+namespace creaImageIO
+{
+
+  namespace tree
+  {
+
+    
+    class Node;
+    
+    
+       /**
+       * \ingroup Tree
+       */
+  //=====================================================================
+    /// Abstract definition of a comparator of Node
+  struct Comparator
+  {
+    virtual ~Comparator() {}
+    virtual bool operator() (Node* const & x, Node* const & y) = 0;
+  };
+  //=====================================================================
+
+
+
+  //=====================================================================
+    /// Abstract Comparator whose order can be reversed
+  struct ComparatorWithOrder : public Comparator
+  {
+    ComparatorWithOrder(bool reverse_order = false) 
+      : mReverseOrder(reverse_order) {}
+    virtual ~ComparatorWithOrder() {}
+
+
+    virtual bool compare(Node* const &, Node* const &) = 0;
+
+    virtual bool operator() (Node* const & x, Node* const & y)
+    {
+      if (mReverseOrder) return this->compare(y,x);
+      return this->compare(x,y);
+    };
+
+    bool mReverseOrder;
+  };
+  //=====================================================================
+
+
+
+  //=====================================================================
+    /// A Comparator which stores a vector of Comparators and 
+                              /// which performs lexicographical comparison
+  class LexicographicalComparator : public Comparator
+  {
+  public:
+    LexicographicalComparator(const std::string& name) 
+      : mName(name) {}
+    ~LexicographicalComparator() {}
+
+    const std::string& GetName() const { return mName; }
+    void SetName(const std::string& s) { mName = s; }
+    void Clear() { mComparator.clear(); }
+    void DeleteComparators() 
+    { 
+       std::vector<Comparator*>::iterator i;
+       for (i =mComparator.begin();
+           i!=mComparator.end();
+           ++i)
+        {
+          delete *i;
+        }
+       mComparator.clear(); 
+    }
+    void Add(Comparator* c) { mComparator.push_back(c); }
+    
+    bool operator() (Node* const & x, Node * const & y);
+
+  private:
+    std::string mName;
+    std::vector<Comparator*> mComparator;
+  };
+  //=====================================================================
+
+
+
+
+  //=================================================================== 
+    /// Comparator which compares the values of a given Attribute of the Nodes which is decoded as an int value
+  struct IntComparator : 
+    public ComparatorWithOrder
+  {    
+    IntComparator(const std::string& key,
+                                    bool reverse_order)
+      :
+      ComparatorWithOrder(reverse_order),
+      mKey(key)
+    {}
+    virtual bool compare(Node* const & x, Node* const & y);
+
+  private:
+    std::string mKey;
+  };
+  //===================================================================
+
+  //===================================================================
+    /// Comparator which compares the values of a given Attribute of the Nodes which is decoded as an float value
+  struct FloatComparator : 
+    public ComparatorWithOrder
+  {    
+    FloatComparator(const std::string& key,
+                                      bool reverse_order )
+      : 
+      ComparatorWithOrder(reverse_order),
+      mKey(key)
+    {}
+
+    virtual bool compare(Node* const & x, Node* const & y);
+
+  private:
+    std::string mKey;
+  };
+  //===================================================================
+
+  //===================================================================
+    /// Comparator which compares the values of a given Attribute of the Nodes which is decoded as a string value
+  struct StringComparator : 
+    public ComparatorWithOrder
+  {    
+    StringComparator(const std::string& key,
+                                  bool reverse_order )
+      : 
+      ComparatorWithOrder(reverse_order),
+      mKey(key)
+    {}
+    
+    virtual bool compare(Node* const & x, Node* const & y);
+    
+  private:
+    std::string mKey;
+  };
+  //===================================================================
+
+  //===================================================================
+#define INT_FIELD_COMP(NAME,FIELD)     \
+  struct Node##NAME##Comparator :      \
+    public IntComparator       \
+  {                                            \
+    Node##NAME##Comparator(bool o = false) :   \
+      IntComparator(FIELD,o)   \
+    {}                                         \
+  }
+  //==================================================================
+  
+  //===================================================================
+#define FLOAT_FIELD_COMP(NAME,FIELD)           \
+  struct Node##NAME##Comparator :      \
+    public FloatComparator     \
+  {                                            \
+    Node##NAME##Comparator(bool o = false) :   \
+      FloatComparator(FIELD,o) \
+    {}                                         \
+  }
+  //===================================================================
+
+  //===================================================================
+#define STRING_FIELD_COMP(NAME,FIELD)          \
+  struct Node##NAME##Comparator :      \
+    public StringComparator    \
+  {                                            \
+    Node##NAME##Comparator(bool o = false) :   \
+      StringComparator(FIELD,o)        \
+    {}                                         \
+  }
+  //===================================================================
+
+
+
+  //===================================================================
+  // Patient comparators
+  ///Compares the names of the patients
+  STRING_FIELD_COMP(PatientName,"A0010_0010");
+  ///Compares the sex of the patients
+  STRING_FIELD_COMP(PatientSex, "A0010_0040");
+  ///Compares the birthdays of the patients
+  STRING_FIELD_COMP(PatientBirthday, "A0010_0030");
+  //===================================================================
+
+  //===================================================================
+  // Study comparators
+  ///Compares the dates of the studies
+  STRING_FIELD_COMP(StudyDate,"A0008_0020");
+  ///Compares the description of the studies
+  STRING_FIELD_COMP(StudyDescription,"A0008_1030");
+  //===================================================================
+
+  //===================================================================
+  // Series comparators
+  ///Compares the modality of the series
+  STRING_FIELD_COMP(Modality,"A0008_0060");
+  ///Compares the description of the series
+  STRING_FIELD_COMP(SeriesDescription,"A0008_103E");
+  ///Compares the date of the series
+  STRING_FIELD_COMP(SeriesDate,"A0008_0021");
+  //===================================================================
+
+  //===================================================================
+  // Image comparators
+  ///Compares the number of the images
+  INT_FIELD_COMP(ImageNumber,"A0020_0013");
+  ///Compares the location of the images
+  FLOAT_FIELD_COMP(SliceLocation,"A0020_1041");
+  ///Compares the filename of the images
+  STRING_FIELD_COMP(FullFileName,"FullFileName");
+  //===================================================================
+  } // namespace tree
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIOComparators_h_INCLUDED__
diff --git a/src/creaImageIOTreeDescriptor.cpp b/src/creaImageIOTreeDescriptor.cpp
new file mode 100644 (file)
index 0000000..8524794
--- /dev/null
@@ -0,0 +1,276 @@
+#include <creaImageIOTreeDescriptor.h>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <creaImageIOSystem.h>
+#include <boost/filesystem.hpp>
+
+
+#include <fstream>
+
+
+namespace creaImageIO
+{
+
+  namespace tree
+  {
+
+    //==================================================================
+    /// The attribute is hidden (not visible to user)
+    const unsigned int AttributeDescriptor::PRIVATE = 1;
+    /// The attribute enters in unique identifier constitution 
+    const unsigned int AttributeDescriptor::IDENTIFIER = 2;
+    /// The attribute can be edited
+    const unsigned int AttributeDescriptor::EDITABLE = 3;
+    /// the attribute describes the node
+    const unsigned int AttributeDescriptor::LABEL = 4;
+    //==================================================================
+
+    //==================================================================
+    Descriptor::Descriptor()
+    {
+      CreateLevel0Descriptor();
+    }
+    //==================================================================
+
+   //==================================================================
+    Descriptor::~Descriptor()
+    {
+    }
+    //==================================================================
+
+    //==================================================================
+    void Descriptor::CreateLevel0Descriptor()
+    {
+      Add(LevelDescriptor("Root"));
+    }
+    //==================================================================
+    
+    //==================================================================
+    /// Creates the default descriptor
+    void Descriptor::CreateDefault()
+    {
+      // clears the existing one
+      Clear();
+      
+      // Creates the level 0 descriptor 
+      CreateLevel0Descriptor();
+      // Creates the attribute "Name"
+      Add(AttributeDescriptor("Name","Name",
+                             AttributeDescriptor::LABEL),0);
+      
+      // Patient level
+      Add(LevelDescriptor("Patient"));
+      Add(AttributeDescriptor("NumberOfChildren","#Series",0),1);   // Number of Series
+      Add(AttributeDescriptor(0x0010,0x0010,   // Patient name
+                             AttributeDescriptor::LABEL),1);
+      Add(AttributeDescriptor(0x0010,0x0040),1); // Patient sex
+      Add(AttributeDescriptor(0x0010,0x0030),1); // Patient birthday
+      Add(AttributeDescriptor(0x0010,0x0020,   // Patient ID
+                             AttributeDescriptor::IDENTIFIER),1);
+
+      // Study-series level
+      Add(LevelDescriptor("Series"));
+      Add(AttributeDescriptor("NumberOfChildren","#Images",0),2);   // Number of images
+      Add(AttributeDescriptor(0x0008,0x0060,    // Modality
+                             AttributeDescriptor::LABEL),2);
+      Add(AttributeDescriptor(0x0008,0x1030),2); // Study Description
+      Add(AttributeDescriptor(0x0008,0x103E),2); // Description
+      Add(AttributeDescriptor(0x0008,0x0080),2); // Institution Name
+      Add(AttributeDescriptor(0x0008,0x0081),2); // Institution Adress
+      Add(AttributeDescriptor(0x0008,0x1010),2); // Station Name
+      Add(AttributeDescriptor(0x0008,0x1048),2); // Physician of Record
+      Add(AttributeDescriptor(0x0008,0x1050),2); // Performing Physician's Name
+      Add(AttributeDescriptor(0x0018,0x1030),2); // Protocol Name
+
+      Add(AttributeDescriptor(0x0020,0x0010),2); // Study ID
+      Add(AttributeDescriptor(0x0008,0x0020),2); // Study Date
+      Add(AttributeDescriptor(0x0008,0x0030),2); // Study Time
+      Add(AttributeDescriptor(0x0008,0x0050),2); // Study Accession Number
+      Add(AttributeDescriptor(0x0008,0x0005),2); // Specific character set
+      Add(AttributeDescriptor(0x0008,0x0021),2); // Series Date
+      Add(AttributeDescriptor(0x0008,0x0031),2); // Series time
+
+      Add(AttributeDescriptor(0x0020,0x000D   // Study Instance UID  
+                                                   ),2);//AttributeDescriptor::IDENTIFIER),2);
+      Add(AttributeDescriptor(0x0020,0x000E,   // Series Instance UID  
+                               AttributeDescriptor::IDENTIFIER),2);
+      // |
+      //                       AttributeDescriptor::LABEL),2);
+     
+
+      // Image level
+      Add(LevelDescriptor("Image"));
+
+      Add(AttributeDescriptor(0x0020,0x0013),3); // Image Number
+
+      Add(AttributeDescriptor(0x0028,0x0010),3); // Rows
+      Add(AttributeDescriptor(0x0028,0x0011),3); // Columns
+      Add(AttributeDescriptor(0x0028,0x0012),3); // Planes
+      Add(AttributeDescriptor(0x0028,0x0002),3); // Sample per pixels
+      Add(AttributeDescriptor(0x0028,0x0008),3); // Number of Frames 
+      Add(AttributeDescriptor(0x0028,0x0004),3); // Photometric Interpretation
+      Add(AttributeDescriptor(0x0028,0x0103),3); // Pixel Representation
+
+      Add(AttributeDescriptor(0x0020,0x0032),3); // Image Position Patient
+      Add(AttributeDescriptor(0x0020,0x0037),3); // Image Orientation Patient
+      Add(AttributeDescriptor(0x0020,0x1041),3); // Slice Location
+      Add(AttributeDescriptor(0x0028,0x0006),3); // Planar Configuration
+
+      Add(AttributeDescriptor(0x0028,0x0030),3); // Pixel Spacing
+      Add(AttributeDescriptor(0x0028,0x0100),3); // AlocatedBits
+      Add(AttributeDescriptor(0x0028,0x0101),3); // StoredBits
+
+      Add(AttributeDescriptor(0x0008,0x0008),3); // Image Type
+      Add(AttributeDescriptor(0x0008,0x0023),3); // Content Date
+      Add(AttributeDescriptor(0x0008,0x0033),3); // Content Time
+
+      Add(AttributeDescriptor(0x0020,0x4000),3); // Image Comments
+
+      Add(AttributeDescriptor(0x0004,0x1500,   // File Name
+                               AttributeDescriptor::LABEL),3);
+      Add(AttributeDescriptor(0x0028,0x1052),3); // Rescale Intercept
+      Add(AttributeDescriptor(0x0028,0x1053),3); // Rescale Slope
+
+      Add(AttributeDescriptor(0x0050,0x0004),3); // Calibration Image
+
+      Add(AttributeDescriptor(0x0020,0x0052   // Frame Reference UID
+                                          ),3);
+      Add(AttributeDescriptor(0x0008,0x0016),3); // SOP Class UID
+      Add(AttributeDescriptor("FullFileName",  // Full file name
+                               "Full file name",
+                               AttributeDescriptor::IDENTIFIER),3); 
+
+    }
+
+       //////////////////////////////////////////////////////////////
+       // create a descriptor (name, attributes...) from a file)       //
+       // @param : file path                                           //
+       // return : -                                                   //
+       //////////////////////////////////////////////////////////////
+       void Descriptor::createDescriptorfromFile(const std::string &i_name)
+       {
+               Clear();
+               
+               // read file and put in buffer
+               std::ifstream i_file(i_name.c_str());
+               std::stringstream buffer;
+               buffer << i_file.rdbuf();
+               std::string line;
+               bool bname;
+               int ilevel = -1;
+
+               
+               while(std::getline(buffer, line))
+               {
+                       if(line =="<level>")
+                       {       //increment levels.
+                               ilevel++;
+                               bname = true;
+                       }
+                       else if(bname)
+                       {
+                               // For each level, a name to describe it
+                               Add(LevelDescriptor(line));
+                               bname = false;
+                       }
+                       else if(line.empty()) // to avoid end line
+                       {
+                               return;
+                       }
+                       else
+                       { 
+                               // split line to find all tags
+                               std::vector<std::string> descriptors;
+                               std::string separator = " ";
+                               std::string::size_type last_pos = line.find_first_not_of(separator);
+                               //find first separator
+                               std::string::size_type pos = line.find_first_of(separator, last_pos);
+                               while(std::string::npos != pos || std::string::npos != last_pos)
+                               {
+                                       descriptors.push_back(line.substr(last_pos, pos - last_pos));
+                                       last_pos = line.find_first_not_of(separator, pos);
+                                       pos = line.find_first_of(separator, last_pos);
+                               }
+                               
+                               // By default, the last tag is at zero and not recorded but if take in count
+                               unsigned int flag = 0;
+                               if(descriptors.size() == 4)
+                               {
+                                       std::stringstream val;
+                                       val << std::dec << descriptors[3];
+                                       val>> flag;
+                               }
+
+                               // if Dicom tag, use "group" and "element" descriptor
+                               if(descriptors[0] == "D")
+                               {       std::stringstream val, val2;
+                                       unsigned short group;
+                                       unsigned short element;
+                                       val <<   std::dec << descriptors[1] ;
+                                       val >> std::hex >> group;
+                                       val2 << std::dec <<  descriptors[2];
+                                       val2 >> std::hex >> element;
+                                       Add(AttributeDescriptor( group,element,flag), ilevel);
+                               }
+
+                               else if(descriptors[0].find("#") != -1)
+                               {
+                                       // commented line continue to next line
+                               }
+                               else
+                               {       boost::algorithm::replace_all(descriptors[2],"_"," ");
+                                       Add(AttributeDescriptor( descriptors[1].c_str(),descriptors[2].c_str(),flag), ilevel);
+                               }
+                       }
+               }
+       }
+
+    //==================================================================
+
+    //==================================================================
+    /// Adds a LevelDescriptor at the end of the list
+    void Descriptor::Add(const LevelDescriptor& d)
+    {
+      mLevelDescriptorList.push_back(d);
+    }
+    //==================================================================
+    
+    //==================================================================  
+    /// Adds an AttributeDescriptor to level l
+    void Descriptor::Add(const AttributeDescriptor& d, int l)
+    {
+      mLevelDescriptorList[l].Add(d);
+      // TO DO : update DicomTagToName and NameToDicomTag map
+    }
+    //==================================================================
+
+    //==================================================================
+    /// Clears the Descriptor
+    void Descriptor::Clear()
+    {
+      mLevelDescriptorList.clear();
+    }
+
+    //==================================================================
+
+    //==================================================================
+    /// Builds the key to value map of all the attributes of the tree
+    void Descriptor::BuildAttributeMap( std::map<std::string,std::string>& map ) const
+    {
+      map.clear();
+      LevelDescriptorListType::const_iterator l;
+      for (l = GetLevelDescriptorList().begin();
+          l!= GetLevelDescriptorList().end();
+          ++l)
+       {
+         LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+         for (a = l->GetAttributeDescriptorList().begin();
+              a!= l->GetAttributeDescriptorList().end();
+              ++a)
+           {
+             map[a->GetKey()]="";
+           }
+       }
+    }
+  }
+}
diff --git a/src/creaImageIOTreeDescriptor.h b/src/creaImageIOTreeDescriptor.h
new file mode 100644 (file)
index 0000000..a7e5b94
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef __creaImageIOTreeDescriptor_h_INCLUDED__
+#define __creaImageIOTreeDescriptor_h_INCLUDED__
+
+#include <creaImageIOTreeAttributeMapType.h>
+#include <creaImageIOTreeLevelDescriptor.h>
+
+
+namespace creaImageIO
+{
+       using namespace std;
+  namespace tree
+  {
+    
+    /**
+     * \ingroup Tree
+     */
+    
+       ///Descriptor of the structure of a Tree (number of levels, descriptors of each level, ...). 
+         //Any Tree has at least one level (level 0) of name "Root"
+     
+    class Descriptor
+    {
+    public:
+      /// Ctor : creates the mandatory level 0 descriptor called "Root"
+      Descriptor();
+      /// Destructor
+      ~Descriptor();
+
+      /// Loads from a xml description file
+      void LoadXML(const std::string& filename);
+      /// Creates the default descriptor
+      void CreateDefault();
+
+      /// Returns the number of levels of the tree
+      unsigned int GetNumberOfLevels() 
+      { return mLevelDescriptorList.size(); }
+
+      /// Returns the LevelDescriptor of a given level (const ref)
+      const LevelDescriptor& GetLevelDescriptor(int level) const
+      { return mLevelDescriptorList[level]; }
+
+      /// Returns the AttributeDescriptorList of a given level (const ref)
+      const LevelDescriptor::AttributeDescriptorListType& 
+      GetAttributeDescriptorList(int level) const
+      { return mLevelDescriptorList[level].GetAttributeDescriptorList(); }
+  
+
+      /// Adds a LevelDescriptor at the end of the list
+      void Add(const LevelDescriptor&);
+      
+      /// Adds an AttributeDescriptor to level l
+      void Add(const AttributeDescriptor&, int l);
+      
+      
+      /// Builds the key to value map of all the attributes of the tree
+       void BuildAttributeMap( AttributeMapType& ) const;
+
+      /// The type of LevelDescriptor container
+       typedef std::vector<LevelDescriptor> LevelDescriptorListType;
+      /// Returns the list of tree levels (const)
+       const LevelDescriptorListType& GetLevelDescriptorList() const { return mLevelDescriptorList; }
+
+      /// Clears the Descriptor
+      void Clear();
+
+         //Create Attribute Descriptors from a file
+       void createDescriptorfromFile(const std::string &i_file);
+
+    private:
+      LevelDescriptorListType mLevelDescriptorList;
+      /// Creates the mandatory level 0 descriptor called "Root"
+      /// (assumes the list is empty)
+      void CreateLevel0Descriptor();
+  
+    };
+    // EO class Descriptor
+    //=====================================================================
+  } // EO namespace tree
+
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
diff --git a/src/creaImageIOTreeHandler.h b/src/creaImageIOTreeHandler.h
new file mode 100644 (file)
index 0000000..b84d0f9
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef __creaImageIOTreeHandler_h_INCLUDED__
+#define __creaImageIOTreeHandler_h_INCLUDED__
+
+#include <creaImageIOTree.h>
+
+namespace creaImageIO
+{
+
+
+  //=======================================================================
+  //class TreeHandlerStatistics;
+  //=======================================================================
+  /**
+   * \ingroup Model
+   */
+  //=======================================================================
+
+  /// Abstract class which 'handles' a Tree structure 
+  class TreeHandler
+  {
+  public:
+
+    //====================================================================
+    //  typedef TreeHandlerStatistics Statistics;
+    //====================================================================
+
+    //====================================================================
+    /// Ctor
+    TreeHandler() {}
+    /// Virtual dtor
+    virtual ~TreeHandler() {}
+    //====================================================================
+
+    //====================================================================
+    /// Returns the Tree handled 
+    tree::Tree& GetTree() { return mTree; }
+    /// Returns the Tree handled (const)
+    const tree::Tree& GetTree() const { return mTree; }
+    //====================================================================
+
+    //====================================================================
+    // QUERY METHODS
+    /// Is the 'source' readable ?
+    virtual bool IsReadable() { return false; }
+    /// Is the 'source' writable ?
+    virtual bool IsWritable() { return false; }
+    //====================================================================
+
+
+    //====================================================================
+    // INITIALIZATION / FINALIZATION
+    //====================================================================
+
+    //====================================================================
+    /// Opens an existing 'source' 
+    // Default mode is read only 
+    // If IsWritable and writable==true then opens in read/write mode
+    virtual bool Open(bool writable = false) { return false; }
+    /// Closes the 'source'
+    virtual bool Close() { return false; }
+    /// Creates a new 'source' 
+    // Default mode is read only 
+    // If IsWritable and writable==true then opens in read/write mode
+    virtual bool Create(bool writable = false) { return false; }
+    /// Destroys the 'source'
+    virtual bool Destroy() { return false; }
+       /// Begins a transaction
+       virtual void BeginTransaction(){}
+       ///Commits results and ends transaction
+       virtual void EndTransaction(){}
+    //====================================================================
+
+
+    //====================================================================
+    // READ METHODS
+    //====================================================================
+
+
+    //====================================================================
+    /// Returns the number of children of the Node *WITHOUT LOADING THEM*
+    // REM : The Tree itself is a Node and asking for its number of 
+    //       children returns the number of children of level 1.
+    virtual unsigned int GetNumberOfChildren(tree::Node* n) { return 0; }
+    //====================================================================
+
+       //====================================================================
+    /// Returns the attribute requested. Useful for synchronization.
+       virtual void GetAttribute(std::string levelDescriptor,
+                                                                          std::string searchParam, 
+                                                                          std::string searchVal, 
+                                                                          std::string key, 
+                                                                          std::string& result){}
+    //====================================================================
+
+    //====================================================================
+    /// Recursively loads the children of node 'parent' until maxlevel 
+    // is reached.
+    // If maxlevel <= 0 then loads all the sub-tree rooted at parent 
+    // If parent == NULL or parent == tree then starts with the 'children' of 
+    // the tree itself.
+    // Returns the total number of children loaded.
+    virtual int LoadChildren(tree::Node* parent, int maxlevel) 
+    { return 0; }
+    //====================================================================
+
+    //====================================================================
+    /// Unloads the Node and its descendants
+    // WITHOUT altering the source, e.g. the database
+    virtual void UnLoad(tree::Node* n) { return; }
+    //====================================================================
+
+       //====================================================================
+    /// Returns the top level node id for the given search param and search value
+    virtual void GetTopLevelNodeId(const std::string& searchParam, 
+                                                                                       const std::string& searchValue, 
+                                                                                       std::string& parent_id){ return; }
+    ///====================================================================
+
+
+    //====================================================================
+    // WRITE METHODS : WORK ONLY IN WRITE MODE
+    //====================================================================
+    typedef tree::Node::AttributeMapType AttributeMapType;
+    /// Adds a branch in the tree with the attributes provided
+    // returns the Level in the tree where the branch was connected 
+    // (-1 for error, 0 for top level, etc. ) 
+    // Of course the branch is loaded on exit
+    virtual int AddBranch( const AttributeMapType& ) { return -1; }
+    /// Removes the node and its descendants 
+    virtual bool Remove(tree::Node*)  { return false; }
+    /// Sets an attribute of a Node
+    virtual bool SetAttribute(tree::Node*, 
+                             const std::string& key,
+                             const std::string& value) { return false; }
+       // Sets an attribute
+    virtual void SetAttribute(const std::string& levelDescriptor, 
+                             const std::string& key,
+                             const std::string& value,
+                                 const std::string& searchParam, 
+                                 const std::string& searchVal){}
+       //Deletes the tuple that matches the parameters given
+       virtual void DeleteTuple(std::string levelDescriptor, std::string key, std::string value){}
+       //Deletes the entries that match the parameters given
+       virtual void RemoveEntries(const std::string i_table, 
+               const std::string i_attribute, 
+               const std::string i_operand, 
+               const std::string i_val){}
+    //====================================================================
+
+
+  private:
+    /// The handled tree
+    tree::Tree mTree;
+
+  };
+  // EO class TreeHandler
+  //=======================================================================
+  /*
+  //=======================================================================
+  /// Memorizes statistics on operations done by a tree handler
+  // (nodes created, removed, ...)
+  class TreeHandlerStatistics
+  {
+  public:
+    //====================================================================
+    /// Ctor
+    TreeHandler(TreeHandler* tree) : mTreeHandler(tree) { Reset(); }
+    /// Dtor
+    ~TreeHandler() {}
+    /// Resets the stats
+    void Reset();
+    /// Prints the stats
+    void Print();
+
+    /// 
+    void CreateNode(int level) { mNumberCreatedNode[level]++; }
+    void DeleteNode(int level) { mNumberDeletedNode[level]++; }
+
+  protected:
+      TreeHandler* mTreeHandler;
+    std::vector<int> mNumberCreatedNode;
+    std::vector<int> mNumberDeletedNode;
+    
+    
+    ///====================================================================
+  };
+  // EO class TreeHandlerStatistics
+  //=======================================================================
+  */
+
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
+
diff --git a/src/creaImageIOTreeHandlerImageAdder.cpp b/src/creaImageIOTreeHandlerImageAdder.cpp
new file mode 100644 (file)
index 0000000..76e8530
--- /dev/null
@@ -0,0 +1,692 @@
+#include <creaImageIOTreeHandlerImageAdder.h>
+#include <creaImageIOSystem.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/utility.hpp>
+
+
+namespace fs = boost::filesystem;
+using boost::filesystem::path;
+using boost::next;
+using boost::prior;
+
+
+using namespace crea;
+using namespace boost;
+
+namespace creaImageIO
+{
+  //====================================================================
+  // Ctor
+  TreeHandlerImageAdder::TreeHandlerImageAdder(TreeHandler* tree)
+    : mTreeHandler(tree)
+  {
+  }
+  // Dtor
+  TreeHandlerImageAdder::~TreeHandlerImageAdder()
+  {
+  }
+  //====================================================================
+
+  //====================================================================
+  void TreeHandlerImageAdder::ConnectProgressObserver(ProgressCallbackType callback)
+  {
+    mProgressSignal.connect(callback);
+  }
+  //====================================================================
+
+  //=====================================================================
+  bool TreeHandlerImageAdder::IsHandledFile( const std::string& filename)
+  {
+    return (mReader.CanRead(filename));
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void TreeHandlerImageAdder::AddFiles( const std::vector<std::string>& filenames)
+  {
+    mProgress.Reset();
+       
+    unsigned int nbf = filenames.size(); 
+    std::vector<std::string>::const_iterator i;
+       mSynchronizer->GetList(mCurrentDB);
+    for (i=filenames.begin();i!=filenames.end();++i)
+      {
+       
+       mProgress.IncNumberScannedFiles();
+       if (IsHandledFile(*i)) 
+         {
+           mProgress.IncNumberHandledFiles();
+               if(mSynchronizer->isIndexed(*i))
+               {
+                       mSynchronizer->InsertAddOp((*i),"0","1",mCurrentDB);
+                       std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","ADD_OPS","PATH",(*i),mCurrentDB);
+                       std::stringstream removedOn;
+                       removedOn<<time(0);
+                       mSynchronizer->InsertIgnoreFile(addKey,(*i),"0",removedOn.str(),mCurrentDB);
+                       AddFile(*i);
+               }
+         }
+       mProgressSignal(mProgress);
+       if (mProgress.GetStop()) break;
+      }
+  }
+  //=====================================================================
+
+  //=====================================================================
+  void TreeHandlerImageAdder::AddDirectory( const std::string& directory,
+                                           bool recurse)
+  {
+    mProgress.Reset();
+       std::stringstream files;
+       
+       std::stringstream rec;
+       rec<<recurse;
+       mSynchronizer->InsertAddOp(directory,rec.str(),"0",mCurrentDB);
+       std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","ADD_OPS","PATH",directory,mCurrentDB);
+       mTreeHandler->BeginTransaction();
+       mSynchronizer->GetList(mCurrentDB);
+       //AddDirectoryRecursor( directory, recurse, addKey );
+       DicomImageScanner sc;
+       AddDirectoryRecursorScanner(directory, recurse, addKey, sc, false );
+       
+       int nFiles=GetProgress().GetNumberAddedFiles();
+       files<<nFiles;
+       mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",files.str(),"ADD_KEY",addKey,mCurrentDB);
+       mTreeHandler->EndTransaction();
+    GimmickDebugMessage(3,mProgress<<std::endl);
+  }
+
+  //=====================================================================
+  void TreeHandlerImageAdder::AddFile( const std::string& filename )
+  {
+    GimmickDebugMessage(4,"Adding '"<<filename<<"'"<<std::endl);
+    std::map< std::string, std::string>  attr;
+    mTreeHandler->GetTree().GetDescriptor().BuildAttributeMap(attr);
+
+       
+    mReader.ReadAttributes(filename,attr);
+       //// TO DO Create a function to test if the SOP Instance ID (0008,0018) is not already on DB
+       //// test befor if this attr is present on DB if not don't perform the test!!!
+       //bool bSOPIID = false;
+       //std::map<std::string, std::string>::iterator it_att = attr.begin();
+       //for(; it_att != attr.end(); it_att++)
+       //{
+       //      if (it_att->first == "D0008_0018")
+       //      {
+       //              bSOPIID = mTreeHandler->TestSOPIID(it_attr->second);
+       //              break;
+       //      }
+       //}
+       //if(bSOPIID)
+       //      return;
+
+    int lev = mTreeHandler->AddBranch(attr);
+
+    // update the progress according to lev
+    if (lev<mTreeHandler->GetTree().GetNumberOfLevels())
+      mProgress.IncNumberAddedFiles();
+  }
+  //=====================================================================
+
+  void TreeHandlerImageAdder::RemoveFile( tree::Node* node)
+  {
+               int n=node->GetNumberOfChildren();
+               if(n>0)
+               {
+                       RemoveFiles(node->GetChildrenList());
+               }
+               else
+               {
+                 std::string path=node->GetAttribute("FullFileName");
+                 //Gets the add key
+                 std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","IGNORED_FILES","PATH",path,mCurrentDB);
+                 //Gets the number of files added
+                 int files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",addKey,mCurrentDB)).c_str());
+                 files=files-1;
+                 std::stringstream out;
+                 out<<files;
+                 //Sets the new number of files
+                 mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",out.str(),"ADD_KEY",addKey,mCurrentDB);
+                 //Sets the file as removed
+                 mSynchronizer->SetAttribute("REMOVE","IGNORED_FILES","1","PATH = '"+path+"' AND ADD_KEY",addKey,mCurrentDB);
+               }
+  }
+
+  //=====================================================================
+
+  void TreeHandlerImageAdder::RemoveFiles(const std::vector<tree::Node*>& nodes)
+  {
+         std::vector<tree::Node*>::const_iterator it;
+         for(it=nodes.begin();it!=nodes.end();++it)
+         {
+               int n=(*it)->GetNumberOfChildren();
+               if(n>0)
+               {
+                       RemoveFiles((*it)->GetChildrenList());
+               }
+               else
+               {
+                  std::string path=(*it)->GetAttribute("FullFileName");
+                 //Gets the add key
+                 std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","IGNORED_FILES","PATH",path,mCurrentDB);
+                 //Gets the number of files added
+                 int files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",addKey,mCurrentDB)).c_str());
+                 files=files-1;
+                 std::stringstream out;
+                 out<<files;
+                 //Sets the new number of files
+                 mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",out.str(),"ADD_KEY",addKey,mCurrentDB);
+                 //Sets the file as removed
+                 mSynchronizer->SetAttribute("REMOVE","IGNORED_FILES","1","PATH = '"+path+"' AND ADD_KEY",addKey,mCurrentDB);
+               }
+       
+         }
+  }
+
+  
+  //=======================================================================
+    //=====================================================================
+#if defined(USE_GDCM2)
+  void TreeHandlerImageAdder::AddDirectoryRecursorScanner(const std::string &dirpath, 
+                                                  bool recursive,const std::string &addKey, DicomImageScanner i_sc, bool b_loaded)
+  {
+    GimmickDebugMessage(4,"Scanning '"<<dirpath<<"'"<<std::endl);
+    mProgress.IncNumberScannedDirs();
+
+    if ( !fs::exists( dirpath ) ) return;
+       time_t lastModif=fs::last_write_time(dirpath);
+
+                       
+       
+               std::map< std::string, std::string>  attr;
+               mTreeHandler->GetTree().GetDescriptor().BuildAttributeMap(attr);
+               std::string path = dirpath.c_str();
+               i_sc.addDirectory(path, attr);
+       
+
+    fs::directory_iterator end_itr; // default construction yields past-the-end
+    for ( fs::directory_iterator itr( dirpath );
+         itr != end_itr;
+         ++itr )
+       {
+       
+               // If is directory & recurse : do recurse
+       if ( fs::is_directory(itr->status()) )
+         {
+           if (recursive) 
+               {
+                       AddDirectoryRecursorScanner( itr->string(), recursive, addKey, i_sc, true);
+               }
+         }
+       else 
+         {
+               std::string parent_id;
+               // tTest if directory (and only it) exists or not.
+               bool valid = mSynchronizer->isIndexed(itr->string());//true;//=mTimestampHandler->AddDirectory(dirpath, itr->string(), lastModif, time(0),mCurrentDB);
+               if(valid)
+               {
+
+                       mProgress.IncNumberScannedFiles();
+                       boost::algorithm::replace_all( itr->string(),
+                                   INVALID_FILE_SEPARATOR , 
+                                  VALID_FILE_SEPARATOR);
+                       i_sc.ReadAttributes(itr->string(),attr);
+                       mTreeHandler->GetTopLevelNodeId("FullFileName",itr->string(),parent_id);
+                       mTreeHandler->AddBranch(attr);
+                       mProgress.IncNumberHandledFiles();
+                       std::stringstream removedOn;
+                       removedOn<<time(0);
+                       mSynchronizer->InsertIgnoreFile(addKey, itr->string(),"0",removedOn.str(),mCurrentDB);
+
+                       
+                       mProgressSignal(mProgress);
+                       if (mProgress.GetStop()) 
+                       {
+                       //itr = end_itr;
+                       break;
+                       }
+               }
+                       
+               }
+       }
+       }
+#endif
+ //=====================================================================
+  void TreeHandlerImageAdder::AddDirectoryRecursor(const std::string &dirpath, 
+                                                  bool recursive,
+                                                  const std::string &addKey)
+  {
+    GimmickDebugMessage(4,"Scanning '"<<dirpath<<"'"<<std::endl);
+    mProgress.IncNumberScannedDirs();
+
+    if ( !fs::exists( dirpath ) ) return;
+       time_t lastModif=fs::last_write_time(dirpath);
+
+       
+    fs::directory_iterator end_itr; // default construction yields past-the-end
+    for ( fs::directory_iterator itr( dirpath );
+         itr != end_itr;
+         ++itr )
+       {
+       // If is directory & recurse : do recurse
+       if ( fs::is_directory(itr->status()) )
+         {
+           if (recursive) 
+               {
+                       AddDirectoryRecursor( itr->string(), recursive, addKey);
+               }
+         }
+       else 
+         {
+               std::string parent_id;
+               // tTest if directory (and only it) exists or not.
+               bool valid = mSynchronizer->isIndexed(itr->string());//true;//=mTimestampHandler->AddDirectory(dirpath, itr->string(), lastModif, time(0),mCurrentDB);
+               if(valid)
+               {
+                       mProgress.IncNumberScannedFiles();
+                       if (IsHandledFile(itr->string()))
+                       {
+                       mProgress.IncNumberHandledFiles();
+                       AddFile( itr->string() );
+                       mTreeHandler->GetTopLevelNodeId("FullFileName",itr->string(),parent_id);
+                       std::stringstream removedOn;
+                       removedOn<<time(0);
+                       mSynchronizer->InsertIgnoreFile(addKey, itr->string(),"0",removedOn.str(),mCurrentDB);
+                       }
+                       
+                       mProgressSignal(mProgress);
+                       if (mProgress.GetStop()) 
+                       {
+                       //itr = end_itr;
+                       break;
+                       }
+                       
+               }
+         }
+      }
+       
+  }
+  //=======================================================================
+  
+
+  //=======================================================================
+
+  void TreeHandlerImageAdder::CheckSyncDirectory(const std::string &dirpath, 
+                                                                                               bool recursive, 
+                                                                                               bool repair,
+                                                                                               bool checkAttributes,
+                                                                                               std::vector<std::string> &i_ignorefiles,
+                                                                                               std::vector<std::string> & attsModified,
+                                                                                               std::vector<std::string> & newfiles)
+  {
+    if ( !fs::exists( dirpath ) ) return;
+    fs::directory_iterator end_itr; // default construction yields past-the-end
+                         
+    for ( fs::directory_iterator itr( dirpath ); itr != end_itr; ++itr ) 
+       {
+        // If is directory & recurse : do recurse
+        if ( fs::is_directory(itr->status()) )
+        {
+            if (recursive)
+                       {
+                CheckSyncDirectory( itr->string(), recursive, repair, checkAttributes, i_ignorefiles, attsModified, newfiles);
+                       }
+        }
+        else
+        {
+            if (IsHandledFile(itr->string()))
+            {
+                bool bfound = false;
+                for(std::vector<std::string>::iterator it_new = i_ignorefiles.begin(); it_new < i_ignorefiles.end(); ++it_new)
+                {
+                                       if((*it_new) == itr->string())
+                    {
+                        bfound = true;
+                                               //Additional checking of attributes
+                                               if(checkAttributes)
+                                               {
+                                                       CheckAttributes(repair,(*it_new),attsModified);
+                                               }
+                        i_ignorefiles.erase(it_new);
+                        break;
+                    }
+                               }
+                               if(!bfound && i_ignorefiles.size()>0 )
+                {
+                    newfiles.push_back( itr->string() );
+                }
+                       }
+               }
+        }
+  } 
+
+  //=======================================================================
+  
+  //=======================================================================
+
+  std::string TreeHandlerImageAdder::Synchronize(bool repair, bool checkAttributes)
+  {
+         std::vector<AddList> fileList;
+         std::vector<std::string> ignoreList;
+         std::vector<std::string> newFiles;
+         std::vector<std::string> attsModified;
+         std::stringstream mess;
+         std::vector<AddList>::iterator iter;
+
+         //Gets the list of added files
+         mSynchronizer->GetFileList(fileList,mCurrentDB);
+
+         std::vector<std::string>::iterator i;
+         //Actions to take if the user doesn't want to repair
+         if(!repair)
+         {
+               //Iterates to see if they are in sync
+               for(iter=fileList.begin();iter!=fileList.end();++iter)
+               {
+                       mSynchronizer->GetIgnoredFiles((*iter).key,ignoreList);
+                       bool rec=true;
+                       if((*iter).recursive=="0"){rec=false;}
+                       CheckSyncDirectory((*iter).path,rec,repair,checkAttributes,ignoreList,attsModified,newFiles);
+               }
+
+               //Add to message the result of new found files
+               mess<<"New Files Found: "<<newFiles.size()<<std::endl;
+               if(newFiles.size()>0)
+               {
+                       mess<<"Filenames: "<<std::endl;
+                       for(i=newFiles.begin();i!=newFiles.end();++i)
+                       {
+                               mess<<*i<<std::endl;
+                       }
+               }
+
+               //Add to message the result of missing files
+               mess<<"Missing Files: "<<ignoreList.size()<<std::endl;
+               if(ignoreList.size()>0)
+               {
+                       mess<<"Filenames: "<<std::endl;
+                       for(i=ignoreList.begin();i!=ignoreList.end();++i)
+                       {
+                               mess<<*i<<std::endl;
+                       }
+               }
+
+               //In the case that the user wants to check the attributes...
+               if(checkAttributes)
+               {
+                       //... add to message the result of files that have been changed.
+                       mess<<"Files with different attributes: "<<attsModified.size()<<std::endl;
+                       if(attsModified.size()>0)
+                       {
+                               mess<<"Filenames: "<<std::endl;
+                               for(i=attsModified.begin();i!=attsModified.end();++i)
+                               {
+                                       mess<<*i<<std::endl;
+                               }
+                       }
+               }
+               
+         }
+
+         //Actions to take if the user wants to repair
+         else
+         {
+                 int nf=0;
+               //Iterates to see if they are in sync
+               for(iter=fileList.begin();iter!=fileList.end();++iter)
+               {
+                       mSynchronizer->GetIgnoredFiles((*iter).key,ignoreList);
+                       bool rec=true;
+                       if((*iter).recursive=="0"){rec=false;}
+                       CheckSyncDirectory((*iter).path,rec,repair,checkAttributes,ignoreList,attsModified,newFiles);
+
+                       //For the new files, add them
+                       for (i=newFiles.begin();i!=newFiles.end();++i)
+                       {
+                       if (IsHandledFile(*i)) 
+                       {
+                               std::stringstream removedOn;
+                               removedOn<<time(0);
+                               mSynchronizer->InsertIgnoreFile((*iter).key,(*i),"0",removedOn.str(),mCurrentDB);
+                               //Gets the number of files added
+                               int files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",(*iter).key,mCurrentDB)).c_str());
+                               files=files+1;
+                               std::stringstream out;
+                               out<<files;
+                               //Sets the new number of files
+                               mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",out.str(),"ADD_KEY",(*iter).key,mCurrentDB);
+                               AddFile(*i);
+                       }
+                       }
+                       nf+=newFiles.size();
+                       newFiles.clear();
+
+               }
+               //Reports number of added files
+               mess<<"Files Added: "<<nf<<std::endl;
+               
+               //Removes the necessary files and reports the results
+               if(ignoreList.size()>0)
+               {
+                       tree::Node* node;
+                       mTreeHandler->LoadChildren(NULL,4);
+                       for(i=ignoreList.begin();i!=ignoreList.end();++i)
+                       {
+                               FindNode(mTreeHandler->GetTree().GetChildrenList()[0],3,"FullFileName",*i,node);
+                               RemoveFile(node);
+                               mTreeHandler->Remove(node);
+                       }
+               }
+               mess<<"Files Removed: "<<ignoreList.size()<<std::endl;
+               //In the case that the user wants to check the attributes...
+               if(checkAttributes)
+               {
+                       //... add to message the result of files that were modified.
+                       mess<<"Files Modified: "<<attsModified.size()<<std::endl;
+               }
+         }
+         return mess.str();
+
+  }
+  //=======================================================================
+
+  void TreeHandlerImageAdder::CheckAttributes(bool repair, std::string& file, std::vector<std::string>& attsModified)
+  {
+         std::map< std::string, std::string>  attr;
+         mTreeHandler->GetTree().GetDescriptor().BuildAttributeMap(attr);
+      mReader.ReadAttributes(file,attr);
+         tree::LevelDescriptor::AttributeDescriptorListType adl= mTreeHandler->GetTree().GetAttributeDescriptorList(mTreeHandler->GetTree().GetNumberOfLevels()-1);    
+         tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+         for (a = adl.begin();a!=adl.end();++a)
+         {
+          std::string databaseVal;
+          mTreeHandler->GetAttribute("Image","FullFileName",file,a->GetKey(),databaseVal);
+          std::string fileVal=attr.find(a->GetKey())->second;
+          if ( a->GetFlags()==0 && databaseVal == fileVal) 
+           {
+                       if(repair)
+                       {
+                               mTreeHandler->SetAttribute("Image",a->GetKey(),fileVal,"FullFileName", file);   
+                       }
+                       attsModified.push_back(file);
+           }
+               
+         }
+         
+  }
+
+  //=======================================================================
+
+
+  void TreeHandlerImageAdder::FindNode(tree::Node* parent, int level, const std::string& searchParam, const std::string& searchVal, tree::Node*& node)
+  {
+         if(level>1)
+         {
+                 std::vector<tree::Node*>::iterator iter;
+                 for(iter=parent->GetChildrenList().begin();iter!=parent->GetChildrenList().end();++iter)
+                 {
+                         FindNode(*iter,level-1,searchParam,searchVal,node);
+                 }
+         }
+         else
+         {
+                 if(parent->GetAttribute(searchParam).compare(searchVal)==0)
+                 {
+                         node=parent;
+                 }
+
+         }
+  }
+  
+  void TreeHandlerImageAdder::SaveAs(const std::vector<std::string>& filenames, std::vector<vtkImageData *> i_images)
+  {
+         std::vector<std::string>::const_iterator it_file = filenames.begin();
+         std::vector<vtkImageData *>::iterator it_image = i_images.begin();
+       /*  mWriter.CanWrite(".jpeg");
+         for(; it_file != filenames.end(); ++it_file, ++it_image)
+                 mWriter.WriteImage(it_file->c_str(), (vtkImageData &)it_image);*/
+  }
+
+  //=======================================================================
+  void TreeHandlerImageAdder::FindNodePartial(tree::Node* parent, int level, const std::string& searchParam, const std::string& searchVal, tree::Node*& node)
+  {
+         if(level>1)
+         {
+                 std::vector<tree::Node*>::iterator iter;
+                 for(iter=parent->GetChildrenList().begin();iter!=parent->GetChildrenList().end() && node==0 ;++iter)
+                 {
+                         FindNodePartial(*iter,level-1,searchParam,searchVal,node);
+                 }
+         }
+         else
+         {
+                 if(parent->GetAttribute(searchParam).find(searchVal)<9000)
+                 {
+                         node=parent;
+                         return;
+                 }
+
+         }
+  }
+  
+  //=======================================================================
+
+  void TreeHandlerImageAdder::CopyFiles(const std::vector<std::string>& filenames, const std::string directory  )
+  {
+         std::vector<std::string>::const_iterator i;
+         if(!boost::filesystem::exists(directory))
+         {
+         boost::filesystem::create_directory(boost::filesystem::path(directory));
+         mSynchronizer->InsertAddOp(directory,"0","0",mCurrentDB);
+         }
+         std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","ADD_OPS","PATH",directory,mCurrentDB);
+         size_t last;
+         std::vector<std::string> newNames;
+         for(i=filenames.begin();i!=filenames.end();++i)
+         {
+                 std::string dir=directory.c_str();
+                 if(boost::filesystem::exists(*i) && (*i).find(dir)==std::string::npos)
+                 {
+                 std::string path=*i;
+                 last=(*i).find_last_of('/');
+                 std::string f="\\"+(*i).substr(last+1);
+       
+                 int p=1;
+                 std::stringstream out;
+                 out<<directory<<f;
+                 while(boost::filesystem::exists(out.str()))
+                 {
+                         out.str("");
+                         out<<directory<<f.substr(0,f.size()-4)<<"("<<p<<")"<<f.substr(f.size()-4);
+                         p++;
+                 }
+                 std::string result=out.str();
+                 boost::filesystem::copy_file((*i),result);
+
+                 //To update image database
+                 mTreeHandler->SetAttribute("Image","FullFileName",result,"FullFileName", (*i));
+                 
+                 //To update maintenance database
+                 //1.Add the new path and increase number of children on new operation.
+                 std::stringstream removedOn;
+                 removedOn<<time(0);
+                 //Inserts the file
+                 mSynchronizer->InsertIgnoreFile(addKey, result,"0",removedOn.str(),mCurrentDB);
+                 //Gets the number of files added
+                 int files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",addKey,mCurrentDB)).c_str());
+                 files=files+1;
+                 std::stringstream fil;
+                 fil<<files;
+                 //Sets the new number of files
+                 mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",fil.str(),"ADD_KEY",addKey,mCurrentDB);
+                 fil.str("");
+
+                 //2.Set the old path as removed and decrease number of children on old operation.
+                 //Gets the old add key
+                 std::string oldAddKey=mSynchronizer->GetAttribute("ADD_KEY","IGNORED_FILES","PATH",path,mCurrentDB);
+                 //Sets the file as removed
+                 mSynchronizer->SetAttribute("REMOVE","IGNORED_FILES","1","PATH = '"+path+"' AND ADD_KEY",oldAddKey,mCurrentDB);
+                 //Gets the number of files added
+                 files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",oldAddKey,mCurrentDB)).c_str());
+                 files=files-1;
+                 fil<<files;
+                 //Sets the new number of files
+                 mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",fil.str(),"ADD_KEY",oldAddKey,mCurrentDB);
+                 
+                 }
+
+         }
+  }
+
+  //=======================================================================
+
+  void TreeHandlerImageAdder::DeleteDriveFromMainDB(const std::string& drive)
+  {
+         //Delete from local database and others
+         tree::Node* node=0;
+         mTreeHandler->LoadChildren(NULL,4);
+         FindNodePartial(mTreeHandler->GetTree().GetChildrenList()[0],3,"FullFileName",drive,node);
+         while(node!=0)
+         {
+         mTreeHandler->Remove(node);
+         node=0;
+         mTreeHandler->LoadChildren(NULL,4);
+         FindNodePartial(mTreeHandler->GetTree().GetChildrenList()[0],3,"FullFileName",drive,node); 
+         }
+  }
+
+   //=======================================================================
+
+  void TreeHandlerImageAdder::DeleteDriveFromOtherDB(const std::string& drive)
+  {
+         //Delete from maintenance
+         mSynchronizer->RemoveEntries("ADD_OPS", "PATH", "LIKE", drive+"%");
+         mSynchronizer->RemoveEntries("IGNORED_FILES", "PATH", "LIKE", drive+"%");
+  }
+
+  //=======================================================================
+  void TreeHandlerImageAdder::EditField(tree::Node* node, const std::string& name, const std::string& key, const std::string& val)
+  {
+         node->SetAttribute(key,val);
+         mTreeHandler->SetAttribute(node,key,val);
+  }
+
+  //=======================================================================
+  void TreeHandlerImageAdder::GetAttributes(const std::vector<std::string>& params, 
+         const std::string& filename, 
+         std::vector<std::string>& results)
+  {
+         std::vector<std::string>::const_iterator i;
+         std::string result;
+         for(i=params.begin();i!=params.end();i++)
+         {
+                 mTreeHandler->GetAttribute("Image","FullFileName",filename,*i,result);
+                 results.push_back(result);
+         }
+  }
+
+}
diff --git a/src/creaImageIOTreeHandlerImageAdder.h b/src/creaImageIOTreeHandlerImageAdder.h
new file mode 100644 (file)
index 0000000..252e788
--- /dev/null
@@ -0,0 +1,209 @@
+#ifndef __creaImageIOTreeHandlerImageAdder_h_INCLUDED__
+#define __creaImageIOTreeHandlerImageAdder_h_INCLUDED__
+
+#include <creaImageIOTreeHandler.h>
+#include <creaImageIOSynchron.h>
+#include <creaImageIOImageReader.h>
+//#include <creaImageIOImageWriter.h>
+
+// Signal/slot mechanism for progress events
+#include <boost/signal.hpp>
+#include <boost/bind.hpp>
+#if defined(USE_GDCM2)
+#include "creaImageIODicomScanner.h"
+#endif
+
+namespace creaImageIO
+{
+       /**
+       * \ingroup Model
+       */
+
+  //=======================================================================
+  /// Object which can add images files to a TreeHandler. Is able to parse (recursively) a part of a filesystem to look for known images and load their attributes in order to add the images to a Tree (submission via a TreeHandler::AddBranch)
+
+  class TreeHandlerImageAdder
+  {
+         
+  public:
+    //====================================================================
+    /// Ctor
+    TreeHandlerImageAdder(TreeHandler* tree);
+    /// Dtor
+    ~TreeHandlerImageAdder();
+    /// Sets the TreeHandler
+    void SetTreeHandler(TreeHandler* tree) { mTreeHandler = tree;}
+       
+       /// Sets the synchronizer
+       void SetSynchronizer(Synchronizer* s){mSynchronizer=s;}
+       /// Sets the synchronizer
+       void SetCurrentDatabase(std::string cur){mCurrentDB=cur;}
+    //====================================================================
+
+    //====================================================================
+    /// Structure which holds progress information
+    /// To stop the image adder use SetStop()
+    class Progress
+    {
+    public:
+      Progress() { Reset(); }
+      ~Progress() {}
+      
+      void Reset() 
+      {
+       mStop = false;
+       mNumberScannedFiles = 0;
+       mNumberScannedDirs = 0;
+       mNumberHandledFiles = 0;
+       mNumberAddedFiles = 0;
+      }
+
+      int GetNumberScannedFiles() const { return mNumberScannedFiles; }
+      int GetNumberScannedDirs() const { return mNumberScannedDirs; }
+      int GetNumberHandledFiles() const { return mNumberHandledFiles; }
+      int GetNumberAddedFiles() const { return mNumberAddedFiles; }
+
+      void IncNumberScannedFiles() { mNumberScannedFiles++; }
+      void IncNumberScannedDirs() { mNumberScannedDirs++; }
+      void IncNumberHandledFiles() { mNumberHandledFiles++; }
+      void IncNumberAddedFiles() { mNumberAddedFiles++; }
+
+      void SetStop() { mStop = true; }
+      bool GetStop() const { return mStop; }
+
+    private:
+      bool mStop;
+      int mNumberScannedFiles;
+      int mNumberScannedDirs;
+      int mNumberHandledFiles;
+      int mNumberAddedFiles;
+    };
+    //=============================================
+
+    //=============================================
+    const Progress& GetProgress() const { return mProgress; }
+    //=============================================
+
+    //=============================================
+    typedef boost::signal<void (Progress&)>  ProgressSignalType;
+    typedef ProgressSignalType::slot_function_type ProgressCallbackType;
+    //=============================================
+
+   //==================================================================
+    /// Adds the function f to the list of functions to call 
+    /// when the addition progresses.
+    /// f is of type ProgressCallbackType which is:
+    /// void (*ProgressCallbackType)(Progress&)
+    /// To pass a member function 'f' of an instance 'c' of a class 'C' 
+    /// as callback you have to 'bind' it, i.e. call:
+    /// ConnectProgressObserver ( boost::bind( &C::f , c, _1 ) );
+    void ConnectProgressObserver(ProgressCallbackType callback);
+   //==================================================================
+
+    //====================================================================
+    /// Returns if the file can be read or not
+    bool IsHandledFile( const std::string& filename);
+    /// Adds a list of files to the TreeHandler 
+    void AddFiles( const std::vector<std::string>& filename );
+    /// (Recursively) adds the files of a directory to the TreeHandler 
+    void AddDirectory( const std::string& directory, 
+                      bool recurse);
+
+
+#if defined(USE_GDCM2)
+        void AddDirectoryRecursorScanner(const std::string &dirpath, 
+                                                  bool recursive,const std::string &addKey,  DicomImageScanner i_sc, bool b_loaded);
+#endif
+
+       /// Removes a file from the databases
+       void RemoveFile(tree::Node* node);
+       /// Removes files from the databases
+       void RemoveFiles(const std::vector<tree::Node*>& nodes);
+       /// Synchronizes the DB and disk by repeating the operations the user has done and returns a report
+       std::string Synchronize(bool repair, bool checkAttributes);
+       ///Recursively checks if the directory is synchronized and optionally the state of the attributes
+       void CheckSyncDirectory(const std::string &dirpath, 
+                                                       bool recursive, 
+                                                       bool repair,
+                                                       bool checkAttributes,
+                                                       std::vector<std::string> &i_ignorefiles,
+                                                       std::vector<std::string> & attsModified,
+                                                       std::vector<std::string> & newfiles);
+       ///Copies the files indicated in the vector and updates all databases
+       void CopyFiles(const std::vector<std::string>& filenames, const std::string directory  );
+       
+       ///Saves as the files indicated in the vector in a specific directory
+       void SaveAs(const std::vector<std::string>& filenames, std::vector<vtkImageData *> i_images);
+       ///Finds the node that matches the specified parameters
+       void FindNode(tree::Node* parent, int level, 
+               const std::string& searchParam, 
+               const std::string& searchVal, 
+               tree::Node*& node);
+
+       ///Finds the nodes that partially match the searchVal
+       void FindNodePartial(tree::Node* parent, int level, const std::string& searchParam, const std::string& searchVal, tree::Node*& node);
+       ///Checks the attributes of the database against the ones in disk
+       void CheckAttributes(bool repair, std::string& file, std::vector<std::string>& attsModified);
+       ///Deletes the drive with the given name (use for all databases except maintenance and timestamp)
+       void DeleteDriveFromMainDB(const std::string& drive);
+       ///Deletes the drive with the given name (use for maintenance and timestamp databases)
+       void DeleteDriveFromOtherDB(const std::string& drive);
+       ///Edits the given field and sets the new parameters
+       void EditField(tree::Node* node, const std::string& name, const std::string& key, const std::string& val);
+       ///Returns the demanded attributes for the given file
+       void GetAttributes(const std::vector<std::string>& params, 
+         const std::string& filename, 
+         std::vector<std::string>& results);
+  
+  
+  
+    //====================================================================
+
+  private:
+
+    /// Adds a single file to the TreeHandler 
+    /// **WITHOUT** testing wether it is handled or not 
+    /// hence you have to call IsHandledFile before using AddFile!
+    void AddFile( const std::string& filename );
+
+    /// Recursive method which does the main job for AddDirectory
+    void AddDirectoryRecursor( const std::string& directory, 
+                              bool recurse,
+                          const std::string &addKey);
+
+    TreeHandler* mTreeHandler;
+       Synchronizer* mSynchronizer;
+    ImageReader mReader;
+       //ImageWriter mWriter;
+       std::string mCurrentDB;
+    
+    Progress mProgress;
+    ProgressSignalType mProgressSignal;
+
+
+  };
+  // EO class TreeHandlerImageAdder
+  //=======================================================================
+
+
+
+
+} // EO namespace creaImageIO
+
+#include <iostream>
+inline std::ostream& operator << ( std::ostream& o, 
+                           const creaImageIO::TreeHandlerImageAdder::Progress& p)
+{
+  o << p.GetNumberScannedFiles() << " files - "
+    << p.GetNumberScannedDirs() << " dirs - "
+    << p.GetNumberHandledFiles() << " handled -"
+    << p.GetNumberAddedFiles() << " added";
+  return o;
+}
+
+// EOF
+#endif  
+
diff --git a/src/creaImageIOTreeLevelDescriptor.cpp b/src/creaImageIOTreeLevelDescriptor.cpp
new file mode 100644 (file)
index 0000000..46eb41a
--- /dev/null
@@ -0,0 +1,32 @@
+#include <creaImageIOTreeLevelDescriptor.h>
+#include <creaImageIOSystem.h>
+
+
+namespace creaImageIO
+{
+  namespace tree
+  {
+    /// Adds the AttributeDescriptor to the list
+    void LevelDescriptor::Add(const AttributeDescriptor& a)
+    {
+      GimmickMessage(5,"Adding Attribute Descriptor '"<<a.GetKey()
+                    <<"' to LevelDescriptor"
+                    <<std::endl);
+      mAttributeDescriptorList.push_back(a);
+      if ( a.GetFlags() & AttributeDescriptor::IDENTIFIER )
+       {
+         GimmickMessage(6,"Is an IDENTIFIER"<<std::endl);
+         mIdentifierList.push_back(a.GetKey());
+       }
+      if ( a.GetFlags() & AttributeDescriptor::LABEL )
+       {
+         GimmickMessage(6,"Is a LABEL"<<std::endl);
+         mLabelList.push_back(a.GetKey());
+       }
+    }
+
+       
+
+  }
+}
+
diff --git a/src/creaImageIOTreeLevelDescriptor.h b/src/creaImageIOTreeLevelDescriptor.h
new file mode 100644 (file)
index 0000000..f947034
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __creaImageIOTreeLevelDescriptor_h_INCLUDED__
+#define __creaImageIOTreeLevelDescriptor_h_INCLUDED__
+
+#include <creaImageIOTreeAttributeDescriptor.h>
+#include <vector>
+
+namespace creaImageIO
+{
+
+  namespace tree
+  {
+       /**
+       * \ingroup Tree
+       */
+    //=====================================================================
+    /// Descriptor of a level of a Tree (name, attributes, ...)
+    class LevelDescriptor
+    {
+    public:
+      /// Ctor with name
+      LevelDescriptor(const std::string& name) : mName(name) {}
+      /// Destructor
+      ~LevelDescriptor() {} 
+
+      /// Returns the name of the level
+      const std::string& GetName() const { return mName; }
+
+      /// Returns the number of attributes of the level
+      unsigned int GetNumberOfAttributes() const
+      { return mAttributeDescriptorList.size(); }
+
+      /// Adds the AttributeDescriptor to the list
+      void Add(const AttributeDescriptor&);
+
+         /// The type of attribute container
+      typedef std::vector<AttributeDescriptor> AttributeDescriptorListType;
+      /// Returns the list of AttributeDescriptor (const)
+      const AttributeDescriptorListType& GetAttributeDescriptorList() const 
+      { return mAttributeDescriptorList; }
+
+      /// \return The list of attributes with flag IDENTIFIER set
+      const std::vector<std::string>& GetIdentifierList() const 
+      { return mIdentifierList; }
+      /// \return The list of attributes with flag LABEL set
+      const std::vector<std::string>& GetLabelList() const 
+      { return mLabelList; }
+
+    private:
+      std::string mName;
+      AttributeDescriptorListType mAttributeDescriptorList;
+      /// The list of attributes with flag IDENTIFIER set
+      std::vector<std::string> mIdentifierList;
+      /// The list of attributes with flag LABEL set
+      std::vector<std::string> mLabelList;
+
+    };
+    // EO class LevelDescriptor
+    //=====================================================================
+  }// EO namespace tree
+  
+
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
diff --git a/src/creaImageIOTreeNode.cpp b/src/creaImageIOTreeNode.cpp
new file mode 100644 (file)
index 0000000..5d892af
--- /dev/null
@@ -0,0 +1,244 @@
+#include <creaImageIOTreeNode.h>
+#include <creaImageIOTree.h>
+#include <creaImageIOSystem.h>
+#include <algorithm>
+#include <creaImageIOGimmick.h>
+
+namespace creaImageIO
+{
+  namespace tree
+  {
+
+    //=============================================================
+    /// Ctor with parent
+    Node::Node(Node* parent)
+      : mParent(parent),//mData(0),
+       mChildrenLoaded(false)
+    {
+       mData.reset();
+      if (parent) 
+       {
+         GimmickDebugMessage(6,"Default Node constructor (level "<<GetLevel()<<")"
+                        << std::endl);
+         // Insert into parent's children list
+         InitializeAttributeMap();
+        parent->GetChildrenList().push_back(this);
+       }
+      else
+       {
+         GimmickDebugMessage(6,"Default Node constructor without parent"       
+                        << std::endl);
+       }
+    }
+    //=============================================================
+
+    //=============================================================
+    /// Ctor with parent and attributes map 
+    Node::Node(Node* parent, const AttributeMapType& attr)
+     : mParent(parent),//mData(0),
+       mChildrenLoaded(false)
+    {
+       mData.reset();
+      GimmickDebugMessage(6,"Node constructor (level "<<GetLevel()<<")"
+                    << std::endl);
+
+     if (parent) 
+       {
+         // Insert into parent's children list
+         parent->GetChildrenList().push_back(this);
+         // Initialize attributes
+         LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+         for (a = GetTree()->GetAttributeDescriptorList(GetLevel()).begin();
+              a!= GetTree()->GetAttributeDescriptorList(GetLevel()).end();
+              ++a)
+           {
+             std::string v;
+             AttributeMapType::const_iterator i = attr.find(a->GetKey());
+             if ( i != attr.end() )  
+               {
+                 v = i->second;
+               }
+             GimmickDebugMessage(6,"Setting attribute '"<<a->GetName()<<"' = '"
+                            <<v<<"'"<<std::endl);
+             UnsafeSetAttribute( a->GetKey(), v );
+           }
+       }
+      
+    }
+    //=============================================================
+
+
+    //=============================================================
+    Node::~Node()
+    {
+      GimmickDebugMessage(6,"Node destructor"
+                    << std::endl);
+      ChildrenListType::iterator i;
+      for (i=GetChildrenList().begin(); i!=GetChildrenList().end(); i++)
+       {
+         delete *i;
+       }
+       mData.reset();
+    }
+    //=============================================================
+
+
+    //=============================================================
+    /// Initializes the attribute map i.e. creates the entries
+    void Node::InitializeAttributeMap()
+    {
+      // Initialize attributes
+      LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+      for (a = GetTree()->GetAttributeDescriptorList(GetLevel()).begin();
+          a!= GetTree()->GetAttributeDescriptorList(GetLevel()).end();
+          ++a)
+       {
+         UnsafeSetAttribute( a->GetKey(), "" );
+       }
+    }
+    //=============================================================
+
+    //=============================================================
+    /// Returns the level descriptor of the node
+    const LevelDescriptor& Node::GetLevelDescriptor() const
+    { 
+      return GetTree()->GetLevelDescriptor(GetLevel()); 
+    }
+
+       //=============================================================
+
+    //=============================================================
+    /// Returns the attribute descriptor of the passed parameter
+       const AttributeDescriptor& Node::GetAttributeDescriptor(const std::string& k)const
+       {
+               LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+      for (a = GetTree()->GetAttributeDescriptorList(GetLevel()).begin();
+          a!= GetTree()->GetAttributeDescriptorList(GetLevel()).end();
+          ++a)
+               {
+               
+                       if(a->GetKey()==k)
+                       {
+                               return *a;
+                       }
+               
+               }
+               return *a;
+       }
+    //=============================================================
+
+    //=============================================================
+    int Node::RemoveChildrenFromList(Node* node)
+    {
+      ChildrenListType::iterator i = find(GetChildrenList().begin(),
+                                         GetChildrenList().end(),
+                                         node);
+      if (i != GetChildrenList().end())
+       {
+         GetChildrenList().erase(i);
+       }
+       return GetChildrenList().size();
+    }
+    //=============================================================
+
+    //=============================================================
+    const std::string& Node::GetAttribute(const std::string& k) const
+    {
+      //    std::cout << "this = "<<(void*)this<<std::endl;
+      //    std::cout << "mFieldValueMap="<<(void*)(&mFieldValueMap)<<std::endl;
+      AttributeMapType::const_iterator i = mAttributeMap.find(k);
+      if (i == mAttributeMap.end())
+       {
+         static std::string def("");
+         return def;
+         //    CREAIMAGEIO_ERROR("DicomNode::GetFieldValue : no field with key '"<<k<<"'");
+       }
+      return i->second;
+  }
+  //=============================================================
+
+  //=============================================================
+    void Node::SetAttribute(const std::string& k, 
+                                const std::string& v)
+  {
+    AttributeMapType::iterator i = mAttributeMap.find(k);
+    if (i==mAttributeMap.end())
+      {
+       std::cout<<"[Gimmick!] Node::SetAttribute : no attribute with key '"
+                <<k<<"'"<<std::endl;
+       creaError( "[Gimmick!] Node::SetAttribute : no attribute with key '"
+                  <<k<<"'");
+      }
+    i->second = v;
+  }
+    //=============================================================
+
+    //=============================================================
+    bool Node::Matches(  const AttributeMapType& m ) const
+    {
+      GimmickDebugMessage(2,"'"<<GetLabel()<<"' matching..."<<std::endl);
+      const std::vector<std::string>& id 
+       = GetLevelDescriptor().GetIdentifierList();
+      std::vector<std::string>::const_iterator i;
+      for (i = id.begin(); i != id.end(); ++i)
+       {
+         if (mAttributeMap.find(*i)->second != m.find(*i)->second ) 
+           {
+             GimmickDebugMessage(2,"IDENTIFIER '"<<*i<<"' values do not match"<<std::endl);
+             return false;
+           }
+         GimmickDebugMessage(2,"IDENTIFIER '"<<*i<<"' values match"<<std::endl);
+       }
+      return true;
+    }
+    //=============================================================
+    
+    //=============================================================
+    void Node::Print() const
+    {
+      std::string mess;
+      for (int i = 0; i<GetLevel(); ++i) mess += "  ";
+      mess += "|_ " + GetLabel();
+      GimmickMessage(1,mess<<std::endl);
+      ChildrenListType::const_iterator j;
+      for (j=GetChildrenList().begin(); j!=GetChildrenList().end(); j++)
+       {
+         (*j)->Print();
+       } 
+    }
+    //=============================================================
+
+    //=============================================================
+    std::string Node::GetLabel() const
+    {
+      std::string l;
+      const std::vector<std::string>& label 
+       = GetLevelDescriptor().GetLabelList();
+      
+      std::vector<std::string>::const_iterator i;
+      for (i = label.begin(); i != label.end(); )
+       {
+         GimmickDebugMessage(9,"LABEL '"<<*i<<"'"<<std::endl);
+         AttributeMapType::const_iterator j = mAttributeMap.find(*i);
+         if (j != mAttributeMap.end())
+           {
+             l += j->second;
+             ++i;
+             if (i != label.end()) l += "|";
+           }
+         else 
+           {
+             GimmickError("Node::GetLabel() : LABEL attribute '"
+                          <<*i
+                          <<"' is not in node attribute map (should be!)" );
+           }
+       }
+      if (l.size()==0) l="?";
+      return l;
+    }
+    //=============================================================
+
+  }
+
+}
diff --git a/src/creaImageIOTreeNode.h b/src/creaImageIOTreeNode.h
new file mode 100644 (file)
index 0000000..2905c1a
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef __creaImageIOTreeNode_h_INCLUDED__
+#define __creaImageIOTreeNode_h_INCLUDED__
+
+#include <creaImageIOTreeDescriptor.h>
+#include <creaImageIOTreeComparators.h>
+#include<boost/filesystem/operations.hpp>
+#include <vector>
+#include <map>
+
+
+namespace creaImageIO
+{
+
+  namespace tree
+  {
+         /**
+       * \ingroup Tree
+       */
+    //=====================================================================
+    /// Forward declaration of Tree
+    class Tree;
+    //=====================================================================  
+    
+    //=====================================================================
+    /// Abstract class to store user data on a Tree node
+    struct NodeData
+    { 
+      NodeData() {}
+      virtual ~NodeData() {}
+    };
+    //=====================================================================
+
+
+    //=====================================================================
+    /// Node of an attributed Tree structure
+    class Node
+    {
+    public:
+      typedef std::map<std::string,std::string> AttributeMapType;
+
+
+      /// Ctor with parent
+      Node(Node* parent);
+      /// Ctor with parent and attributes map 
+      Node(Node* parent, const AttributeMapType& );
+      /// Virtual destructor
+      virtual ~Node();
+
+      /// Initializes the attribute map i.e. creates the entries
+      void InitializeAttributeMap();
+      /// Returns the level descriptor of the node
+      const LevelDescriptor& GetLevelDescriptor() const;
+
+
+      /// Returns the tree to which the node belongs
+      virtual Tree* GetTree() { return mParent->GetTree(); }
+      /// Returns the tree to which the node belongs
+      virtual const Tree* GetTree() const { return mParent->GetTree(); }
+      /// Returns the level of the node in the tree
+      virtual int GetLevel() const { return mParent->GetLevel()+1; }
+
+        
+      /// Returns the parent of the node
+      Node* GetParent() const { return mParent; }
+
+      /// Returns the number of children of the node.
+      /// Warning : if the children are not loaded then might return 0
+      ///           even if the node has children !
+      ///           see TreeHandler::GetNumberOfChildren 
+      unsigned int GetNumberOfChildren() const { return mChildren.size(); }
+
+      /// Returns true iff the node's children are loaded
+      bool GetChildrenLoaded() const { return mChildrenLoaded; }
+
+      /// Sets the node's children 
+      void SetChildrenLoaded(bool l) { mChildrenLoaded = l; }
+
+      /// The type of children container
+      typedef std::vector<Node*> ChildrenListType;
+      /// Returns the list of children
+      ChildrenListType& GetChildrenList() { return mChildren; }
+      /// Returns the list of children (const)
+      const ChildrenListType& GetChildrenList() const { return mChildren; }
+
+      /// Remove the given children from the children list
+      int RemoveChildrenFromList(Node*);
+
+       
+         /// Get the Attributes Map
+      AttributeMapType& GetAttributeMap() { return mAttributeMap; }
+
+         /// Get the Attributes Map
+      const AttributeMapType& GetAttributeMap() const { return mAttributeMap; }
+
+         /// Get the Attribute for a specific key
+      const std::string& GetAttribute(const std::string& k) const;
+      
+         /// Get the Attribute for a specific key without OS dependance (not implemented)
+         // TODO : backslash OS uniformity
+         const std::string& GetCleanAttribute(const std::string& k) const;
+
+         /// Set an Attribute for a specific key
+      void SetAttribute(const std::string& k, const std::string& v);
+
+         /// Set an Attribute for a specific key(unsafe mode)
+      void UnsafeSetAttribute(const std::string& k, const std::string& v)
+      { mAttributeMap[k] = v; }
+    
+         /// Get Descriptor for an Attribute
+      const AttributeDescriptor& GetAttributeDescriptor(const std::string& k)const;
+      
+      /// Returns true if the KEY attributes of the node match those of the map provided
+      bool Matches( const AttributeMapType& ) const;
+
+      /// Returns the node data casted into the type T
+      template<class T> T GetData() const 
+      { if (mData!=0) return dynamic_cast<T>(mData); return 0; }
+
+      /// Sets the node data. Deletes existing data if any.
+         void SetData(boost::shared_ptr<NodeData> d) {mData.reset(); mData = d; }//{ if (mData) delete mData; mData = d; }
+
+      /// Sorts the children of the node 
+      void SortChildren(const LexicographicalComparator&);
+
+         /// Print the node
+      virtual void Print() const;
+
+         /// Get the Label of the node
+      std::string GetLabel() const;
+
+    private:
+      /// The parent of the node
+      Node* mParent;
+      /// The list of children
+      ChildrenListType mChildren;
+      /// The map of attributes
+      AttributeMapType mAttributeMap;
+      /// User data
+      boost::shared_ptr<NodeData> mData;
+      /// Are the children loaded ?
+      bool mChildrenLoaded;
+      /// The number of children
+      // int mNumberOfChildren;
+
+    }; // class Node
+    //=====================================================================
+
+  } // namespace tree
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIOTreeNode_h_INCLUDED__
diff --git a/src/creaImageIOTreeView.cpp b/src/creaImageIOTreeView.cpp
new file mode 100644 (file)
index 0000000..b0820d3
--- /dev/null
@@ -0,0 +1,32 @@
+#include <creaImageIOTreeView.h>
+#include <creaImageIOSystem.h>
+
+
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+  // CTor
+  TreeView::TreeView(TreeHandler* handler, GimmickView* gimmick )
+    : mTreeHandler(handler),
+      mGimmickView(gimmick)
+  {
+    GimmickDebugMessage(1,"TreeView::TreeView"
+                       <<std::endl);
+  }
+
+  /// Destructor
+  TreeView::~TreeView()
+  {
+    GimmickDebugMessage(1,"TreeView::~TreeView"
+                       <<std::endl);
+  }
+  
+  
+  
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOTreeView.h b/src/creaImageIOTreeView.h
new file mode 100644 (file)
index 0000000..bf1298a
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef __creaImageIOTreeView_h_INCLUDED__
+#define __creaImageIOTreeView_h_INCLUDED__
+
+#include <creaImageIOTreeHandler.h>
+#include <creaImageIOTimestampDatabaseHandler.h>
+#include <creaImageIOSystem.h>
+#include <vtkImageData.h>
+
+namespace creaImageIO
+{
+
+  class GimmickView;
+
+  /**
+   * \ingroup View
+   */
+       
+  //=====================================================================
+
+  //=====================================================================
+  /// Abstract class that handles the view of a Tree through its TreeHandler
+  class TreeView
+    {
+    public:
+      /// Ctor
+      TreeView(TreeHandler*,GimmickView*);
+      /// Virtual destructor
+      virtual ~TreeView();
+
+      
+      /// Updates the view of a level given the selected items of upper level
+      virtual void UpdateLevel( int ) 
+      { GimmickError("INTERNAL ERROR : TreeView::UpdateLevel not overloaded");}
+
+         ///Removes selected nodes
+         virtual void RemoveSelected(std::string &i_save )
+         { GimmickError("INTERNAL ERROR : TreeView::RemoveSelected not overloaded");}
+
+         ///Validates the selected images
+      virtual void ValidateSelectedImages()
+         { GimmickError("INTERNAL ERROR : TreeView::ValidateSelected not overloaded");}
+         
+         ///Returns the last selected level
+         virtual unsigned int GetLastSelectedLevel(){GimmickError("INTERNAL ERROR : TreeView::GetLastSelectedLevel not overloaded");}
+
+         ///Returns the maximum number of levels
+         virtual int GetNumberOfLevels(){ GimmickError("INTERNAL ERROR : TreeView::GetLevels not overloaded"); }
+         ///Gets the current selections filenames
+         virtual void GetSelectedAsString(std::vector<std::string>&s){ GimmickError("INTERNAL ERROR : TreeView::GetSelectedAsString not overloaded"); }
+
+         /// Gets the user selected data from the level passed as a parameter
+      virtual const std::vector<tree::Node*>& GetSelected(int level){ GimmickError("INTERNAL ERROR : TreeView::GetSelected not overloaded"); }
+
+         /// Gets the next nodes on the list, be it up(true) or down(false).
+      virtual void GetNodes(std::vector<tree::Node*>& nodes, bool direction){ GimmickError("INTERNAL ERROR : TreeView::GetNodes not overloaded"); }
+
+         /// Gets the attributes that are being shown and the ones that have been blocked on a specific level
+         virtual void GetAttributes(std::vector<std::string>& areShown, std::vector<std::string>& notShown, int level){ GimmickError("INTERNAL ERROR : TreeView::GetAttributes not overloaded"); }
+         
+         ///Sets the non visible attributes and refreshes the GUI
+         virtual void SetNonVisibleAttributes(const std::vector<std::string>& notShown, int level){ GimmickError("INTERNAL ERROR : TreeView::SetNonVisibleAttributes not overloaded"); }
+
+         ///Creates a new listctrl
+         virtual void CreateCtrl(std::vector<std::string>& notShown, int nlevel){ GimmickError("INTERNAL ERROR : TreeView::CreateCtrl not overloaded"); }
+
+    protected:
+      TreeHandler* GetTreeHandler() { return mTreeHandler; }
+         GimmickView* GetGimmickView() { return mGimmickView; }
+        
+    private:
+      /// The TreeHandler with which it corresponds
+      TreeHandler* mTreeHandler;
+         /// The GimmickView which holds the TreeView
+      GimmickView* mGimmickView;  
+
+  };
+    // EO class TreeView
+    //=====================================================================
+  
+  
+} // EO namespace creaImageIO
+
+// EOF
+#endif  
diff --git a/src/creaImageIOUltrasonixImageReader.cpp b/src/creaImageIOUltrasonixImageReader.cpp
new file mode 100644 (file)
index 0000000..8eb476b
--- /dev/null
@@ -0,0 +1,261 @@
+
+#include "creaImageIOSystem.h"
+#include "creaImageIOUltrasonixImageReader.h"
+#include <creaVtk.h>
+#include <boost/filesystem/path.hpp>
+namespace creaImageIO
+{
+#define HEADER_SIZE    19
+#define TYPE_RF                16
+#define TYPE_B8                4
+#define TYPE_B32       8
+
+
+  //=====================================================================
+  UltrasonixImageReader::UltrasonixImageReader()
+  {
+    SetName("Ultrasonix");
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  UltrasonixImageReader::~UltrasonixImageReader()
+  {
+  }
+  //=====================================================================
+
+  //=====================================================================
+  struct Ultrasonix_header
+  {
+    // frames, width, height, ultrasounds frequency, sampling rate
+    int type, frame, width, height, frequency, samplingRate;
+  };
+  //=====================================================================
+
+
+  //=====================================================================
+  bool ReadHeader( FILE *Ultrasonix_file, Ultrasonix_header& h )
+  {
+    //int *header=(int*)malloc(sizeof(int)*HEADER_SIZE);
+    int header[HEADER_SIZE];
+    fread(header, sizeof(int), HEADER_SIZE, Ultrasonix_file);
+    if (ferror(Ultrasonix_file))
+       return false;
+    h.type         = header[0];
+    h.frame        = header[1];
+    h.height       = header[2];
+    h.width        = header[3];
+    h.frequency    = header[14];
+    h.samplingRate = header[15];
+    //free(header);  
+    return true;
+  }
+  //=====================================================================
+
+  //=====================================================================
+  bool UltrasonixImageReader::CanRead(const std::string& filename)
+  { 
+    long size;
+    bool ok = false;
+    FILE *Ultrasonix_file=fopen(filename.c_str(), "rb");
+    if (Ultrasonix_file) 
+    {
+       Ultrasonix_header h;
+       if (!ReadHeader(Ultrasonix_file, h) )
+       {
+               fclose(Ultrasonix_file);
+               std::cout << "cannot read Ultrasonix header for file [" << filename << "]" << std::endl;                                
+               return false;   
+       }
+
+       fseek(Ultrasonix_file,0,SEEK_END);              // go to end of file
+       if (h.type == TYPE_RF)
+               size = (ftell(Ultrasonix_file) - (HEADER_SIZE+h.frame) * sizeof(int)) / sizeof(short);
+       else if (h.type == TYPE_B8)
+               size = (ftell(Ultrasonix_file) - HEADER_SIZE * sizeof(int)) / sizeof(char);
+       else if (h.type == TYPE_B32)
+               size = (ftell(Ultrasonix_file) - HEADER_SIZE * sizeof(int)) / sizeof(int);
+
+       // check if the data size corresponds to the dimensions of the images
+       if (size == h.width * h.height * h.frame)
+               ok = true;
+               
+       fclose(Ultrasonix_file);
+    }
+    return ok;
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  vtkImageData* UltrasonixImageReader::ReadImage(const std::string& filename)
+  {
+    FILE *Ultrasonix_file=fopen(filename.c_str(),"rb");
+    if (!Ultrasonix_file) 
+    {
+       std::cout << "cannot open file [" << filename << "]" << std::endl;
+       return 0;
+    }
+    Ultrasonix_header h;
+    if (!ReadHeader(Ultrasonix_file,h)) 
+    {
+        std::cout << "cannot read Ultrasonix header for file [" << filename << "]" << std::endl;
+       fclose(Ultrasonix_file);  
+       return 0;
+    }
+
+    long frame_size = h.height   * h.width;      
+    long im_size    = frame_size * h.frame;
+
+    short *dataRF,  *ptrRF;
+    char  *dataB8,  *ptrB8;
+    int   *dataB32, *ptrB32;
+    vtkImageData* im;
+    int temp;
+
+    switch (h.type)
+    {
+       case TYPE_RF:
+               dataRF = (short*)malloc(sizeof(short)*im_size);
+               ptrRF  = dataRF;
+
+               for (int k=0; k<h.frame; k++)
+               {
+                       int frame_number;
+                       fread(&frame_number, sizeof(int), 1, Ultrasonix_file);
+                       fread(ptrRF,sizeof(short), frame_size, Ultrasonix_file);
+                       ptrRF += frame_size;
+               }
+               fclose(Ultrasonix_file);  
+
+               im = crea::NewVtkImageDataFromRaw( dataRF, h.width, h.height, h.frame);
+       break;
+
+       case TYPE_B8:
+               dataB8 = (char*)malloc(sizeof(char)*im_size);
+               ptrB8  = dataB8;
+               for (int k=0; k<h.frame; k++)
+               {
+                       fread(ptrB8,sizeof(char), frame_size, Ultrasonix_file);
+                       ptrB8 += frame_size;
+               }
+               // in mode b frames width and height are inverted
+               temp     = h.width;
+               h.width  = h.height;
+               h.height = temp;
+
+               fclose(Ultrasonix_file);  
+
+       im = crea::NewVtkImageDataFromRaw( dataB8, h.width, h.height, h.frame);
+       break;
+
+       case TYPE_B32:
+               dataB32 = (int*)malloc(sizeof(int)*im_size);
+               ptrB32  = dataB32;
+               for (int k=0; k<h.frame; k++)
+               {
+                       fread(ptrB32, sizeof(int), frame_size, Ultrasonix_file);
+                       ptrB32 += frame_size;
+               }
+               // in B mode frames width and height are inverted
+               temp     = h.width;
+               h.width  = h.height;
+               h.height = temp;
+
+               fclose(Ultrasonix_file);  
+
+               im = crea::NewVtkImageDataFromRaw( dataB32, h.width, h.height, h.frame);
+       break;
+    }
+
+    return im;
+}
+  //=====================================================================
+  
+
+  //=====================================================================
+  void UltrasonixImageReader::PushBackExtensions(std::vector<std::string>& v)
+  {
+    v.push_back("Ultrasonix");
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+ void UltrasonixImageReader::ReadAttributes(const std::string& filename, 
+                                     std::map<std::string,std::string>& attr)
+ {
+    GimmickMessage(2,"Reading attributes from '" << filename << std::endl);
+
+    FILE *Ultrasonix_file = fopen(filename.c_str(), "rb");
+    if (!Ultrasonix_file)
+    {
+       std::cout << "cannot open RF file [" << filename << "]" << std::endl;
+       return;
+    }
+
+    Ultrasonix_header h;
+    if (!ReadHeader(Ultrasonix_file, h)) 
+    {
+        fclose(Ultrasonix_file);
+        std::cout << "cannot read Ultrasonix Attributes for RF file [" << filename << "]" << std::endl;  
+       return;
+    }
+
+    fclose(Ultrasonix_file);  
+  
+    // Columns
+    char cols[128];
+    sprintf(cols,"%i", h.width);
+    // Rows
+    char rows[128];
+    sprintf(rows,"%i", h.height);
+    // Planes 
+    char planes[128];
+    sprintf(planes,"%i", h.frame);
+    // Sampling frequency
+    char samplingFrequency[128];
+    sprintf(samplingFrequency,"%i", h.samplingRate);
+    // Transducer frequency
+    char transducerFrequency[128];
+    sprintf(transducerFrequency,"%i", h.frequency);
+   
+    // 
+    std::map<std::string,std::string>::iterator i;
+    if ( (i = attr.find("FullFileName")) != attr.end())
+    {
+          i->second = filename;
+    }
+    if ( (i = attr.find("D0004_1500")) != attr.end())
+    {
+          boost::filesystem::path full_path(filename);
+          std::string f = full_path.leaf();
+          i->second = f;
+    }
+    if ( (i = attr.find("D0028_0010")) != attr.end())
+    {
+          i->second = rows;
+    }
+    if ( (i = attr.find("D0028_0011")) != attr.end())
+    {
+          i->second = cols;
+    }
+    if ( (i = attr.find("D0028_0012")) != attr.end())
+    {
+          i->second = planes;
+    }
+    if ( (i = attr.find("D003a_001a")) != attr.end())
+    {
+       i->second = samplingFrequency;
+    }
+    if ( (i = attr.find("D0018_6030")) != attr.end())
+    {
+          i->second = transducerFrequency;
+    }
+    
+    GimmickMessage(2,"Attributes map:"<<std::endl<<attr<<std::endl);
+    return;
+}
+  //=====================================================================
+
+} // namespace creaImageIO
diff --git a/src/creaImageIOUltrasonixImageReader.h b/src/creaImageIOUltrasonixImageReader.h
new file mode 100644 (file)
index 0000000..c0c9c54
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __creaImageIOUltrasonixImageReader_h_INCLUDED__
+#define __creaImageIOUltrasonixImageReader_h_INCLUDED__
+
+#include <creaImageIOAbstractImageReader.h>
+#include <creaImageIOSystem.h>
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup IO
+   */
+  
+  //=====================================================================
+  /// Concrete image reader for ultrasonix 'rf' files
+  class CREAIMAGEIO_EXPORT UltrasonixImageReader : virtual public AbstractImageReader
+  {
+  public:
+    UltrasonixImageReader();
+
+    virtual ~UltrasonixImageReader();
+       /// Add file extensions read by the reader
+    virtual void PushBackExtensions(std::vector<std::string>&);
+       /// Test if file is read by this reader
+    virtual bool CanRead(const std::string& filename);
+       /// return for a file a 2D VTkImage
+    virtual vtkImageData* ReadImage(const std::string& filename);
+       /// Read the attributes for a file
+    virtual void ReadAttributes(const std::string& filename, 
+                               tree::AttributeMapType& attr);
+
+  };
+  //=====================================================================
+
+} // namespace creaImageIO
+
+#endif // #ifndef __creaImageIOUltrasonixImageReader_h_INCLUDED__
diff --git a/src/creaImageIOVtkImageReader.cpp b/src/creaImageIOVtkImageReader.cpp
new file mode 100644 (file)
index 0000000..0d3780a
--- /dev/null
@@ -0,0 +1,167 @@
+#include <creaImageIOVtkImageReader.h>
+#include <vtkImageReader2.h>
+#include <creaImageIOSystem.h>
+#include "boost/filesystem/path.hpp"
+
+namespace creaImageIO{
+  //=====================================================================
+  VtkImageReader::VtkImageReader(vtkImageReader2* r, 
+                                      const std::string& name,
+                                      const std::string& extensions)
+    : mReader(r), mExtensions(extensions)
+  {
+    if (name.size() == 0) 
+      {
+                 const char *test =mReader->GetDescriptiveName();
+                 if(test != "")
+                 {
+                       SetName ( "toto");// mReader->GetDescriptiveName());
+                 }
+               
+      }
+    else 
+      {
+       SetName ( name );
+      }
+    GimmickDebugMessage(5,"Constructing vtkImageReader : "<<GetName()
+                       <<std::endl);
+      
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  VtkImageReader::~VtkImageReader()
+  {
+
+    mReader->Delete();
+  }
+  //=====================================================================
+
+  //=====================================================================
+  bool VtkImageReader::CanRead(const std::string& filename)
+  { 
+
+    return (mReader->CanReadFile(filename.c_str())!=0);
+/*       if(filename != "")
+         {
+               return (mReader->CanReadFile(filename.c_str())!=0);
+         }
+         else
+         {
+                 return false;
+         }*/
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  vtkImageData* VtkImageReader::ReadImage(const std::string& filename)
+  {
+    vtkImageData* im = 0;
+    try
+      {
+       mReader->SetFileName(filename.c_str());
+       mReader->Update();
+       im = vtkImageData::New();
+       im->ShallowCopy(mReader->GetOutput());
+      }
+    catch (...)
+      {
+       if (im!=0) im->Delete();
+       im = 0;
+      }
+    return im;
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  void SplitExtensionsString ( const std::string& str, 
+                              const std::string& delimiters, 
+                              std::vector<std::string>& tokens)
+  {
+    // Skip delimiters at beginning.
+    std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
+    // Find first delimiter.
+    std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
+    
+    while (std::string::npos != pos || std::string::npos != lastPos)
+      {
+       // Found a token, add it to the vector.
+       // SPECIFIC : REMOVE INITIAL DOT (lastPos + 1)
+       tokens.push_back(str.substr(lastPos+1, pos - lastPos));
+       // Skip delimiters.  Note the "not_of"
+       lastPos = str.find_first_not_of(delimiters, pos);
+       // Find next delimiter
+       pos = str.find_first_of(delimiters, lastPos);
+      }
+    
+    }
+  //=====================================================================
+  
+  //=====================================================================
+  void VtkImageReader::PushBackExtensions(std::vector<std::string>& v)
+  {
+    std::string ext = mExtensions;
+    if (ext.size()==0) ext = mReader->GetFileExtensions ();
+    
+    SplitExtensionsString(ext," ",v);
+  }
+  //=====================================================================
+
+
+  //=====================================================================
+  void VtkImageReader::ReadAttributes(const std::string& filename, 
+                                     std::map<std::string,std::string>& attr)
+  {
+    GimmickMessage(2,"Reading attributes from '"<<filename<<std::endl);
+    // Get image dimensions
+    // How to get the image info without loading it in vtk ?
+    mReader->SetFileName(filename.c_str());
+    mReader->Update(); //OpenFile();
+    int ext[6];
+    mReader->GetDataExtent(ext);
+    // Columns
+    char cols[128];
+    sprintf(cols,"%i",ext[1]-ext[0]);
+    // Rows
+    char rows[128];
+    sprintf(rows,"%i",ext[3]-ext[2]);
+    // Planes 
+    char planes[128];
+    sprintf(planes,"%i",ext[5]-ext[4]);
+   
+       std::map<std::string,std::string>::iterator i;
+    if ( (i = attr.find("FullFileName")) != attr.end())
+      {
+       i->second = filename;
+      }
+    if ( (i = attr.find("D0004_1500")) != attr.end())
+      {
+       boost::filesystem::path full_path(filename);
+       std::string f = full_path.leaf();
+       i->second = f;
+      }
+    if ( (i = attr.find("D0028_0010")) != attr.end())
+      {
+       i->second = rows;
+      }
+    if ( (i = attr.find("D0028_0011")) != attr.end())
+      {
+       i->second = cols;
+      }
+    
+    if ( (i = attr.find("D0028_0012")) != attr.end())
+      {
+               i->second = planes;
+      }
+         if ( (i = attr.find("FullFileDirectory")) != attr.end())
+      {
+        std::string::size_type last_pos = filename.find_last_of("//");
+                i->second = filename.substr(0, last_pos);
+         }
+
+    GimmickMessage(2,"Attributes map:"<<std::endl<<attr<<std::endl);
+  }
+  //=====================================================================
+
+} // namespace creaImageIO
diff --git a/src/creaImageIOVtkImageReader.h b/src/creaImageIOVtkImageReader.h
new file mode 100644 (file)
index 0000000..44e8f23
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef __creaImageIOVtkImageReader_h_INCLUDED__
+#define __creaImageIOVtkImageReader_h_INCLUDED__
+
+
+#include <creaImageIOAbstractImageReader.h>
+
+// forward decl
+class vtkImageReader2;
+
+namespace creaImageIO
+{
+
+
+  /**
+   * \ingroup IO
+   */
+  
+  //=====================================================================
+  /// Concrete image reader based on a vtkImageReader2 
+  class VtkImageReader : virtual public AbstractImageReader
+  {
+  public:
+    VtkImageReader(vtkImageReader2* reader, 
+                  const std::string& name = "",
+                  const std::string& extensions = "");
+
+    virtual ~VtkImageReader();
+
+
+
+       /// Add file extensions read by the reader
+    virtual void PushBackExtensions(std::vector<std::string>&);
+       /// Test if file is read by this reader
+    virtual bool CanRead(const std::string& filename);
+       /// return for a file a 2D VTkImage
+    virtual vtkImageData* ReadImage(const std::string& filename);
+       /// Read the attributes for a file
+    virtual void ReadAttributes(const std::string& filename, 
+                               tree::AttributeMapType& attr);
+
+  private:
+    vtkImageReader2* mReader;
+    std::string mExtensions;
+  };
+  //=====================================================================
+
+
+
+} // namespace creaImageIO
+
+
+
+#endif // #ifndef __creaImageIOVtkImageReader_h_INCLUDED__
diff --git a/src/creaImageIOWxAttributeSelectionPanel.cpp b/src/creaImageIOWxAttributeSelectionPanel.cpp
new file mode 100644 (file)
index 0000000..29538b9
--- /dev/null
@@ -0,0 +1,193 @@
+#include <creaImageIOWxAttributeSelectionPanel.h>
+#include <creaImageIOSystem.h>
+
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+       const int  ID_COMBO             = 180;
+  // CTor
+  WxAttributeSelectionPanel::WxAttributeSelectionPanel(wxWindow *parent, 
+         wxDialog* dial, 
+         WxGimmickView* view,
+         std::vector<std::string> sAtts,
+         std::vector<std::string> nsAtts,
+         int numLev)
+ :   wxPanel( parent, 
+                 -1, wxDefaultPosition, 
+                 wxDefaultSize,
+                 wxRESIZE_BORDER | 
+             wxSYSTEM_MENU  |
+                 wxCLOSE_BOX |
+                 wxMAXIMIZE_BOX | 
+                 wxMINIMIZE_BOX | 
+                 wxCAPTION  
+              ),       
+                  dialog(dial),
+                  shownA(sAtts),
+                  notShownA(nsAtts),
+                  mView(view)
+  {
+    GimmickDebugMessage(1,"WxCustomizeConfigPanel::WxCustomizeConfigPanel"
+                       <<std::endl);
+       wxStaticText * aa=new wxStaticText(this,-1,_T(" Currently shown attributes for level: "), wxPoint(5,10));
+       wxArrayString as;
+       std::stringstream out;
+       for(int i=1;i<=numLev;i++)
+       {
+               out<<i;
+               as.Add(crea::std2wx(out.str()));
+               out.str("");
+       }
+       levels=new wxComboBox(this, ID_COMBO,_T("1"),wxPoint(190, 5),wxDefaultSize,as);
+       wxStaticText * na=new wxStaticText(this,-1,_T(" Currently hidden attributes: "), wxPoint(255,10));
+
+    shownAtts=new wxListCtrl(this, wxID_ANY, wxPoint(5,30), wxSize(160,90), wxLC_REPORT | wxLC_NO_HEADER );
+
+       shownAtts->InsertColumn(0, 
+                                  crea::std2wx(""),
+                                  wxLIST_FORMAT_LEFT);
+       shownAtts->SetColumnWidth(0,155);
+       shownAtts->Show();
+
+       wxButton *add = new wxButton(this,wxID_ANY,_T(">>"), wxPoint(170,50) );
+       Connect( add->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxAttributeSelectionPanel::OnAdd ); 
+
+       wxButton *remove = new wxButton(this,wxID_ANY,_T("<<"), wxPoint(170,70) );
+       Connect( remove->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxAttributeSelectionPanel::OnRemove ); 
+       
+       notShownAtts=new wxListCtrl(this, wxID_ANY, wxPoint(255,30), wxSize(160,90), wxLC_REPORT | wxLC_NO_HEADER );
+
+       notShownAtts->InsertColumn(0, 
+                                  crea::std2wx(""),
+                                  wxLIST_FORMAT_LEFT);
+       notShownAtts->SetColumnWidth(0,155);
+       notShownAtts->Show();
+       LoadCtrls();
+
+       wxButton *save = new wxButton(this,wxID_ANY,_T("Save Changes"), wxPoint(5,130) );
+       Connect( save->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxAttributeSelectionPanel::OnSaveConfig ); 
+   
+    Layout(); 
+  }
+
+  /// Destructor
+  WxAttributeSelectionPanel::~WxAttributeSelectionPanel()
+  {
+    GimmickDebugMessage(1,"WxAttributeSelectionPanel::~WxAttributeSelectionPanel"
+                       <<std::endl);
+  }
+
+  void WxAttributeSelectionPanel::OnSaveConfig(wxCommandEvent& event)
+  {
+         int n=levels->GetSelection();
+         if(n<0){n=0;}
+         mView->OnAttributesChanged(notShownA,n);
+         dialog->Destroy();
+  }
+
+  void WxAttributeSelectionPanel::OnAdd(wxCommandEvent& event)
+  {
+       long item = -1;
+       for ( ;; )
+       {
+               item = shownAtts->GetNextItem(item,
+                       wxLIST_NEXT_ALL,
+                       wxLIST_STATE_SELECTED);
+               if ( item == -1 )
+                       break;
+       
+                       std::string change = crea::wx2std(shownAtts->GetItemText(item));
+                       std::vector<std::string>::iterator it;
+                       bool found=false;
+                       for(it=shownA.begin();it!=shownA.end()&&!found;++it)
+                       {
+                               if((*it).compare(change)==0)
+                               {
+                                       found=true;
+                               }
+                       }
+                       shownA.erase(it-1);
+                       notShownA.push_back(change);
+       }
+       LoadCtrls();
+       
+  }
+
+  void WxAttributeSelectionPanel::OnRemove(wxCommandEvent& event)
+  {
+
+       long item = -1;
+       for ( ;; )
+       {
+               item = notShownAtts->GetNextItem(item,
+                       wxLIST_NEXT_ALL,
+                       wxLIST_STATE_SELECTED);
+               if ( item == -1 )
+                       break;
+       
+                       std::string change = crea::wx2std(notShownAtts->GetItemText(item));
+                       std::vector<std::string>::iterator it;
+                       bool found=false;
+                       for(it=notShownA.begin();it!=notShownA.end()&&!found;++it)
+                       {
+                               if((*it).compare(change)==0)
+                               {
+                                       found=true;
+                               }
+                       }
+                       notShownA.erase(it-1);
+                       shownA.push_back(change);
+               
+       }
+       LoadCtrls();    
+         
+  }
+  
+
+  void WxAttributeSelectionPanel::LoadCtrls()
+  {
+
+         wxListItem item;
+           item.SetMask(wxLIST_MASK_STATE | 
+                        wxLIST_MASK_TEXT |
+                        //                      wxLIST_MASK_IMAGE |
+                        wxLIST_MASK_DATA |
+                        //                      wxLIST_MASK_WIDTH |
+                        wxLIST_MASK_FORMAT
+                        );
+       std::vector<std::string>::iterator it;
+       shownAtts->DeleteAllItems();
+       notShownAtts->DeleteAllItems();
+       for(it=shownA.begin();it!=shownA.end();++it)
+       {
+               item.SetText(crea::std2wx(*it));
+               shownAtts->InsertItem(item);
+       }
+
+       
+       for(it=notShownA.begin();it!=notShownA.end();++it)
+       {
+               item.SetText(crea::std2wx(*it));
+               notShownAtts->InsertItem(item);
+       }
+
+  }
+  void WxAttributeSelectionPanel::OnComboChange(wxCommandEvent& event)
+  {
+      int n=levels->GetSelection()+1;
+         mView->GetVisibleAttributes(shownA,notShownA,n);
+         LoadCtrls();
+  }
+  
+//======================================================================
+BEGIN_EVENT_TABLE(WxAttributeSelectionPanel, wxPanel)
+EVT_COMBOBOX  (ID_COMBO,WxAttributeSelectionPanel::OnComboChange)
+END_EVENT_TABLE()
+//======================================================================
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxAttributeSelectionPanel.h b/src/creaImageIOWxAttributeSelectionPanel.h
new file mode 100644 (file)
index 0000000..5700fd5
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __creaImageIOWxAttributeSelectionPanel_h_INCLUDED__
+#define __creaImageIOWxAttributeSelectionPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <creaImageIOWxGimmickView.h>
+#include <wx/listctrl.h>
+
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  class WxAttributeSelectionPanel : public wxPanel
+  {
+  public:
+    WxAttributeSelectionPanel();    
+       WxAttributeSelectionPanel(wxWindow *parent, 
+               wxDialog* dial,
+               WxGimmickView* view,
+               std::vector<std::string> sAtts,
+           std::vector<std::string> nsAtts,
+               int numLev);
+    
+    ~WxAttributeSelectionPanel();
+       ///Saves the configuration
+        void OnSaveConfig(wxCommandEvent& event);
+        ///Changes items from shown to notShown
+        void OnAdd(wxCommandEvent& event);
+        ///Changes items from notShown to shown
+        void OnRemove(wxCommandEvent& event);
+        void OnComboChange(wxCommandEvent& event);
+  
+
+  private :
+         ///Loads the information on the vectors onto the lists
+          void LoadCtrls();
+         std::vector<std::string> shownA;
+         std::vector<std::string> notShownA;
+         wxComboBox* levels;
+         wxListCtrl* shownAtts;
+         wxListCtrl* notShownAtts;
+       wxDialog* dialog;
+       WxGimmickView* mView;
+
+       
+       DECLARE_EVENT_TABLE()
+
+  }; // class WxAttributeSelectionPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
diff --git a/src/creaImageIOWxCustomizeConfigPanel.cpp b/src/creaImageIOWxCustomizeConfigPanel.cpp
new file mode 100644 (file)
index 0000000..c28a37d
--- /dev/null
@@ -0,0 +1,69 @@
+#include <creaImageIOWxCustomizeConfigPanel.h>
+#include <creaImageIOSystem.h>
+namespace creaImageIO
+{
+  // CTor
+  WxCustomizeConfigPanel::WxCustomizeConfigPanel(wxWindow *parent, wxDialog* dial, WxGimmickView* view, const std::string& cPath, 
+               const std::string& dPath,
+               const std::string& sEvent,
+               const std::string& sFreq)
+ :   wxPanel( parent, 
+                 -1, wxDefaultPosition, 
+                 wxDefaultSize,
+                 wxRESIZE_BORDER | 
+             wxSYSTEM_MENU  |
+                 wxCLOSE_BOX |
+                 wxMAXIMIZE_BOX | 
+                 wxMINIMIZE_BOX | 
+                 wxCAPTION  
+              ),       
+                  dialog(dial),
+                  copyP (cPath), 
+                  databaseP(dPath), 
+                  syncEv(sEvent), 
+                  syncFr(sFreq),
+                  mView(view)
+  {
+    GimmickDebugMessage(1,"WxCustomizeConfigPanel::WxCustomizeConfigPanel"
+                       <<std::endl);
+       wxStaticText * cp=new wxStaticText(this,-1,_T(" Copy Path: "), wxPoint(5,10));
+    copyPath=new wxTextCtrl(this, wxID_ANY, crea::std2wx(copyP), wxPoint(150,10), wxSize(250,20));
+
+       wxStaticText * dp=new wxStaticText(this,-1,_T(" Database Path: "), wxPoint(5,40));
+       dbPath=new wxTextCtrl(this, wxID_ANY, crea::std2wx(databaseP), wxPoint(150,40), wxSize(250,20));
+
+       wxStaticText * se=new wxStaticText(this,-1,_T(" Synchronization Event: "), wxPoint(5,70));
+       syncEvent=new wxTextCtrl(this, wxID_ANY, crea::std2wx(syncEv), wxPoint(150,70), wxSize(250,20));
+
+       wxStaticText * sf=new wxStaticText(this,-1,_T(" Synchronization Frequency: "), wxPoint(5,100));
+       syncFrequency=new wxTextCtrl(this, wxID_ANY, crea::std2wx(syncFr), wxPoint(150,100), wxSize(250,20));
+
+       wxButton *save = new wxButton(this,wxID_ANY,_T("Save Changes"), wxPoint(5,130) );
+       Connect( save->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxCustomizeConfigPanel::OnSaveConfig ); 
+  
+    Layout(); 
+  }
+
+  /// Destructor
+  WxCustomizeConfigPanel::~WxCustomizeConfigPanel()
+  {
+    GimmickDebugMessage(1,"WxCustomizeConfigPanel::~WxCustomizeConfigPanel"
+                       <<std::endl);
+  }
+
+  void WxCustomizeConfigPanel::OnSaveConfig(wxCommandEvent& event)
+  {
+         mView->OnSaveSettingsCallback(crea::wx2std(copyPath->GetValue()),
+                 crea::wx2std(dbPath->GetValue()),
+                 crea::wx2std(syncEvent->GetValue()),
+                 crea::wx2std(syncFrequency->GetValue()));
+         dialog->Destroy();
+  }
+  
+//======================================================================
+  
+//====================================================================== 
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxCustomizeConfigPanel.h b/src/creaImageIOWxCustomizeConfigPanel.h
new file mode 100644 (file)
index 0000000..0152af1
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __creaImageIOWxCustomizeConfigPanel_h_INCLUDED__
+#define __creaImageIOWxCustomizeConfigPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <creaImageIOWxGimmickView.h>
+
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  class WxCustomizeConfigPanel : public wxPanel
+  {
+  public:
+    WxCustomizeConfigPanel();    
+       WxCustomizeConfigPanel(wxWindow *parent, 
+               wxDialog* dial,
+               WxGimmickView* view,
+               const std::string& cPath, 
+               const std::string& dPath,
+               const std::string& sEvent,
+               const std::string& sFreq);
+    
+    ~WxCustomizeConfigPanel();
+       ///Saves the configuration
+        void OnSaveConfig(wxCommandEvent& event);
+
+  private :
+       std::string copyP;
+       std::string databaseP;
+       std::string syncEv;
+       std::string syncFr;
+    wxTextCtrl* copyPath;
+       wxTextCtrl* dbPath;
+       wxTextCtrl* syncEvent;
+       wxTextCtrl* syncFrequency;
+       wxDialog* dialog;
+       WxGimmickView* mView;
+
+
+  }; // class WxCustomizeConfigPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
diff --git a/src/creaImageIOWxDescriptorPanel.cpp b/src/creaImageIOWxDescriptorPanel.cpp
new file mode 100644 (file)
index 0000000..d50de1f
--- /dev/null
@@ -0,0 +1,816 @@
+#include "creaImageIOWxDescriptorPanel.h"
+#include <creaImageIOSystem.h>
+#if defined(USE_GDCM)
+#include <gdcmGlobal.h>
+#include <gdcmDictSet.h>
+#endif
+
+#if defined(USE_GDCM2)
+#include <gdcmGlobal.h>
+#include <gdcmDicts.h>
+#include <gdcmDict.h>
+#endif
+#include <boost/algorithm/string.hpp>
+
+namespace creaImageIO
+{
+  // CTor
+                  
+       WxDescriptorPanel::WxDescriptorPanel(wxWindow *parent, const std::string path)
+               : wxDialog(parent, -1,_T("Descriptor Creation"), wxDefaultPosition, wxSize(550,550)) , m_path(path)
+{
+
+  
+    GimmickDebugMessage(1,"WxDescriptorPanel::WxDescriptorPanel"
+                       <<std::endl);
+
+       lv = 0;
+       ownatt["FullFileName"]      = "Full_File_Name";
+       ownatt["FullFileDirectory"] = "Full_File_Directory";
+       
+
+       // START BUTTONS
+       wxButton *NewDescriptor = new wxButton(this, -1,_T("Create a new descriptor"), wxPoint(10,7) );
+       Connect( NewDescriptor->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnNew ); 
+
+       wxButton *LoadDescriptor = new wxButton(this, -1,_T("Load a descriptor"), wxPoint(150,7) );
+       Connect( LoadDescriptor->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnLoad ); 
+       
+       wxStaticLine *line1 = new wxStaticLine(this, -1, wxPoint(5,40), wxSize(540,2));
+
+       // LEVEL
+       wxStaticText * LevelText=new wxStaticText(this,-1,_T(" Level: "), wxPoint(5,50));
+       LevelCtrl=new wxTextCtrl(this, ID_GR_CTRL,_T("patient"), wxPoint(50,50), wxSize(50,25));
+       wxButton *addLevel = new wxButton(this, ID_LEVEL_ADD,_T("add a level"), wxPoint(150,50) );
+       Connect( addLevel->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnAddLevel ); 
+
+       wxStaticLine *line2 = new wxStaticLine(this, -1, wxPoint(5,75), wxSize(540,2));
+
+       // ATTRIBUTES
+
+       wxStaticText * GR=new wxStaticText(this,-1,_T(" DICOM Group: "), wxPoint(5,110));
+        GRCtrl=new wxTextCtrl(this, ID_GR_CTRL,_T("0x0010"), wxPoint(82,110), wxSize(50,25));
+       Connect( GRCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED , (wxObjectEventFunction) &WxDescriptorPanel::OnDicomAttribute ); 
+       
+       wxStaticText * EL=new wxStaticText(this,-1,_T(" DICOM Element: "), wxPoint(140,110));
+       ELCtrl=new wxTextCtrl(this, ID_EL_CTRL,_T("0x0010"), wxPoint(230,110), wxSize(50,25));
+       Connect( ELCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED , (wxObjectEventFunction) &WxDescriptorPanel::OnDicomAttribute ); 
+
+       
+       wxString choices[3];
+       choices[0] = _T("Unknow Attribute");
+       std::map<std::string, std::string>::iterator it_att =ownatt.begin();
+       for(int i = 1; it_att != ownatt.end(); it_att++, i++)
+       {
+               choices[i] = crea::std2wx(it_att->second);
+       }
+       
+
+       AttributeCombo  = new wxComboBox(this, ID_ATTRIBUTE_CTRL,_T(""),wxPoint(300,110), wxSize(120,25),3,choices, wxCB_READONLY);
+       AttributeCombo->SetSelection(0);
+       
+
+       wxButton *addAttribute = new wxButton(this, ID_ATTRIBUTE_ADD,_T("add an attribute"), wxPoint(440,110) );
+       Connect( addAttribute->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnAddAttribute ); 
+
+       wxStaticLine *line3 = new wxStaticLine(this, -1, wxPoint(5,140), wxSize(540,2));
+
+       // RESULT
+
+       ResultCtrl=new wxTextCtrl(this, ID_EL_CTRL,_T(""), wxPoint(5,150), wxSize(250,310), wxTE_READONLY| wxMac | wxTE_MULTILINE | wxTE_RICH );
+       wxButton *RemoveCtrl = new wxButton(this, ID_REMOVE_ADD,_T("Remove an entry"), wxPoint(280,200) );
+       Connect( RemoveCtrl->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnRemove ); 
+
+       wxStaticLine *line4 = new wxStaticLine(this, -1, wxPoint(5,470), wxSize(540,2));
+       // VALIDATION BUTTON
+       wxButton *Ok = new wxButton(this, -1,_T("OK"), wxPoint(10,480) );
+       Connect( Ok->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnOK ); 
+
+       wxButton *Apply = new wxButton(this, -1,_T("APPLY"), wxPoint(150,480) );
+       Connect( Apply->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxDescriptorPanel::OnApply ); 
+       
+       wxButton *Cancel = new wxButton(this, wxID_CANCEL,_T("CANCEL"), wxPoint(250,480) );
+//     Connect( Cancel->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxCloseEvent) &wxWindow::Close ); 
+
+        Layout(); 
+       CreateDescriptor(0);
+  }
+
+  /// Destructor
+  WxDescriptorPanel::~WxDescriptorPanel()
+  {
+    GimmickDebugMessage(1,"WxCustomizeConfigPanel::~WxCustomizeConfigPanel"
+                       <<std::endl);
+  }
+
+    //////////////////////////////////////////////////////////
+  // Add an attribute  //
+  // @param event : Wxevent  //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  void WxDescriptorPanel::OnAddAttribute(wxCommandEvent& event)
+  {
+         std::string name_lv;
+         std::string name_att;
+         if (AttributeCombo->GetSelection() == 0)
+         {
+             name_att = "D" + crea::wx2std(GRCtrl->GetValue()) + "_" + crea::wx2std(ELCtrl->GetValue());
+         }
+         else
+         {     
+            wxString wd = AttributeCombo->GetValue();
+            std::string st = crea::wx2std(wd);
+            name_att = OwnAttribute(st);
+         }
+         onAddAttribute(crea::wx2std(AttributeCombo->GetValue()), name_att);
+  }
+  //////////////////////////////////////////////////////////
+  // add an attribute  //
+  // @param att :  attribute //
+  // @param name_att :  's name //
+  // @param level : level to add the attribute  //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  void WxDescriptorPanel::onAddAttribute( const std::string &att, const std::string &name_att,std::string level )
+  {
+         if(lv == 0)
+         {
+                 wxMessageBox(_T("Need a level first!"),crea::std2wx("WARNING"),wxOK,this);
+         }
+         else
+         {
+               if( !att.empty() )
+               {
+               // Find Name of level
+                       if(level.empty())
+                       {
+                               level = findLevel();
+                       }
+
+                       if (!addAtribute(level, name_att))
+                       {
+                               wxMessageBox(_T("Attribute already used in this level"),crea::std2wx("WARNING"),wxOK,this);
+                       }
+                       else
+                       {
+                               ResultCtrl->SetInsertionPoint(InsertPt);
+                for (int i = 1; i<=lv;i++)
+                               { 
+                                  ResultCtrl->WriteText(_T("   "));
+                               }
+                               ResultCtrl->WriteText(_T("| - "));
+                               ResultCtrl->WriteText(crea::std2wx(att));
+                               wxTextAttr ResultAttr(ResultCtrl->GetDefaultStyle());
+                               ResultAttr.SetTextColour(*wxWHITE);
+                               ResultCtrl->SetDefaultStyle(ResultAttr);
+                               std::string text = " ";
+                               ResultCtrl->WriteText(crea::std2wx(" " + name_att));
+                               ResultAttr.SetTextColour(*wxBLACK);
+                               ResultCtrl->SetDefaultStyle(ResultAttr);
+                               ResultCtrl->WriteText(_T("\n"));
+                       }
+                       InsertPt = ResultCtrl->GetInsertionPoint();
+               }
+         }
+  }
+  
+    //////////////////////////////////////////////////////////
+  // add a level //
+  // @param event : Wxevent  //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  void WxDescriptorPanel::OnAddLevel(wxCommandEvent& event)
+  {
+         if( !LevelCtrl->GetValue().IsEmpty() )
+         {
+                 onAddLevel(crea::wx2std(LevelCtrl->GetValue()));
+         }
+  }
+
+    //////////////////////////////////////////////////////////
+  // add a level  //
+  // @param level : level's name   //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  void WxDescriptorPanel::onAddLevel(const std::string &level)
+  {
+                 if(addLevel(level))
+                 {
+                         wxMessageBox(_T("Level already used"),crea::std2wx(("WARNING")),wxOK,this);
+                         return;
+                 }
+                 
+                  lv++;
+                  ResultCtrl->SetInsertionPoint(InsertPt);
+                  for (int i = 1; i<lv;i++)
+                  { 
+                          ResultCtrl->WriteText(_T("   "));
+                  }
+                  if(lv>1)
+                  {    ResultCtrl->WriteText(_T("| \n"));
+                               for (int i = 1; i<lv;i++)
+                               { 
+                                       ResultCtrl->WriteText(_T("   "));
+                               }
+                               ResultCtrl->WriteText(_T("|_"));
+                  }
+                  
+                       wxTextAttr ResultAttr(ResultCtrl->GetDefaultStyle());
+                       ResultAttr.SetTextColour(*wxRED);
+                       ResultCtrl->SetDefaultStyle(ResultAttr);
+                       ResultCtrl->WriteText(crea::std2wx(level));
+                       ResultAttr.SetTextColour(*wxBLACK);
+                       ResultCtrl->SetDefaultStyle(ResultAttr);
+                       ResultCtrl->WriteText(_T("\n"));
+                       InsertPt = ResultCtrl->GetInsertionPoint();
+         
+  }
+
+    //////////////////////////////////////////////////////////
+  // Find a DICOM attribute from group and element values //
+  // @param event : Wxevent  //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  void WxDescriptorPanel::OnDicomAttribute(wxCommandEvent& event)
+  {
+         int i = 0;
+         if(!GRCtrl->GetValue().IsEmpty() && !ELCtrl->GetValue().IsEmpty() 
+                 && GRCtrl->GetValue().Len() == 6 && ELCtrl->GetValue().Len() == 6 && AttributeCombo->GetSelection() == 0)
+         {
+
+                 std::string gr = crea::wx2std(GRCtrl->GetValue());
+                 std::string el = crea::wx2std(ELCtrl->GetValue());
+                 std::stringstream val;
+       
+                 unsigned short group;
+                 unsigned short element;
+                 val <<   std::dec << gr ;
+                 val >> std::hex >> group;
+                 val.clear();
+                 val <<   std::dec << el ;
+                 val >> std::hex >> element;
+#if defined(USE_GDCM)  
+                // Retrieve the name from gdcm dict
+                 GDCM_NAME_SPACE::DictEntry* entry = GDCM_NAME_SPACE::Global::GetDicts()->GetDefaultPubDict()->GetEntry(group, element);
+                // AttributeCombo->Clear();
+                 if(entry)
+                 {
+                         AttributeCombo->Delete(0);
+                         AttributeCombo->Insert(crea::std2wx(entry->GetName()), 0);
+                 }
+                 else
+                 {
+                         AttributeCombo->Delete(0);
+                         AttributeCombo->Insert(_T("Unknown Attribute"),0);
+                 }
+#endif
+                         AttributeCombo->SetSelection(0);
+               
+         }
+    
+  }
+
+
+   //////////////////////////////////////////////////////////
+  // determine values for own attributes //
+  // @param name : attribute's name  //
+  // @param key : indicates key map or not  //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  std::string WxDescriptorPanel::OwnAttribute(const std::string name)
+  {
+         std::string result;
+
+         std::map<std::string, std::string>::iterator it_att = ownatt.begin();
+         for(; it_att != ownatt.end(); it_att++)
+         {
+                 if(it_att->second == name)
+                 {
+                         result = it_att->first.c_str();
+                         break;
+                 }
+         }
+         return result;
+  }
+       
+  //////////////////////////////////////////////////////////
+  // Find a level in function of position in Return Ctrl  //
+  // @param - :   //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  std::string WxDescriptorPanel::findLevel()
+  {
+         long column;
+         long line;
+         
+         ResultCtrl->PositionToXY( ResultCtrl->GetInsertionPoint(),&column, &line);
+         std::string tx(crea::wx2std(ResultCtrl->GetRange(0, ResultCtrl->XYToPosition(0,line+1))).c_str());
+         std::string::size_type level_pos_start = tx.rfind("|_");
+         if(level_pos_start == -1)
+         {
+                 level_pos_start = 0;
+         }
+         else
+         {
+                 level_pos_start += 2;
+         }
+
+         std::string::size_type level_pos_end = tx.find_first_of("\n",level_pos_start);
+         return  tx.substr(level_pos_start,level_pos_end - level_pos_start);
+  }
+
+  //////////////////////////////////////////////////////
+  // Remove an item                              //
+  // @param event : Wxevent  //
+  // @return : -                                                 //
+  //////////////////////////////////////////////////
+  void WxDescriptorPanel::OnRemove(wxCommandEvent& event)
+  {
+         long line;
+         long column;
+         long pos_start;
+         long pos_end;
+
+         pos_start = ResultCtrl->GetInsertionPoint();
+         ResultCtrl->PositionToXY( pos_start,&column, &line);
+         if (line == 0) 
+         {
+                 std::string name("root");
+                 RemoveLevel(name);
+                 ResultCtrl->Clear();
+                 lv = 0;
+         }
+         else
+         {
+               wxString text = ResultCtrl->GetLineText(line);
+               if ( text.Find(_T("|_")) == -1)
+               {
+                 std::string level = findLevel();
+                 // find GR and EL values to remove
+                 std::string tx = crea::wx2std(text);
+                 std::string::size_type  EL_start_pos = tx.find_last_of(" ");
+                 RemoveAttribute(level, tx.substr(EL_start_pos+1,tx.size() - EL_start_pos));
+                 ResultCtrl->Remove( ResultCtrl->XYToPosition(0,line), ResultCtrl->XYToPosition(0,line+1));
+               }
+               else
+               {       
+                        RemoveLevel(crea::wx2std(text.AfterFirst('_')));
+                        lv = text.Find(_T("|"))/3;
+                        pos_start= ResultCtrl->XYToPosition(0,line-1);
+                        ResultCtrl->SetInsertionPointEnd();
+                        pos_end = ResultCtrl->GetInsertionPoint();
+                        ResultCtrl->Remove(pos_start, pos_end);
+               }
+         }
+
+  }
+   //////////////////////////////////////////////
+  // create a descriptor structure              //
+  // @param name : level's name to add           //
+  // @return : boolean result                   //
+  //////////////////////////////////////////////////
+   void WxDescriptorPanel::CreateDescriptor(int type)
+   {
+          if(type == 0) // First initialization
+          {
+                  outDscp.clear();
+                  outDscp += "<level>";
+                  outDscp += "\n";
+                  outDscp += "root";
+                  outDscp += "\n";
+                  outDscp += "O Name Name 4";
+                  outDscp += "\n";
+          }
+          if(type == 1)
+          {
+                  if(lv > 1)
+                  {
+                       outDscp += "O NumberOfChildren ";
+                       outDscp += crea::wx2std(LevelCtrl->GetValue());
+                       outDscp += "s";
+                       outDscp += "\n";
+                  }
+                  outDscp += "<level>";
+                  outDscp += "\n";
+                  outDscp += crea::wx2std(LevelCtrl->GetValue());
+                  outDscp += "\n";
+                  
+          }
+          if(type == 2)
+          {
+                  outDscp += "D";
+                  outDscp += " ";
+                  outDscp += crea::wx2std(GRCtrl->GetValue());
+                  outDscp += " ";
+                  outDscp += crea::wx2std(ELCtrl->GetValue());
+                  outDscp += " ";
+                  outDscp += "3";
+                  outDscp += "\n";
+          }
+          
+
+   }
+
+
+  //////////////////////////////////////////////////////
+  // add a level                                 //
+  // @param name : level's name to add  //
+  // @return : boolean result                                            //
+  //////////////////////////////////////////////////
+   bool WxDescriptorPanel::addLevel(const std::string &name)
+   {
+          bool bfound = false;
+          std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+          for (;it_tree != DscpTree.end(); it_tree++)
+          {
+                  if(it_tree->first == name)
+                  {
+                          bfound = true;
+                          break;
+                  }
+          }
+          if(!bfound)
+          {
+                   lvlist[lv] = name;
+                       std::vector <std::string> branch;
+                       DscpTree[name] = branch;
+          }
+               return bfound;
+   }
+
+  //////////////////////////////////////////////////////
+  // remove a level                              //
+  // @param name : level's name to remove  //
+  // @return : boolean result                                            //
+  //////////////////////////////////////////////////
+   bool WxDescriptorPanel::RemoveLevel(const std::string &name)
+   {
+          bool bresult = false;
+          std::map<int, std::string>::iterator it_list= lvlist.begin();
+          for(; it_list != lvlist.end(); it_list++)
+          {
+                  if(it_list->second == name)
+                  {
+                          break;
+                  }
+          }
+          std::map<int, std::string>::iterator it_list2 = it_list;
+          for(;it_list != lvlist.end(); it_list++)
+          {
+                       std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+                       for (;it_tree != DscpTree.end(); it_tree++)
+                       {       
+                               if(it_tree->first == name)
+                               {
+                                       DscpTree.erase(it_tree);
+                                       break;
+                               }
+                       }
+          }
+          lvlist.erase(it_list2, lvlist.end());
+          return bresult;
+   }
+
+
+  //////////////////////////////////////////////////////
+  // add an attribute in a level                                 //
+  // @param level : level's name to add attribute  //
+  // @param name : attribute's name                                      //
+  // @return : boolean result                                            //
+  //////////////////////////////////////////////////
+   bool WxDescriptorPanel::addAtribute(const std::string &level, const std::string &name)
+   {
+          bool bresult = true;
+          std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+          for (;it_tree != DscpTree.end(); it_tree++)
+          {
+                  if (it_tree->first.c_str() == level)
+                  {
+                          std::vector<std::string>::iterator it_branch = it_tree->second.begin();
+                          for(;it_branch != it_tree->second.end(); it_branch++)
+                          { 
+                                  if(it_branch->c_str() == name)
+                                  {
+                                          bresult = false;
+                                  }
+                          }
+                          if(bresult)
+                          {
+                                       it_tree->second.push_back(name);
+                                       break;
+                          }
+                  }
+          }
+          return bresult;
+   }
+
+  //////////////////////////////////////////////////////
+  // remove an attribute from a level                            //
+  // @param level : level's name to remove attribute  //
+  // @param name : attribute's name                                      //
+  // @return : boolean result                                            //
+  //////////////////////////////////////////////////
+   bool WxDescriptorPanel::RemoveAttribute(const std::string &level, const std::string &name)
+   {
+             bool bresult = false;
+          std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+          for (;it_tree != DscpTree.end(); it_tree++)
+          {
+                  if(it_tree->first == level)
+                  {
+                          std::vector<std::string>::iterator it_branch = it_tree->second.begin();
+                          cout << it_tree->second.size();
+                          for(;it_branch != it_tree->second.end(); it_branch++)
+                          {
+                                  if(it_branch->c_str() == name)
+                                  {
+                                          bresult = true;
+                                          it_tree->second.erase(it_branch);
+                                          break;
+                                  }
+                          }
+                  }
+          }
+          return bresult;
+   }
+
+  //////////////////////////////////////////////////
+  // create a new descriptor                                   //
+  // @param event : WxEvent                                    //
+  // @return : -                                               //
+  //////////////////////////////////////////////////
+   void WxDescriptorPanel::OnNew(wxCommandEvent &Event)
+   {
+          LevelCtrl->SetValue(_T("patient"));
+          ResultCtrl->Clear();
+          DscpTree.clear();
+          lv = 0;
+   }
+
+  //////////////////////////////////////////////////
+  // Load a descriptor file                                            //
+  // @param event : WxEvent                                            //
+  // @return : -                                                       //
+  //////////////////////////////////////////////////
+   void WxDescriptorPanel::OnLoad(wxCommandEvent &Event)
+   {
+           long style = wxOPEN | wxFILE_MUST_EXIST;
+          LevelCtrl->SetValue(_T("patient"));
+          ResultCtrl->Clear();
+          DscpTree.clear();
+          lv = 0;
+               
+          std::string wc("*.dscp");
+          wxFileDialog* FD = new wxFileDialog( 0, 
+                                        _T("Select file"),
+                                        crea::std2wx(m_path),
+                                        _T(""),
+                                        crea::std2wx(wc),
+                                        style,
+                                        wxDefaultPosition);
+       if (FD->ShowModal()==wxID_OK)
+       {
+               loadDescriptor(crea::wx2std(FD->GetPath()).c_str());
+       }
+       
+   }
+
+  //////////////////////////////////////////////////
+  // Save a descriptor                                                   //
+  // @param event : WxEvent                                              //
+  // @return : -                                                        //
+  //////////////////////////////////////////////////
+   void WxDescriptorPanel::OnOK(wxCommandEvent &Event)
+   {
+         saveDescriptor();
+         wxWindow::Close();
+   }
+   
+  /////////////////////////////////////////////////////
+  // Save a descriptor and apply it (create a new DB//
+  // @param event : WxEvent                                            //
+  // @return : -                                                       //
+  /////////////////////////////////////////////////////
+   void WxDescriptorPanel::OnApply(wxCommandEvent &Event)
+   {
+               m_DscpFile = saveDescriptor();
+               wxWindow::Close();
+               SetReturnCode(ID_DSCP_APPLY);
+   }
+
+   const std::string WxDescriptorPanel::saveDescriptor()
+   {
+          std::string file = "";
+               long style = wxSAVE;
+               std::string wc("*.dscp");
+               wxFileDialog* FD = new wxFileDialog( 0, 
+                                               _T("Select file"),
+                                               _T(""),
+                                               _T(""),
+                                               crea::std2wx(wc),
+                                               style,
+                                               wxDefaultPosition);
+
+
+               if (FD->ShowModal()==wxID_OK)
+               {
+                       createDescriptorFile();
+                       file = crea::wx2std(FD->GetPath()).c_str();
+                       std::ofstream ofs(file.c_str());
+                       ofs.clear();
+                       ofs << outDscp;
+                       ofs.close();
+               }
+               return file.c_str();
+   }
+   ///////////////////////////////////////////////////////
+   // Cancel action                                                            //
+   // @param event :   WxEvent                                                 //
+   // @return : -                                                              //
+   ///////////////////////////////////////////////////////
+
+   void WxDescriptorPanel::OnCancel(wxCommandEvent& event)
+   {
+   }
+   
+   ///////////////////////////////////////////////////////
+   // create  a descriptor     file                                            //
+   // @param - :                                                               //
+   // @return : -                                                              //
+   ///////////////////////////////////////////////////////
+   void WxDescriptorPanel::createDescriptorFile()
+   {
+               
+                  outDscp.clear();
+                  outDscp += "<level>";
+                  outDscp += "\n";
+                  outDscp += "Root";
+                  outDscp += "\n";
+                  outDscp += "O Name Name 4";
+                  outDscp += "\n";
+                  std::map<std::string, std::vector <std::string> >::iterator it_tree = DscpTree.begin();
+                  std::map<int, std::string >::iterator it_lv_nb = lvlist.begin();
+                  std::map<int, std::string >::iterator it_lv = lvlist.begin();
+                  it_lv_nb++;
+                  for (;it_lv != lvlist.end(); it_lv++)
+              {
+                          outDscp +="<level>";
+                      outDscp += "\n";
+                          outDscp += it_lv->second.c_str();
+                            outDscp += "\n";
+                           if(it_lv_nb != lvlist.end())
+                          {
+                                  outDscp += "O NumberOfChildren ";
+                                  outDscp += it_lv_nb->second.c_str();
+                                  outDscp += "s";
+                                  outDscp += "\n";
+                                  it_lv_nb++;
+                          }
+                          std::vector<std::string>::iterator it_branch = DscpTree[it_lv->second.c_str()].begin();      
+                     for(;it_branch != DscpTree[it_lv->second.c_str()].end(); it_branch++)
+                         {      
+                                 std::string att = it_branch->c_str();
+                                 if(att[0] == 'D' && att[7] == '_' && att.size() == 14) 
+                                 {
+                                     outDscp += "D ";
+                                         outDscp += att.substr(1,6) + " "; // GR
+                                         outDscp += att.substr(8,6) + " ";// EL
+                                         outDscp += "3";
+                                         outDscp += "\n";
+                                 }
+                                 else
+                                 {
+                                         outDscp += "O ";
+                                         outDscp += it_branch->c_str();
+                                         outDscp += " ";
+                                         outDscp += ownatt[att];
+                                         outDscp += " ";
+                                         outDscp += "2";
+                                         outDscp += "\n";
+                                 }
+                         }
+
+                  }
+   }
+
+   
+   ///////////////////////////////////////////////////////
+   // load a descriptor                                                                        //
+   // @param i_name : file name        to load                             //
+   // @return : -                                                                              //
+   /////////////////////////////////////////////////////
+   void WxDescriptorPanel::loadDescriptor(const std::string i_name)
+   {
+          std::ifstream i_file(i_name.c_str());
+          std::stringstream buffer;
+          buffer << i_file.rdbuf();
+          std::string line;
+          std::string level;
+
+#if defined(USE_GDCM2)
+          const gdcm::Global& g = gdcm::Global::GetInstance(); // sum of all knowledge !
+          const gdcm::Dicts &dicts = g.GetDicts();
+          const gdcm::Dict &dict = dicts.GetPublicDict(); // Part 6
+#endif
+         
+
+               bool bname;
+               int ilevel = -1;
+
+               
+               while(std::getline(buffer, line))
+               {
+                       if(line =="<level>")
+                       {       //increment levels.
+                               ilevel++;
+                               bname = true;
+                       }
+                       else if(bname)
+                       {
+                               // For each level, a name to describe it
+                               level = line;
+                               if(ilevel>0)
+                               {
+                                       onAddLevel(level);
+                               }
+                               bname = false;
+                       }
+                       else
+                       { 
+                               // split line to find all tags
+                               std::vector<std::string> descriptors;
+                               std::string separator = " ";
+                               std::string::size_type last_pos = line.find_first_not_of(separator);
+                               //find first separator
+                               std::string::size_type pos = line.find_first_of(separator, last_pos);
+                               while(std::string::npos != pos || std::string::npos != last_pos)
+                               {
+                                       descriptors.push_back(line.substr(last_pos, pos - last_pos));
+                                       last_pos = line.find_first_not_of(separator, pos);
+                                       pos = line.find_first_of(separator, last_pos);
+                               }
+                               
+                               // By default, the last tag is at zero and not recorded but if take in count
+                               unsigned int flag = 0;
+                               if(descriptors.size() == 4)
+                               {
+                                       std::stringstream val;
+                                       val << std::dec << descriptors[3];
+                                       val>> flag;
+                               }
+
+                               // if Dicom tag, use "group" and "element" descriptor
+                               if(descriptors[0] == "D")
+                               {       std::stringstream val, val2;
+                                       unsigned short group;
+                                       unsigned short element;
+                                       val <<   std::dec << descriptors[1] ;
+                                       val >> std::hex >> group;
+                                       val2 << std::dec <<  descriptors[2];
+                                       val2 >> std::hex >> element;
+                                       std::string compose =  "D";
+                                       compose +=  descriptors[1];
+                                       compose += "_";
+                                       compose +=  descriptors[2];
+#if defined(USE_GDCM)
+                                       GDCM_NAME_SPACE::DictEntry* entry = GDCM_NAME_SPACE::Global::GetDicts()->GetDefaultPubDict()->GetEntry(group, element);
+                                       if(ilevel>0)
+                                       {
+                                               onAddAttribute( entry->GetName(),compose, level);
+                                       }
+#endif
+
+#if defined(USE_GDCM2)
+                                       gdcm::DictEntry dictentry =  dict.GetDictEntry(gdcm::Tag(group, element));
+                                       if(ilevel>0)
+                                       {
+                                               onAddAttribute( dictentry.GetName(),compose, level);
+                                       }
+       
+
+#endif
+                               }
+                               else if(descriptors[0].find("#") != -1)
+                               {
+                                       // commented line continue to next line
+                               }
+                               else // "O" means if user's own tag.
+                               {       
+                                       boost::algorithm::replace_all(descriptors[2],"_"," ");
+                                       if(ilevel>0 && descriptors[1] != "NumberOfChildren" )
+                                       {       
+                                               onAddAttribute( descriptors[2].c_str(),descriptors[1].c_str(), level);
+                                       }
+                               }
+                       }
+               }
+   }
+   
+//======================================================================
+  
+//====================================================================== 
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxDescriptorPanel.h b/src/creaImageIOWxDescriptorPanel.h
new file mode 100644 (file)
index 0000000..203a409
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef __creaImageIOWxDescriptorPanel_h_INCLUDED__
+#define __creaImageIOWxDescriptorPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <string>
+#include <map>
+#include <vector>
+#include <creaImageIOWxGimmickView.h>
+#include <wx/listctrl.h>
+#include <wx/statline.h>
+
+
+#define ID_DESCRIPTOR 1500
+#define ID_LEVEL_CTRL       ID_DESCRIPTOR+1
+#define ID_LEVEL_ADD        ID_DESCRIPTOR+2
+#define ID_GR_CTRL              ID_DESCRIPTOR+3
+#define ID_EL_CTRL              ID_DESCRIPTOR+4
+#define ID_NAME_CTRL        ID_DESCRIPTOR+5
+#define ID_ATTRIBUTE_CTRL       ID_DESCRIPTOR+6
+#define ID_ATTRIBUTE_ADD        ID_DESCRIPTOR+7
+#define ID_REMOVE_ADD           ID_DESCRIPTOR+8
+#define ID_DSCP_APPLY           ID_DESCRIPTOR+9
+
+namespace creaImageIO
+{
+
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+ /// Gimmick DB are based on descriptors with a tree structure .
+ /// Each level contains attributes (DICOM or other) to identify data
+ /// WxDescriptorPanel allows creation, modification and save of descriptors. 
+ ///
+
+  class WxDescriptorPanel : public wxDialog
+  {
+  public:
+    WxDescriptorPanel();    
+       WxDescriptorPanel(wxWindow *parent, const std::string path);
+    ~WxDescriptorPanel();
+
+       // Get file to load Descriptor
+       const std::string& GetDescriptor(){ return m_DscpFile;}
+
+  private :
+
+    // WxControls
+       wxTextCtrl *LevelCtrl;  //TextCtrl to enter level's name
+       wxTextCtrl *GRCtrl;     // TextCtrl to enter DICOM Group value
+       wxTextCtrl *ELCtrl;     // TextCtrl to enter DICOM element value
+       wxTextCtrl *ResultCtrl; //TextCtrl to visualize Descriptor
+       wxComboBox *AttributeCombo; // Combox to choose Attribute values
+
+       /// Add an attribute (DICOM or own) 
+       void OnAddAttribute(wxCommandEvent& event);
+
+       /// Add an attribute (DICOM or own)
+       void onAddAttribute( const std::string &att, const std::string &name_att, std::string level = "");
+
+       /// Add a Level 
+       void OnAddLevel(wxCommandEvent& event);
+       
+       /// Add a Level 
+       void onAddLevel(const std::string &level);
+
+       /// Find a DICOM attribute from group and element values
+       void OnDicomAttribute(wxCommandEvent& event);
+
+       /// Remove a value (level or attribute)
+       void OnRemove(wxCommandEvent& event);
+
+       /// Create a new descriptor
+       void OnNew(wxCommandEvent& event);
+
+       /// Load an exsitant descriptor
+       void OnLoad(wxCommandEvent& event);
+
+       /// Save a descriptor
+       void OnOK(wxCommandEvent& event);
+
+       /// Save a descriptor and use it
+       void OnApply(wxCommandEvent& event);
+
+       /// Cancel
+       void OnCancel(wxCommandEvent& event);
+
+       /// Create a descriptor structure
+       void CreateDescriptor(int type);
+
+       /// add a level
+       bool addLevel(const std::string &name);
+
+       /// add an attribute
+       bool addAtribute(const std::string &level, const std::string &name);
+
+       /// remove an attribute
+       bool RemoveAttribute(const std::string &level, const std::string &name);
+
+       /// remove a level
+       bool RemoveLevel(const std::string &name);
+
+       /// Create a descriptor file
+       void createDescriptorFile();
+       
+       /// load a descriptor file
+       void loadDescriptor(const std::string i_name);
+
+       /// find a level'name 
+       std::string findLevel();
+
+       /// determine values for own attributes
+       std::string OwnAttribute(const std::string name);
+
+       /// save a descriptor in a file
+       const std::string saveDescriptor();
+
+       /// number of level 
+       int lv;
+
+       /// Insert point in result control
+       long InsertPt;
+
+       /// Output file for Descriptor
+       std::string m_DscpFile;
+
+       /// Output Descriptor
+       std::string outDscp; 
+       
+       // Vector of attributes
+       std::vector<std::string> VLevel;
+
+       // map of level, attributes
+       std::map<std::string, std::vector<std::string> > DscpTree;
+
+       // map of own application attributes
+       std::map<std::string, std::string> ownatt;
+
+       // List of added level
+       std::map<int, std::string> lvlist;
+
+       // DB Gimmick path
+       std::string m_path;
+
+  }; // class WxDescriptorPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
diff --git a/src/creaImageIOWxDumpPanel.cpp b/src/creaImageIOWxDumpPanel.cpp
new file mode 100644 (file)
index 0000000..843db48
--- /dev/null
@@ -0,0 +1,123 @@
+#include <creaImageIOWxDumpPanel.h>
+#include <creaImageIOSystem.h>
+#include <creaImageIOGimmick.h>
+#if defined(USE_GDCM)
+#include <gdcmGlobal.h>
+#include <gdcmDictSet.h>
+#include "gdcmFile.h"
+#include "gdcmDocument.h"
+#include "gdcmFileHelper.h"
+#endif
+#include "icons/save.xpm"
+
+namespace creaImageIO
+{
+       // CTor
+   WxDumpPanel::WxDumpPanel(wxWindow *parent,  std::string i_filename)
+    : wxDialog(parent, -1,_T("DICOM TAGS"), wxDefaultPosition, wxSize(550,580)), filename(i_filename)
+   {
+       int size = 16;
+       mIcon = new wxImageList(size,size,true);
+       mIcon->Add(wxBitmap(wxBitmap(wxIcon(save_xpm)).ConvertToImage().Rescale(size, size)));
+       wxToolBar *mToolBar = new wxToolBar(this,-1,wxDefaultPosition,wxDefaultSize);
+       mToolBar->AddTool( DUMP_SAVE_ID,_T("Save"), mIcon->GetBitmap(0), _T("Save Dicom Tags in text file"));
+       mToolBar->Realize();
+       DumpText = new wxTextCtrl( this, wxID_ANY,_T(""), wxPoint(5,30), wxSize(520,510), wxTE_READONLY| wxMac | wxTE_MULTILINE | wxTE_RICH );
+       Layout(); 
+       Print();
+       }
+
+       // DTor
+       WxDumpPanel::~WxDumpPanel(){}
+
+       ///////////////////////////////////////////////////
+       /// Display in a control Text all dicom tags
+       ///////////////////////////////////////////////////
+       void WxDumpPanel::Print()
+       {
+          std::stringstream os;
+          if ( !filename.empty()) // ====== Deal with a single file ======
+          {
+       /*         GDCM_NAME_SPACE::File *f = GDCM_NAME_SPACE::File::New();
+                  f->SetLoadMode(GDCM_NAME_SPACE::LD_ALL);
+                  f->SetFileName( filename );
+                  f->SetMaxSizeLoadEntry(0xffff);
+                  f->Load();
+                  GDCM_NAME_SPACE::FileHelper *fh = GDCM_NAME_SPACE::FileHelper::New(f);
+                     f->SetLoadMode(GDCM_NAME_SPACE::LD_NOSEQ |GDCM_NAME_SPACE::LD_NOSHADOW); 
+                  fh->SetPrintLevel( 0 );
+                  fh->Print(os);
+                  std::string result;
+                  std::string line;
+                  while(std::getline(os, line))
+                  {
+                         result +=clean(line.c_str());
+                         result += "\n";
+                  }
+                  DumpText->SetValue(crea::std2wx(result));
+               
+                  std::string pixelType =f->GetPixelType();
+                       int nX,nY,nZ,nT,sPP,planarConfig;
+    
+      nX=f->GetXSize();
+      nY=f->GetYSize();
+      nZ=f->GetZSize();
+      nT=f->GetTSize();*/
+               }
+       }
+
+
+       const std::string WxDumpPanel::clean(const std::string &i_line)
+       {
+               
+                 if (i_line.substr(4,1) == "|")
+                          {
+                                  std::string tag;
+                                  std::string line;
+                                  std:string signification;
+                                  std::string value;
+                                  std::string resultat;
+
+                                  tag = "(" + i_line.substr(0,9) + ")";
+                                  line = i_line.substr(14,i_line.size()-10);
+                                  int pos1 = line.find_first_of("[");
+                                  int pos2 = line.find_first_of("]");
+                                  signification = line.substr(pos1+1, pos2-pos1-1);
+                                  line = line.substr(pos2+1);
+                                   pos1 = line.find_first_of("[");
+                                   pos2 = line.find_first_of("]");
+                                  value = line.substr(pos1+1, pos2-pos1-1);
+                                  resultat = tag + " " + signification + ": " +value;
+                                 return resultat;
+                          }
+                  else
+                  {
+                          return i_line;
+                  }
+       }
+
+///////////////////////////////////////////////////    
+/// wxEvent to save Dicom Tags in a text file   //
+///////////////////////////////////////////////////
+       void WxDumpPanel::SaveInfos(wxCommandEvent& event)
+       {
+       wxFileDialog* FD = new wxFileDialog( 0,_T("Select file"), _T(""), _T(""),
+                                              crea::std2wx("*.txt"), wxOPEN, wxDefaultPosition);
+        if (FD->ShowModal()==wxID_OK)
+               {
+                       wxBusyCursor busy;
+                       std::ofstream ofs(crea::wx2std(FD->GetPath()).c_str());
+                       ofs.clear();
+                       ofs << crea::wx2std(DumpText->GetValue());;
+                       ofs.close();
+               }
+               Close();
+       }
+
+////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////
+BEGIN_EVENT_TABLE(WxDumpPanel, wxDialog)
+    EVT_TOOL(DUMP_SAVE_ID, WxDumpPanel::SaveInfos)
+END_EVENT_TABLE()
+}
+
diff --git a/src/creaImageIOWxDumpPanel.h b/src/creaImageIOWxDumpPanel.h
new file mode 100644 (file)
index 0000000..474892c
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef __creaImageIOWxDumpPanel_h_INCLUDED__
+#define __creaImageIOWxDumpPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <creaImageIOWxGimmickView.h>
+
+#define DUMP_SAVE_ID 1800
+
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  /// Display all dicom tags from a given DICOM file
+       class WxDumpPanel : public wxDialog
+  {
+  public:
+
+    /// Constructor
+       WxDumpPanel(wxWindow *parent, std::string i_filename);
+    
+       /// Destructor
+    ~WxDumpPanel();
+       
+       
+  private :
+
+        const std::string clean(const std::string &i_line);
+    /// Display in a control Text all dicom tags
+       void Print();
+
+       /// wxEvent to save Dicom Tags in a text file
+        void SaveInfos(wxCommandEvent& event);
+
+   /// Parent DialogBox
+       wxDialog* dialog;
+
+       /// Icons list
+       wxImageList *mIcon;
+
+       /// ControlText to display tags
+       wxTextCtrl *DumpText;
+
+       /// Dicom file to display
+       std::string filename;
+
+    DECLARE_EVENT_TABLE()
+
+  }; // class WxEditFieldsPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
diff --git a/src/creaImageIOWxEditFieldsPanel.cpp b/src/creaImageIOWxEditFieldsPanel.cpp
new file mode 100644 (file)
index 0000000..6db827b
--- /dev/null
@@ -0,0 +1,88 @@
+#include <creaImageIOWxEditFieldsPanel.h>
+#include <creaImageIOSystem.h>
+#include <wx/arrstr.h>
+
+//using namespace tree;
+namespace creaImageIO
+{
+   const int  ID_COMBO             = 140;
+  // CTor
+   WxEditFieldsPanel::WxEditFieldsPanel(wxWindow *parent, wxDialog* dial, WxGimmickView* view, tree::Node* nod, 
+      const std::vector<std::string> name,
+      const std::vector<std::string> key)
+ :   wxPanel( parent, 
+        -1, wxDefaultPosition, 
+        wxDefaultSize,
+        wxRESIZE_BORDER | 
+        wxSYSTEM_MENU  |
+        wxCLOSE_BOX |
+        wxMAXIMIZE_BOX | 
+        wxMINIMIZE_BOX | 
+        wxCAPTION  
+          ), 
+        dialog(dial),
+        node (nod), 
+        names(name), 
+        keys(key),
+        mView(view)
+  {
+    GimmickDebugMessage(1,"WxCustomizeConfigPanel::WxCustomizeConfigPanel"
+                       <<std::endl);
+       wxStaticText * cp=new wxStaticText(this,-1,_T(" Attribute to change: "), wxPoint(5,10));
+       wxArrayString as;
+       std::vector<std::string>::const_iterator it;
+       for(it=names.begin();it!=names.end();++it)
+       {
+           as.Add(crea::std2wx(*it));
+       }
+       attributes=new wxComboBox(this, ID_COMBO, crea::std2wx(names.front()), wxPoint(110, 10), wxDefaultSize,as);
+       std::string val=node->GetAttribute(keys[0]);
+       if(val.compare("")==0){val="?";}
+
+       wxStaticText * av=new wxStaticText(this,-1,_T(" Current Value: "), wxPoint(5,40));
+       actualVal=new wxStaticText(this,-1,crea::std2wx(val), wxPoint(110,40));
+
+       wxStaticText * nv=new wxStaticText(this,-1,_T(" New Value: "), wxPoint(5,70));
+       newVal=new wxTextCtrl(this, wxID_ANY, crea::std2wx(val), wxPoint(110,70), wxSize(220,20));
+
+       wxButton *save = new wxButton(this,wxID_ANY,_T("Save Changes"), wxPoint(5,100) );
+       Connect( save->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxEditFieldsPanel::OnEdit ); 
+      
+    Layout(); 
+  }
+
+  /// Destructor
+  WxEditFieldsPanel::~WxEditFieldsPanel()
+  {
+    GimmickDebugMessage(1,"WxEditFieldsPanel::~WxEditFieldsPanel"
+                 <<std::endl);
+  }
+
+  void WxEditFieldsPanel::OnEdit(wxCommandEvent& event)
+  {
+         std::string val=crea::wx2std(newVal->GetValue());
+         int sel=attributes->GetSelection();
+         if(sel==-1)
+         {
+            sel=0;
+         }
+         mView->OnFieldsEdited(node,names[sel],keys[sel],val);
+         dialog->Destroy();
+  }
+
+  void WxEditFieldsPanel::OnComboChange(wxCommandEvent& event)
+  {
+         std::string val=node->GetAttribute(keys[attributes->GetSelection()]);
+         if(val.compare("")==0){val="?";}
+         actualVal->SetLabel(crea::std2wx(val));
+         newVal->SetValue(crea::std2wx(val));
+  }
+  
+//======================================================================
+BEGIN_EVENT_TABLE(WxEditFieldsPanel, wxPanel)
+EVT_COMBOBOX  (ID_COMBO,WxEditFieldsPanel::OnComboChange)
+END_EVENT_TABLE()
+//====================================================================== 
+
+} // EO namespace creaImageIO
+
diff --git a/src/creaImageIOWxEditFieldsPanel.h b/src/creaImageIOWxEditFieldsPanel.h
new file mode 100644 (file)
index 0000000..b71736a
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __creaImageIOWxEditFieldsPanel_h_INCLUDED__
+#define __creaImageIOWxEditFieldsPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <creaImageIOWxGimmickView.h>
+
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  class WxEditFieldsPanel : public wxPanel
+  {
+  public:
+    WxEditFieldsPanel();    
+       WxEditFieldsPanel(wxWindow *parent, 
+               wxDialog* dial,
+               WxGimmickView* view, 
+               tree::Node* nod, 
+               const std::vector<std::string> name,
+               const std::vector<std::string> key);
+    
+    ~WxEditFieldsPanel();
+       ///Saves the configuration
+        void OnEdit(wxCommandEvent& event);
+        void OnComboChange(wxCommandEvent& event);
+
+  private :
+       tree::Node* node; 
+       std::vector<std::string> names;
+       std::vector<std::string> keys;
+       wxDialog* dialog;
+       WxGimmickView* mView;
+       wxComboBox* attributes;
+       wxStaticText * actualVal;
+       wxTextCtrl* newVal;
+
+       DECLARE_EVENT_TABLE()
+
+
+  }; // class WxEditFieldsPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
diff --git a/src/creaImageIOWxExportDlg.cpp b/src/creaImageIOWxExportDlg.cpp
new file mode 100644 (file)
index 0000000..682cc89
--- /dev/null
@@ -0,0 +1,39 @@
+#include <creaImageIOWxExportDlg.h>
+
+namespace creaImageIO
+{
+       // CTor
+   WxExportDlg::WxExportDlg(wxWindow *parent, const std::vector<std::string> storages)
+    : wxDialog(parent, -1,_T("EXPORT FILES TO STORAGE"), wxDefaultPosition, wxSize(260,150))
+   {
+         int size = 16;
+       
+         wxStaticText * ExportText=new wxStaticText(this,-1,_T(" Storage to export: "), wxPoint(5,10));
+         wxArrayString names;
+         std::vector<std::string>::const_iterator it = storages.begin();
+         for(;it != storages.end(); it++)
+         {
+                 names.Add(crea::std2wx(*it));
+         }
+         ExportCombo  = new wxComboBox(this, ID_EXPORTCOMBO_CTRL,_T(""),wxPoint(120,10), wxSize(120,25),names);
+         ExportCombo->SetSelection(0);
+       //  Connect( ExportCombo->GetId(), wxEVT_COMMAND_TEXT_UPDATED , (wxObjectEventFunction) &WxDescriptorPanel::OnDicomAttribute ); 
+
+         // VALIDATION BUTTON
+         wxButton *Ok = new wxButton(this, -1,_T("OK"), wxPoint(5,50) );
+         Connect( Ok->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxExportDlg::OnOk ); 
+       
+         wxButton *Cancel = new wxButton(this, wxID_CANCEL,_T("CANCEL"), wxPoint(100,50) );
+         Layout(); 
+         
+       }
+
+       WxExportDlg::~WxExportDlg(){}
+
+       void WxExportDlg::OnOk(wxCommandEvent &event)
+       {
+               m_name = crea::wx2std(ExportCombo->GetValue());
+               Close();
+               SetReturnCode(ID_EXPORT_OK);
+       }       
+}
diff --git a/src/creaImageIOWxExportDlg.h b/src/creaImageIOWxExportDlg.h
new file mode 100644 (file)
index 0000000..6c5c9cd
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __creaImageIOWxExportDlg_h_INCLUDED__
+#define __creaImageIOWxExportDlg_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <creaImageIOWxGimmickView.h>
+
+#define ID_EXPORTCOMBO_CTRL 1801
+#define ID_EXPORT_OK           1802
+
+namespace creaImageIO{
+       /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+ /// Gimmick can handle multiple database with different organisations.
+ /// WxDescriptorPanel allows to select the storage to export data. 
+ ///
+       class WxExportDlg : public wxDialog
+       {
+       public:
+               ///CTor
+               WxExportDlg(wxWindow *parent, const std::vector<std::string> storages);
+               ///DTor
+               ~WxExportDlg();
+
+       /// Get selected storage
+       const std::string& GetStorage(){ return m_name;}
+
+       private:
+
+               /// Storage ComboBox
+               wxComboBox *ExportCombo;
+
+               ///Validate selected storage
+               void OnOk(wxCommandEvent &event);
+
+               /// Storage name
+               std::string m_name;
+       };
+}
+#endif // USE_WIDGETS
+// EOF
+#endif
diff --git a/src/creaImageIOWxGimmickFrame.cpp b/src/creaImageIOWxGimmickFrame.cpp
new file mode 100644 (file)
index 0000000..6204344
--- /dev/null
@@ -0,0 +1,89 @@
+#include <creaImageIOWxGimmickFrame.h>
+#include <creaImageIOSystem.h>
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+  // CTor
+  WxGimmickFrame::WxGimmickFrame(wxWindow *parent, 
+                                              wxWindowID id,
+                                              wxString title,
+                                              const wxPoint& pos,
+                                              const wxSize& size,
+                                              int threads)
+ :   wxFrame( parent, 
+                 id, 
+                 title,
+                 pos,
+                 size,
+                 wxRESIZE_BORDER | 
+             wxSYSTEM_MENU  |
+                 wxCLOSE_BOX |
+                 wxMAXIMIZE_BOX | 
+                 wxMINIMIZE_BOX | 
+                 wxCAPTION  
+              ),
+    // mGimmick(0),
+     mView(0)
+  {
+    GimmickDebugMessage(1,"WxGimmickFrame::WxGimmickFrame"
+                       <<std::endl);
+    wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
+    
+    try {
+      
+//             mGimmick = boost::shared_ptr<Gimmick>(new Gimmick());
+      mGimmick->Initialize();
+     
+      int min_dim = GIMMICK_2D_IMAGE_SELECTION;
+         int max_dim = GIMMICK_3D_IMAGE_SELECTION;
+      mView = new WxGimmickView(mGimmick,
+                               this,
+                               -1,
+                               wxDefaultPosition,
+                               size,
+                               min_dim,
+                               max_dim,
+                               threads);
+      mView->Initialize();
+    }
+    catch (crea::Exception e)
+    {
+      e.Print();
+      return;
+    }
+
+    topsizer->Add( mView,1,wxGROW,0);
+
+    SetSizer( topsizer );     
+    Layout(); 
+  }
+
+  /// Destructor
+  WxGimmickFrame::~WxGimmickFrame()
+  {
+    GimmickDebugMessage(1,"WxGimmickFrame::~WxGimmickFrame"
+                       <<std::endl);
+    if (mView) 
+      {
+       delete mView;
+      }
+    if (mGimmick) 
+      {
+       mGimmick->Finalize();
+//     delete mGimmick;
+      }
+  }
+  
+  
+  //================================================================
+  //  BEGIN_EVENT_TABLE(WxGimmickFrame, wxDialog)
+  //    END_EVENT_TABLE()
+  //================================================================
+
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxGimmickFrame.h b/src/creaImageIOWxGimmickFrame.h
new file mode 100644 (file)
index 0000000..af7c253
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __creaImageIOWxGimmickFrame_h_INCLUDED__
+#define __creaImageIOWxGimmickFrame_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+
+#include <creaImageIOWxGimmickView.h>
+#include <creaWx.h>
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  class  WxGimmickFrame : public wxFrame
+  {
+  public:
+    WxGimmickFrame();    
+    WxGimmickFrame(wxWindow *parent, 
+                  const wxWindowID id,
+                  wxString title,
+                  const wxPoint& pos, 
+                  const wxSize& size,
+                  int threads = 0);
+    
+    ~WxGimmickFrame();
+
+    //    Gimmick* GetGimmick() { return mGimmick; }
+    //    typedef WxGimmick ViewType;
+    //    typedef WxGimmickView::EventType EventType;
+
+
+
+     
+    //    void OnSelChanged(EventType& event);
+    //    void OnContextualMenu(EventType& event);
+    //    void OnMenuTest(wxCommandEvent& event);
+    //    void OnButtonOk(wxCommandEvent& event);
+    //    void OnButtonCancel(wxCommandEvent& event);
+
+    //    DECLARE_EVENT_TABLE();
+  private :
+    
+         boost::shared_ptr<Gimmick>       mGimmick;
+    WxGimmickView* mView;
+
+  }; // class WxGimmickFrame
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif  
diff --git a/src/creaImageIOWxGimmickPanel.cpp b/src/creaImageIOWxGimmickPanel.cpp
new file mode 100644 (file)
index 0000000..2b2ebb9
--- /dev/null
@@ -0,0 +1,111 @@
+#include <creaImageIOWxGimmickPanel.h>
+#include <creaImageIOSystem.h>
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+  // CTor
+  WxGimmickPanel::WxGimmickPanel(wxWindow *parent, 
+                                              wxWindowID id,
+                                              const wxPoint& pos,
+                                              const wxSize& size,
+                                                  const std::string i_namedescp , 
+                                                  const std::string i_namedb ,
+                                              int threads)
+ :   wxPanel( parent, 
+                 id, 
+                 pos,
+                 size,
+                 wxRESIZE_BORDER | 
+             wxSYSTEM_MENU  |
+                 wxCLOSE_BOX |
+                 wxMAXIMIZE_BOX | 
+                 wxMINIMIZE_BOX | 
+                 wxCAPTION  
+              ),
+     //mGimmick(0),
+     mView(0)
+  {
+    GimmickDebugMessage(1,"WxGimmickPanel::WxGimmickPanel"
+                       <<std::endl);
+    wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
+    
+    try {
+      
+               mGimmick = boost::shared_ptr<Gimmick>(new Gimmick());
+               mGimmick->Initialize(i_namedescp,i_namedb);
+      int min_dim = GIMMICK_2D_IMAGE_SELECTION;
+         int max_dim = GIMMICK_3D_IMAGE_SELECTION;
+      mView = new WxGimmickView(mGimmick,
+                               this,
+                               -1,
+                               wxDefaultPosition,
+                               size,
+                               min_dim,
+                               max_dim,
+                               threads);
+      mView->Initialize();
+         // Connect the AddProgress callback
+      mView->ConnectValidationObserver ( boost::bind( &WxGimmickPanel::OnSelectedImage , this, _1 ) );
+    }
+    catch (crea::Exception e)
+    {
+      e.Print();
+      return;
+    }
+
+    topsizer->Add( mView,1,wxGROW,0);
+
+    SetSizer( topsizer );     
+    Layout(); 
+  }
+
+  /// Destructor
+  WxGimmickPanel::~WxGimmickPanel()
+  {
+    GimmickDebugMessage(1,"WxGimmickPanel::~WxGimmickPanel"
+                       <<std::endl);
+    if (mView) 
+      {
+       delete mView;
+      }
+    if (mGimmick) 
+      {
+       mGimmick->Finalize();
+      }
+  }
+  
+//======================================================================
+  
+//====================================================================== 
+  
+  ///Callback method on a selection
+  void WxGimmickPanel::OnSelectedImage(bool t)
+  {
+               mSendImageSignal(t);
+  }
+
+  void WxGimmickPanel::AddImagesToDB(std::string dir)
+  {
+      mView->AddDir(dir);
+  }
+
+  //================================================================
+  //  BEGIN_EVENT_TABLE(WxGimmickPanel, wxDialog)
+  //    END_EVENT_TABLE()
+  //================================================================
+
+
+  //====================================================================
+
+  //====================================================================
+  void WxGimmickPanel::ConnectSendImageObserver(SendImageCallbackType callback)
+  {
+    mSendImageSignal.connect(callback);
+  }
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxGimmickPanel.h b/src/creaImageIOWxGimmickPanel.h
new file mode 100644 (file)
index 0000000..ad776dd
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef __creaImageIOWxGimmickPanel_h_INCLUDED__
+#define __creaImageIOWxGimmickPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+
+// Signal/slot mechanism for progress events
+#include <boost/signal.hpp>
+#include <boost/bind.hpp>
+
+#include <creaImageIOWxGimmickView.h>
+#include <creaWx.h>
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  class  CREAIMAGEIO_EXPORT WxGimmickPanel : public wxPanel
+  {
+  public:
+    WxGimmickPanel();    
+    WxGimmickPanel(wxWindow *parent, 
+                  const wxWindowID id,
+                  const wxPoint& pos, 
+                  const wxSize& size,
+                  const std::string i_namedescp , 
+                  const std::string i_namedb = "Local Database",
+                  int threads = 0);
+    
+    ~WxGimmickPanel();
+
+      //=============================================
+      typedef boost::signal<void (bool)> SendImageSignalType;
+      typedef SendImageSignalType::slot_function_type SendImageCallbackType;
+      //=============================================
+
+     //==================================================================
+      /// Adds the function f to the list of functions to call 
+      /// when the addition progresses.
+      /// f is of type ProgressCallbackType which is:
+      /// void (*ProgressCallbackType)(Progress&)
+      /// To pass a member function 'f' of an instance 'c' of a class 'C' 
+      /// as callback you have to 'bind' it, i.e. call:
+      /// ConnectSendImageObserver ( boost::bind( &C::f , c, _1 ) );
+      void ConnectSendImageObserver(SendImageCallbackType callback);
+     //==================================================================
+
+       //===============================================================================================
+       //Image Selection
+       //===============================================================================================
+
+    void GetSelectedImages(std::vector<vtkImageData*>& s, int dim)
+    { 
+       mView->GetSelectedImages(s, dim); 
+    }
+
+    void GetSelectedImagesInVector(std::vector<vtkImageData*>& s, int dim)
+    { 
+       mView->GetSelectedImagesInVector(s, dim); 
+    }
+
+    void OnSelectedImage(bool t);
+
+    void AddImagesToDB(std::string dir);
+
+    //    DECLARE_EVENT_TABLE();
+  private :
+    
+       boost::shared_ptr<Gimmick>       mGimmick;
+    WxGimmickView* mView;
+
+       ///The sendImage signal
+    SendImageSignalType mSendImageSignal;
+
+  }; // class WxGimmickPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif  
diff --git a/src/creaImageIOWxGimmickReaderDialog.cpp b/src/creaImageIOWxGimmickReaderDialog.cpp
new file mode 100644 (file)
index 0000000..e2362d9
--- /dev/null
@@ -0,0 +1,112 @@
+#include <creaImageIOWxGimmickReaderDialog.h>
+#include <creaImageIOSystem.h>
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+namespace creaImageIO
+{
+  // CTor
+  WxGimmickReaderDialog::WxGimmickReaderDialog(wxWindow *parent, 
+                                              wxWindowID id,
+                                              const std::string i_namedescp, 
+                                              const std::string i_namedb,
+                                              wxString title,
+                                              const wxPoint& pos,
+                                              const wxSize& size,
+                                              int min_dim,
+                                              int max_dim,
+                                              int output_dim,  // never used ?!? // JPR
+                                              int threads)
+ :   wxDialog( parent, 
+                 id, 
+                 title,
+                 pos,
+                 size,
+                 wxRESIZE_BORDER | 
+                 wxSYSTEM_MENU   |
+                 wxCLOSE_BOX     |
+                 wxMAXIMIZE_BOX  | 
+                 wxMINIMIZE_BOX  | 
+                 wxCAPTION  
+              ),
+ //   mGimmick(0),
+     mView(0)
+  {
+    GimmickDebugMessage(1,"WxGimmickReaderDialog::WxGimmickReaderDialog"
+                       <<std::endl);
+    mtopsizer = new wxBoxSizer(wxVERTICAL);
+
+    try {
+
+         mGimmick = boost::shared_ptr<Gimmick>(new Gimmick());
+      mGimmick->Initialize(i_namedescp,i_namedb);
+
+      mView = new WxGimmickView(mGimmick,
+                               this,
+                               TVID,
+                               wxDefaultPosition,
+                               size,
+                               min_dim,
+                               max_dim,
+                               threads);
+      mView->Initialize();
+          // Connect the AddProgress callback
+      mView->ConnectValidationObserver
+               ( boost::bind( &WxGimmickReaderDialog::OnValid , this, _1 ) );
+    }
+    catch (crea::Exception e)
+    {
+      e.Print();
+      return;
+    }
+
+    mtopsizer->Add( mView,1,wxGROW,0);
+
+    wxSizer* bsizer = this->CreateSeparatedButtonSizer(wxOK|wxCANCEL);
+       /*mOkButton = new wxButton(this, wxID_OK, _T("OK"), wxPoint(170,50));
+       mCancelButton = new wxButton(this, wxID_CANCEL, _T("CANCEL"), wxPoint(210,50));
+       */      mOkButton = (wxButton*)FindWindowById(GetAffirmativeId(), this);
+    mCancelButton = (wxButton*)FindWindowById(GetEscapeId(),      this);
+
+    mOkButton->Enable(false);
+    mtopsizer->Add ( bsizer, 0, wxGROW );
+
+    SetSizer( mtopsizer );     
+    Layout(); 
+  }
+
+  /// Destructor
+  WxGimmickReaderDialog::~WxGimmickReaderDialog()
+  {
+    GimmickDebugMessage(1,"WxGimmickReaderDialog::~WxGimmickReaderDialog"
+                       <<std::endl);
+    if (mView) 
+      {
+        delete mView;
+      }
+    if (mGimmick) 
+      {
+               mGimmick->Finalize();
+      }
+   deleteMessage();
+  }
+
+void           WxGimmickReaderDialog::deleteMessage()
+       {
+               deleteGimmickDebugMessage();
+       };
+  ///Callback method on a selection
+  void WxGimmickReaderDialog::OnValid(bool t)
+  {
+    mOkButton->Enable(t);
+  }
+
+  //================================================================
+  //BEGIN_EVENT_TABLE(WxGimmickReaderDialog, wxDialog)
+  //END_EVENT_TABLE()
+  //================================================================
+
+} // EO namespace creaImageIO
+
diff --git a/src/creaImageIOWxGimmickReaderDialog.h b/src/creaImageIOWxGimmickReaderDialog.h
new file mode 100644 (file)
index 0000000..bac2c14
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef __creaImageIOWxGimmickReaderDialog_h_INCLUDED__
+#define __creaImageIOWxGimmickReaderDialog_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+
+#include <creaImageIOWxGimmickView.h>
+#include "creaImageIOSystem.h"
+#include <creaWx.h>
+#include "wx/wx.h"
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+
+  //=====================================================================
+ //=====================================================================
+  class CREAIMAGEIO_EXPORT  WxGimmickReaderDialog : public wxDialog
+  {
+  public:
+    WxGimmickReaderDialog();
+    WxGimmickReaderDialog(wxWindow *parent,
+                         const wxWindowID id,
+                         const std::string i_namedescp , 
+                         const std::string i_namedb ,
+                         wxString title,
+                         const wxPoint& pos,
+                         const wxSize& size,
+                         int image_min_dim = GIMMICK_2D_IMAGE_SELECTION,
+                         int image_max_dim = GIMMICK_3D_IMAGE_SELECTION,
+                         int output_dim = NATIVE,
+                         int threads = 0);
+
+    boost::shared_ptr<Gimmick> GetGimmick() { return mGimmick; }
+    //    typedef WxGimmick ViewType;
+    typedef WxGimmickView::EventType EventType;
+
+    ~WxGimmickReaderDialog();
+
+       //===============================================================================================
+       //Image Selection
+       //===============================================================================================
+
+    void GetSelectedImages(std::vector<vtkImageData*>& s, int dim)
+    { mView->GetSelectedImages(s, dim); }
+
+    void GetSelectedImagesInVector(std::vector<vtkImageData*>& s, int dim)
+    { mView->GetSelectedImagesInVector(s, dim); }
+
+    void GetSelectedFiles(std::vector<std::string>& s) 
+    { mView->GetSelectedFiles(s); }
+
+    void OnSelChanged(EventType& event);
+    void OnContextualMenu(EventType& event);
+    void OnMenuTest(wxCommandEvent& event);
+    void OnValid(bool valid);
+    void OnExit(){ mView->StopPlayer(); }
+       void deleteMessage();
+    // void OnButtonOk(wxCommandEvent& event);
+    // void OnButtonCancel(wxCommandEvent& event);
+
+  private :
+
+    boost::shared_ptr<Gimmick>   mGimmick;
+    WxGimmickView* mView;
+
+    wxButton* mOkButton;
+    wxButton* mCancelButton;
+       wxBoxSizer *mtopsizer;
+
+    enum 
+      {
+       TVID = 1
+       //      OKID = 2,
+       //      CANCELID = 3
+      };
+
+  }; // class WxGimmickReaderDialog
+  //=====================================================================
+       
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif  
diff --git a/src/creaImageIOWxGimmickTools.cpp b/src/creaImageIOWxGimmickTools.cpp
new file mode 100644 (file)
index 0000000..6bbcec2
--- /dev/null
@@ -0,0 +1,114 @@
+#include <creaImageIOWxGimmickTools.h>
+
+
+namespace creaImageIO
+{
+       /**
+       ** Begin of the threshold panel
+       **/
+       WxGimmickTools::WxGimmickTools(wxWindow* parent, wxString mCurrentDirectory)
+        : wxPanel(parent, -1, wxDefaultPosition, wxSize(300,250), wxBORDER_SUNKEN)
+       {
+               _currentDir = mCurrentDirectory;
+               _addFiles = true;
+               _mhd      = false;
+
+               _inputPath      = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxSize(400,30));
+               _outputPath     = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxSize(400,30));
+               _addCheckBox    = new wxCheckBox(this, -1,       _T("Add Images to Database?") );
+               _mhdCheckBox    = new wxCheckBox(this, -1,       _T("Convert to MHD?") );
+               _addCheckBox->SetValue(_addFiles);
+               _mhdCheckBox->SetValue(_mhd);           
+
+               wxButton *inputDir  = new wxButton(this, wxID_ANY,_T("Input Directory"),  wxDefaultPosition, wxSize(140,30) );
+               wxButton *outputDir = new wxButton(this, wxID_ANY,_T("Output Directory"), wxDefaultPosition, wxSize(140,30) );
+
+               Connect( inputDir->GetId(),     wxEVT_COMMAND_BUTTON_CLICKED ,  (wxObjectEventFunction) &WxGimmickTools::onInputDir ); 
+               Connect( outputDir->GetId(),    wxEVT_COMMAND_BUTTON_CLICKED ,  (wxObjectEventFunction) &WxGimmickTools::onOutputDir );
+               Connect( _addCheckBox->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, (wxObjectEventFunction) &WxGimmickTools::onAddToDatabase );
+               Connect( _mhdCheckBox->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, (wxObjectEventFunction) &WxGimmickTools::onMHD );
+               
+               wxFlexGridSizer *textSizer = new wxFlexGridSizer(1,2);
+               textSizer->Add( new wxStaticText(this, -1, _T("Transform a Bruker image into Dicom / MHD format.")),          1, wxGROW );
+               textSizer->Add( new wxStaticText(this, -1, _T("If checkbox is selected images will be loaded into the DB.")), 1, wxGROW );
+
+               wxFlexGridSizer *sizer  = new wxFlexGridSizer(2,5);
+               sizer->Add( new wxStaticText(this, -1, _T(" ")), 1, wxGROW );
+               sizer->Add( new wxStaticText(this, -1, _T(" ")), 1, wxGROW );
+               sizer->Add( _inputPath,   1, wxGROW );
+               sizer->Add( inputDir,     1, wxGROW );
+               sizer->Add( _outputPath,  1, wxGROW );
+               sizer->Add( outputDir,    1, wxGROW );
+               sizer->Add( new wxStaticText(this, -1, _T(" ")), 1, wxGROW );
+               sizer->Add( new wxStaticText(this, -1, _T(" ")), 1, wxGROW );
+               sizer->Add( _addCheckBox, 1, wxGROW );
+               sizer->Add( _mhdCheckBox, 1, wxGROW );
+               
+               wxFlexGridSizer *topSizer = new wxFlexGridSizer(1, 2);
+               topSizer->Add( textSizer, 1, wxGROW );
+               topSizer->Add( sizer,     1, wxGROW );
+               this->SetSizer( topSizer );
+               this->SetAutoLayout( true );
+               this->Layout();
+       }
+
+       WxGimmickTools::~WxGimmickTools()
+       {
+
+       }
+
+       wxString WxGimmickTools::getInputDir()
+       {
+               return _inputPath->GetValue();
+       }
+
+       wxString WxGimmickTools::getOutputDir()
+       {
+               return _outputPath->GetValue();
+       }
+
+       bool WxGimmickTools::getAddToDBCheckBoxValue()
+       {
+               return _addCheckBox->GetValue();
+       }
+       
+       bool WxGimmickTools::getMHDCheckBoxValue()
+       {
+               return _mhdCheckBox->GetValue();
+       }       
+
+       void WxGimmickTools::onInputDir(wxCommandEvent& event)
+       {
+               long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
+               wxDirDialog* FD = new wxDirDialog( 0, _T("Select the Input Directory"), _currentDir, style);
+                             
+               if (FD->ShowModal()==wxID_OK)
+               {  
+                       _inputPath->SetValue(FD->GetPath());
+               }
+       }
+
+       void WxGimmickTools::onOutputDir(wxCommandEvent& event)
+       {
+               long style = wxDD_DEFAULT_STYLE;
+               wxDirDialog* FD = new wxDirDialog( 0, _T("Select the Output Directory"), _currentDir, style);
+           
+               if (FD->ShowModal()==wxID_OK)
+               {
+                       _outputPath->SetValue(FD->GetPath());
+               }
+       }
+
+       void WxGimmickTools::onAddToDatabase(wxCommandEvent& event)
+       {
+               _addFiles = _addCheckBox->GetValue();
+       }
+       
+       void WxGimmickTools::onMHD(wxCommandEvent& event)
+       {
+               _mhd = _mhdCheckBox->GetValue();
+       }       
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxGimmickTools.h b/src/creaImageIOWxGimmickTools.h
new file mode 100644 (file)
index 0000000..88e862f
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __creaImageIOWxGimmickTools_h_INCLUDED__
+#define __creaImageIOWxGimmickTools_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+
+#include <creaWx.h>
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup Tools
+   */
+  //=====================================================================
+
+  //=====================================================================
+
+  class WxGimmickTools : public wxPanel
+  {
+       public:
+               WxGimmickTools(wxWindow *parent, wxString mCurrentDirectory);           
+               ~WxGimmickTools();
+
+               wxString getInputDir();
+               wxString getOutputDir();
+               bool getAddToDBCheckBoxValue();
+               bool getMHDCheckBoxValue();
+       private:
+               wxCheckBox * _addCheckBox;
+               wxCheckBox * _mhdCheckBox;
+               wxTextCtrl * _inputPath;
+               wxTextCtrl * _outputPath;
+               wxString _currentDir;
+               bool _addFiles;
+               bool _mhd;
+               void onInputDir(wxCommandEvent& event);
+               void onOutputDir(wxCommandEvent& event);
+               void onAddToDatabase(wxCommandEvent& event);
+               void onMHD(wxCommandEvent& event);
+       };
+  
+} // EO namespace creaImageIO
+
+#endif // USE_WIDGETS
+// EOF
+#endif  
diff --git a/src/creaImageIOWxGimmickView.cpp b/src/creaImageIOWxGimmickView.cpp
new file mode 100644 (file)
index 0000000..91185a5
--- /dev/null
@@ -0,0 +1,1200 @@
+#include <creaImageIOPACSConnection.h>
+#include <creaImageIOWxPACSConnectionPanel.h>
+#include <creaImageIOWxGimmickView.h>
+#include <creaImageIOWxTreeView.h>
+#include <creaImageIOSystem.h>
+#include <creaImageIOWxCustomizeConfigPanel.h>
+#include <creaImageIOWxListenerPanel.h>
+#include <creaImageIOWxEditFieldsPanel.h>
+#include <creaImageIOWxAttributeSelectionPanel.h>
+#include <creaImageIOWxDescriptorPanel.h>
+#include <creaImageIOWxDumpPanel.h>
+#include <creaImageIOWxExportDlg.h>
+
+using namespace crea;
+// Icons
+#include "icons/accept.xpm"
+#include "icons/add.xpm"
+#include "icons/folder-down.xpm"
+#include "icons/page-down.xpm"
+#include "icons/remove.xpm"
+#include "icons/database-add.xpm"
+#include "icons/create-database.xpm"
+#include "icons/help.xpm"
+#include "icons/synchronize.xpm"
+#include "icons/settings.xpm"
+#include "icons/tools.xpm"
+//#include "icons/import.xpm"
+
+#include <wx/imaglist.h>
+#include <wx/popupwin.h>
+#include<boost/filesystem/operations.hpp>
+#if defined(BUILD_BRUKER)
+       #include "bruker2dicom.h"
+#endif
+
+
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+namespace creaImageIO
+{
+   
+  //======================================================================
+  // The ids of the different tools
+  enum
+    {
+        TOOL_ADDFILES_ID    = 1,
+        TOOL_ADDDIR_ID      = 2,
+        TOOL_ADDDATABASE_ID = 3,
+        TOOL_REMOVE_ID      = 4,
+        TOOL_SYNCHRONIZE_ID = 5,
+        TOOL_HELP_ID        = 6,
+        TOOL_SETTINGS_ID    = 7,
+        TOOL_TOOLS_ID       = 8,
+        TOOL_CREATEDB_ID    = 9,
+        TOOL_PACS_ID        = 10
+    };
+  //======================================================================
+
+  //================================================================
+  // 
+  const int icon_number = 11;
+  // Icon ids
+  typedef enum
+    {
+      Icon_create_database,
+      Icon_accept,
+      Icon_add,
+      Icon_folder_down,
+      Icon_page_down,
+      Icon_database_add,
+      Icon_remove,
+      Icon_synchronize,
+      Icon_help,
+      Icon_settings,
+      Icon_tools
+    }
+    icon_id;
+  //================================================================
+
+  //================================================================
+  /*
+  const icon_id Icon[5] = { Icon_Database,  
+                           Icon_Patient,
+                           Icon_Study,
+                           Icon_Series,
+                           Icon_Image };
+  */
+  //================================================================
+
+
+  //======================================================================
+  // CTor
+       WxGimmickView::WxGimmickView(boost::shared_ptr<Gimmick> gimmick,
+                              wxWindow *parent, 
+                              const wxWindowID id,
+                              const wxPoint& pos, 
+                              const wxSize& size,
+                              int min_dim,
+                               int max_dim,
+                              int number_of_threads)
+    : wxPanel(parent,id,pos,size),
+      GimmickView(gimmick, number_of_threads),
+      mProgressDialog(0),
+      mConstructed(false)
+  {
+    GimmickDebugMessage(1,"WxGimmickView::WxGimmickView"
+                       <<std::endl);
+    // Sets the current directory to the home dir
+    mCurrentDirectory =  std2wx(gimmick->GetHomeDirectory());
+
+     // Connect the AddProgress callback
+    gimmick->ConnectAddProgressObserver 
+     ( boost::bind( &WxGimmickView::OnAddProgress , this, _1 ) );
+
+    // Create the list of icons (mIcon)
+    CreateIconList();
+
+    // Global sizer
+    msizer = new wxBoxSizer(wxVERTICAL);
+
+    // Create the tool bar
+    CreateToolBar(); 
+    msizer->Add( mToolBar, 0, wxGROW, 0);
+
+    // Split part below toolbar into notebook for views and panel
+    // for preview, messages...
+    mSplitter = new wxSplitterWindow( this , -1);
+
+    // Notebook
+    mNotebook = new wxNotebook(mSplitter,
+                              -1, wxDefaultPosition, wxDefaultSize, 0);
+
+    //Gimmick
+    mGimmick=gimmick;
+
+    mSelectionMaxDimension = max_dim;
+    mSelectionMinDimension = min_dim;
+    
+    // Create the views
+    CreateTreeViews();
+
+    // Bottom panel 
+    mBottomPanel = new wxPanel(mSplitter,-1);
+    
+    mbottom_sizer = new wxBoxSizer(wxVERTICAL); //HORIZONTAL);
+    
+    
+    // Previewer
+    mViewer = new WxViewer(mBottomPanel, wxID_ANY, wxT("Gimmick! Viewer"),wxDefaultPosition, wxDefaultSize );
+       //pointers.push_back(new ImagePointerHolder(GetDefaultImage())
+       pointers.push_back(boost::shared_ptr<creaImageIO::ImagePointerHolder>(new ImagePointerHolder(GetDefaultImage())));
+
+       mViewer->SetImageVector(pointers);
+       mViewer->StartPlayer();
+
+
+    mbottom_sizer->Add(mViewer,1,wxGROW,1);
+    //    mViewer->Show();
+
+    mText = new wxStaticText(mBottomPanel, wxID_ANY, wxT("Welcome to Gimmick!"));
+    mbottom_sizer->Add(mText,0,wxGROW,0);
+
+         
+         
+    mBottomPanel->SetSizer(mbottom_sizer);
+
+    // Splitting
+    int hsize = size.GetHeight();
+
+    int top_minsize = 450;
+    int bottom_minsize = 50;
+
+    mSplitter->SetMinimumPaneSize( bottom_minsize );
+    mSplitter->SplitHorizontally( mNotebook, mBottomPanel, 
+                                 top_minsize);
+
+    msizer->Add( mSplitter, 1, wxGROW, 0);
+
+    mProgressDialog=0;
+    SetSizer( msizer );     
+    SetAutoLayout(true);
+    Layout();
+    //mListener=new Listener();
+    //mListener->ConnectObserver(boost::bind( &WxGimmickView::OnDriveMount, this, _1 ) );
+    //mListener->Create();
+   // mListener->Run();
+   // mListener->Pause();
+
+    mConstructed = true;
+  }
+  //======================================================================
+
+  //======================================================================
+  /// Destructor
+  WxGimmickView::~WxGimmickView()
+  {
+       // stop the viewer before application exit.
+    mViewer->StopPlayer();
+    GimmickDebugMessage(1,"WxGimmickView::~WxGimmickView"
+                       <<std::endl);
+       delete mIcon;
+       delete mViewer;
+    //if(mListener->IsAlive())   {        mListener->Delete();    }
+  }
+  //======================================================================
+  
+  //======================================================================
+  /// Creates the tool bar
+  void WxGimmickView::CreateToolBar()
+  {
+    long style = wxTB_HORIZONTAL | wxNO_BORDER | wxTB_TEXT;
+    mToolBar = new wxToolBar(this,-1,wxDefaultPosition,wxDefaultSize,
+                            style);
+
+    mToolAddFile = mToolBar->AddTool( TOOL_ADDFILES_ID, 
+                                     _T("Add file(s)"),
+                                     mIcon->GetBitmap(Icon_page_down),
+                                     _T("Add one or more file to database")
+                                     );
+    mToolAddDir = mToolBar->AddTool( TOOL_ADDDIR_ID, 
+                                     _T("Add folder"),
+                                     mIcon->GetBitmap(Icon_folder_down),
+                                     _T("Add the content of a folder to database")
+                                     );
+    mToolAddDatabase = mToolBar->AddTool( TOOL_ADDDATABASE_ID, 
+                                     _T("Open database"),
+                                     mIcon->GetBitmap(Icon_database_add),
+                                     _T("Open a local or distant database")
+                                     );
+    mToolRemove = mToolBar->AddTool( TOOL_REMOVE_ID, 
+                                     _T("Remove"),
+                                     mIcon->GetBitmap(Icon_remove),
+                                     _T("Remove selected items")
+                                     );
+    mToolSynchronize = mToolBar->AddTool( TOOL_SYNCHRONIZE_ID, 
+                                     _T("Synchronize"),
+                                     mIcon->GetBitmap(Icon_synchronize),
+                                     _T("Synchronizes the database with disk")
+                                     );
+    mToolHelp = mToolBar->AddTool( TOOL_HELP_ID, 
+                                     _T("Help"),
+                                     mIcon->GetBitmap(Icon_help),
+                                     _T("Open help window")
+                                     );
+    mToolSettings = mToolBar->AddTool( TOOL_SETTINGS_ID, 
+                                     _T("System settings"),
+                                     mIcon->GetBitmap(Icon_settings),
+                                     _T("Allows the modification of various system settings")
+                                     );
+    mToolTools = mToolBar->AddTool( TOOL_TOOLS_ID, 
+                                     _T("Tools"),
+                                     mIcon->GetBitmap(Icon_tools),
+                                     _T("Applies tools to images")
+                                     );
+    mToolAddFile = mToolBar->AddTool( TOOL_CREATEDB_ID, 
+                                     _T("Create database"),
+                                     mIcon->GetBitmap(Icon_create_database),
+                                     _T("Create DB from an Attributes Descriptor file")
+                                     );
+#if defined(BUILD_PACS)
+       mToolAddFile = mToolBar->AddTool( TOOL_PACS_ID, 
+                                     _T("PACS Connection,"),
+                                     mIcon->GetBitmap(Icon_create_database),
+                                     _T("Echo, Find and Get to a PACS")
+                                     );
+#endif
+    //const wxBitmap& bitmap1, const wxString& shortHelpString = "", wxItemKind kind = wxITEM_NORMAL)
+
+    mToolBar->Realize();
+  }
+  //======================================================================
+
+  //======================================================================
+  /// Create the tree view for TreeHandler provided
+  void WxGimmickView::CreateTreeView( TreeHandler* h)
+  {
+    std::string name(h->GetTree().GetAttribute("Name"));
+    GimmickMessage(2,"Creating the tree view for '"<<
+                  name<<"'"<<std::endl);
+    // Create the WxTreeView
+    WxTreeView* view = new WxTreeView(h, this, mNotebook, -1);
+
+    // TO DO : TEST THAT A VIEW WITH SAME NAME IS NOT
+    // ALREADY IN THE MAP
+    GetTreeViewMap()[name] = view;
+
+    // Add Notebook page
+    mNotebook->AddPage( view, crea::std2wx(name) );
+       
+  }
+
+  //======================================================================
+  void WxGimmickView::GetSelectedImages(std::vector<vtkImageData*>& s, int dim)
+  {
+       std::vector<std::string> files;
+       GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetSelectedAsString(files);
+       ReadImagesNotThreaded(s, files, dim);
+  }
+
+  //======================================================================
+  void WxGimmickView::GetSelectedImagesInVector(std::vector<vtkImageData*>& s, int dim)
+  {
+       std::vector<std::string> files;
+       GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetSelectedAsString(files);
+       ReadImagesNotThreadedInVector(s, files, dim);
+  }
+  //======================================================================
+
+  //======================================================================
+  void WxGimmickView::GetSelectedFiles(std::vector<std::string>& s)
+  {
+       GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetSelectedAsString(s);
+  }
+  //======================================================================
+
+  //======================================================================
+  void WxGimmickView::GetImages(int dim, 
+                               const std::vector<std::string>& files, 
+                               std::vector<vtkImageData*>& s)
+  {
+       ReadImagesNotThreaded(s,files,dim);
+  }
+  //======================================================================
+
+
+  //=================================================
+  void WxGimmickView::CreateIconList()
+  {
+    // Size of the icons;
+    int size = 16;
+
+    wxIcon icons[20];
+    // should correspond to Icon_xxx enum
+    icons[Icon_accept]          = wxIcon(accept_xpm);
+    icons[Icon_add]             = wxIcon(add_xpm);
+    icons[Icon_folder_down]     = wxIcon(folder_down_xpm);
+    icons[Icon_page_down]       = wxIcon(page_down_xpm);
+    icons[Icon_remove]          = wxIcon(remove_xpm);
+    icons[Icon_database_add]    = wxIcon(database_add_xpm);
+    icons[Icon_help]            = wxIcon(help_xpm);
+    icons[Icon_synchronize]     = wxIcon(synchronize_xpm);
+    icons[Icon_create_database] = wxIcon(create_database_xpm);
+    icons[Icon_settings]        = wxIcon(settings_xpm);
+    icons[Icon_tools]           = wxIcon(tools_xpm);
+
+    //   unsigned int NbIcons = 8;
+    // Make an image list containing small icons
+    mIcon = new wxImageList(size,size,true);
+    
+    // Make all icons the same size = size of the first one
+    int sizeOrig = icons[0].GetWidth();
+    for ( size_t i = 0; i < icon_number; i++ )
+      {
+       if ( size == sizeOrig )
+         {
+           mIcon->Add(icons[i]);
+         }
+        else
+         {
+            mIcon->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
+         }
+      }
+  }
+  //=================================================
+
+
+  //=================================================
+  void WxGimmickView::OnAddFiles(wxCommandEvent& event)
+  {
+    mViewer->StopPlayer();
+    long style = wxOPEN | wxFILE_MUST_EXIST | wxFD_MULTIPLE;
+    std::string wc("*");
+    wxFileDialog* FD = new wxFileDialog( 0, 
+                                        _T("Select file"),
+                                        _T(""),
+                                        _T(""),
+                                        crea::std2wx(wc),
+                                        style,
+                                        wxDefaultPosition);
+    
+    if (FD->ShowModal()==wxID_OK)
+      {
+       wxBusyCursor busy;
+
+       wxArrayString files;
+       FD->GetPaths(files);
+       unsigned int i;
+       std::vector<std::string> filenames;
+       for (i=0;i<files.GetCount();++i)
+       {
+         filenames.push_back(wx2std(files[i]));
+         GimmickMessage(2,"Adding File "<<files[i]<<"."<<std::endl);
+       }
+
+       mProgressDialog = 
+         new wxProgressDialog(_T("Adding file(s)"),
+                              _T(""),
+                              1000,
+                              this,
+                              wxPD_ELAPSED_TIME |
+                              // wxPD_ESTIMATED_TIME |
+                              // wxPD_REMAINING_TIME |
+                              wxPD_CAN_ABORT );
+
+       // TO DO : select the current tree handler
+       mGimmick->AddFiles(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),filenames);
+
+       mProgressDialog->Pulse(_T("Updating view..."));
+
+       UpdateTreeViewLevel(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),1);
+       delete mProgressDialog;
+       DisplayAddSummary();    
+
+      }
+       mViewer->StartPlayer(); 
+  }
+  //=================================================
+
+  //=================================================
+  void WxGimmickView::OnAddDir(wxCommandEvent& event)
+  {
+    mViewer->StopPlayer();
+       std::string name = crea::wx2std(mNotebook->GetCurrentPage()->GetName());
+    long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
+    wxDirDialog* FD = 
+         new wxDirDialog( 0, 
+                      _T("Select directory"),
+                      mCurrentDirectory,
+                      style);
+    
+    if (FD->ShowModal()==wxID_OK)
+    {
+       std::string dirname = wx2std (FD->GetPath());
+       bool recurse =  isNeedRecursive(dirname);
+       if (recurse)
+       {
+             recurse = wxMessageBox(_T("Recurse into sub-directories ?"), _T("Scan directory"), wxYES_NO,this ) == wxYES ? true : false;
+       }
+
+               wxBusyCursor busy;
+               wxString title(_T("Adding directory"));
+               if (recurse) 
+               title = _T("Adding directory (recursive)");
+               mProgressDialog = 
+               new wxProgressDialog(_T("Adding directory"),
+                                       _T(""),
+                                       NumberFilesToAdd(dirname,recurse),
+                                       this,
+                                       wxPD_ELAPSED_TIME | 
+                                       wxPD_SMOOTH |
+                                       // wxPD_ESTIMATED_TIME |
+                                       // wxPD_REMAINING_TIME |
+                                       wxPD_CAN_ABORT );
+
+               mCurrentDirectory = FD->GetPath();  
+               mGimmick->AddDir(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),dirname,recurse);
+               mProgressDialog->Pulse(_T("Updating view..."));
+
+               UpdateTreeViewLevel(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),1);
+               delete mProgressDialog;
+               DisplayAddSummary();
+         }
+    mViewer->StartPlayer();
+       delete FD;
+  }
+
+
+  //=================================================
+  // Determines number of files potentially to add to database
+   int WxGimmickView::NumberFilesToAdd(const std::string &dirpath, bool recursive)
+  {
+          int nb = 0;
+          if ( !boost::filesystem::exists( dirpath ) ) return nb;
+          boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
+          for ( boost::filesystem::directory_iterator itr( dirpath );  itr != end_itr;  ++itr )
+         {
+               // If is directory & recurse : do recurse
+               if ( boost::filesystem::is_directory(itr->status()) )
+               {
+                       if (recursive) 
+                       {
+                               nb += NumberFilesToAdd(itr->string(), recursive);
+                       }
+               }
+               else
+               {
+                       nb++;
+               }
+         }
+       return nb;
+  }
+
+   //=================================================
+   // Test a directory to know if contains sub-directory to analyze
+  bool WxGimmickView::isNeedRecursive(std::string i_name)
+  {
+      boost::filesystem::directory_iterator iter(i_name), end_iter;
+         bool bfindir = false;
+                 for(; iter != end_iter; ++iter)
+                 {
+                         if(boost::filesystem::is_directory(*iter))
+                         {
+                                 return true;
+                         }
+                 }
+                 return false;
+  }
+  //=================================================
+
+  //=================================================
+  void WxGimmickView::OnSelectionChange(const std::vector<tree::Node*>& sel, bool isSelection, int selection, bool needProcess)
+  {      
+    GimmickDebugMessage(5,
+                       "WxGimmickView::OnSelectionChange"
+                       <<std::endl);
+    wxBusyCursor busy;
+       bool valid=true;
+       
+       if(sel.size()==0)
+       {
+               valid= ValidateSelected(NULL,
+                               mSelectionMinDimension,
+                               mSelectionMaxDimension );
+       }
+       else if(needProcess)
+       {
+               ResetExtent();
+               std::vector<tree::Node*>::const_iterator i;
+               for(i=sel.begin();i!=sel.end()&&valid;++i)
+               {
+                       valid= ValidateSelected((*i),
+                               mSelectionMinDimension,
+                               mSelectionMaxDimension );
+               }
+       }
+       else if(isSelection)
+       {
+               valid= ValidateSelected(sel.front(),
+                               mSelectionMinDimension,
+                               mSelectionMaxDimension );
+       }
+       else
+       {
+               ResetExtent();
+               std::vector<tree::Node*>::const_iterator i;
+               for(i=sel.begin();i!=sel.end()&&valid;++i)
+               {
+                       valid= ValidateSelected((*i),
+                               mSelectionMinDimension,
+                               mSelectionMaxDimension );
+               }
+       }
+       mText->SetLabel(crea::std2wx(GetMessage()));
+    /*if(valid)
+      {
+       ReadImageThreaded(sel);
+      }
+    else
+      {
+                 ClearSelection();
+      }*/
+       ReadImageThreaded(sel);
+   }
+
+  //==================================================
+
+  //==================================================
+  ///Reads Images (Threaded)
+  void WxGimmickView::ReadImageThreaded(const std::vector<tree::Node*>& sel)
+  {    
+   GimmickDebugMessage(5,
+                      "ReadImageThreaded"
+                      <<std::endl);
+   int maxprio = GetMaximalPriority();
+   int prio = maxprio + 2000;
+
+   if(sel.size()>0)
+   {
+   //First load the selected images
+   mCurImageItemToShow = sel.front();
+   pointers.clear();
+   int index = 0;
+   std::vector<tree::Node*>::const_iterator selected;
+   for(selected=sel.begin();selected!=sel.end();++selected)
+     {
+       GimmickDebugMessage(5,
+                          "Requesting image from selected "
+                          <<(*selected)->GetAttribute("FullFileName")
+                          <<std::endl);
+          //ImagePointerHolder* ph=new ImagePointerHolder(GetDefaultImage());
+          boost::shared_ptr<ImagePointerHolder> ph(new ImagePointerHolder(GetDefaultImage()));
+          pointers.push_back(ph);
+       RequestReading(*selected,prio,index,ph);
+       //       AddEntryToMap(*selected);
+       prio--;
+       index++;
+     }
+       mViewer->SetImageVector(pointers);
+       //Going up
+       prio = maxprio + 20;
+       std::vector<tree::Node*> up;
+       GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetNodes(up,true);
+       std::vector<tree::Node*>::iterator iterUp;
+       for(iterUp=up.begin();iterUp!=up.end();++iterUp)
+       {
+               GimmickDebugMessage(5,
+                               "Requesting image from neighbors up "
+                               <<(*iterUp)->GetAttribute("FullFileName")
+                               <<std::endl);
+//             ImagePointerHolder* ph=new ImagePointerHolder(GetDefaultImage());
+               boost::shared_ptr<ImagePointerHolder> ph(new ImagePointerHolder(GetDefaultImage()));
+               RequestReading(*iterUp,prio,-1,ph);
+               //              AddEntryToMap(*iterUp);
+               prio--;
+               if (prio == maxprio) break;
+       }
+
+       //Going down
+       prio = maxprio + 19;
+       std::vector<tree::Node*> down;
+       GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetNodes(down,false);
+       std::vector<tree::Node*>::iterator iterDown;
+       for(iterDown=down.begin();iterDown!=down.end();++iterDown)
+       {
+               GimmickDebugMessage(5,
+                               "Requesting image from neighbors down "
+                               <<(*iterDown)->GetAttribute("FullFileName")
+                               <<std::endl);
+               //ImagePointerHolder* ph=new ImagePointerHolder(GetDefaultImage());
+               boost::shared_ptr<ImagePointerHolder> ph(new ImagePointerHolder(GetDefaultImage()));
+               RequestReading(*iterDown,prio,-1,ph);
+               //              AddEntryToMap(*iterDown);
+               prio--;
+               if (prio == maxprio) break;
+       }
+   }
+   else
+   {
+          pointers.clear();
+          //ImagePointerHolder* ph=new ImagePointerHolder(GetDefaultImage());
+          boost::shared_ptr<ImagePointerHolder> ph(new ImagePointerHolder(GetDefaultImage()));
+          pointers.push_back(ph);
+          mViewer->SetImageVector(pointers);
+   }
+  }
+
+  //==================================================
+
+  //==================================================
+
+#if defined(WIN32)
+  //==================================================
+   void  WxGimmickView::OnInternalIdle()
+   {
+     if (!mConstructed) return;
+     static bool first_time = true;
+     if (false)
+     {
+       first_time = false;
+     }
+   //   GimmickMessage(1,"WxGimmickView : Refresh viewer"<<std::endl);
+       //  mViewer->StartPlayer();
+     if(mViewer)
+     {
+        mViewer->RefreshIfNecessary();
+     }
+  }
+#else
+  void WxGimmickView::UpdateWindowUI(long flags)
+  {
+         if(mViewer)
+     {
+        mViewer->RefreshIfNecessary();
+     }
+  }
+#endif
+   //==================================================
+
+  //==================================================
+   void  WxGimmickView::ClearSelection()
+   {
+       pointers.clear();
+       pointers.push_back(boost::shared_ptr<creaImageIO::ImagePointerHolder>(new ImagePointerHolder(GetDefaultImage())));
+       //pointers.push_back(new ImagePointerHolder(GetDefaultImage()));
+       mViewer->SetImageVector(pointers);
+       mViewer->RefreshIfNecessary();
+       ResetExtent();
+  }
+
+  //=================================================
+  //=================================================
+  void WxGimmickView::OnRemove(wxCommandEvent& event)
+  {
+       //TODO Select current tree handler       
+     wxBusyCursor busy;
+        std::string remove;
+        mGimmick->GetSetting(SETTINGS_REMOVE_PATIENT_DISPLAY,remove);
+        GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->RemoveSelected(remove);
+        mGimmick->UpdateSetting(SETTINGS_REMOVE_PATIENT_DISPLAY,remove);
+     ClearSelection();
+  }
+  //=================================================
+
+
+  //=================================================
+  void WxGimmickView::AddIgnoreFile(tree::Node* toRemove)
+  {
+     mGimmick->RemoveFile(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),toRemove);
+   //  GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->UpdateLevel(1);
+  }
+
+  //=================================================
+  void WxGimmickView::CopyFiles(const std::vector<std::string>& filenames)
+  {
+     mGimmick->CopyFiles(filenames, crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())));
+     wxMessageBox(std2wx("The selected files have been copied"),_T("Copy files"),wxOK,this);
+  }
+
+   //=================================================
+  void WxGimmickView::AddDir(std::string dirName)
+  {
+     mProgressDialog = new wxProgressDialog(_T("Adding directory"),_T(""),1000,this,wxPD_ELAPSED_TIME |wxPD_CAN_ABORT );
+     mCurrentDirectory = crea::std2wx(dirName);
+     mGimmick->AddDir(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),dirName,true);
+     mProgressDialog->Pulse(_T("Updating view..."));
+
+     UpdateTreeViewLevel(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),1);
+     delete mProgressDialog;
+     DisplayAddSummary();
+  }
+
+   //=================================================
+  void WxGimmickView::OnSynchronize(wxCommandEvent& event)
+  {       
+    wxBusyCursor busy;
+    const wxString choices[] = { _T("Check database for files deletion and addition and give a report."), 
+                               _T("Check database for files deletion, addition and attributes change. Then give a report."), 
+                               _T("Repair database (remove deleted files and add new files)."), 
+                               _T("Repair database (remove deleted files, add new files and reset changed attributes).") } ;
+
+    wxSingleChoiceDialog dialog(this,
+                               _T("Select one of the following synchronization actions:\n")
+                                _T("Please note that, due to the heavy amount of operations required, this action might take a while."),
+                                _T("Synchronization Settings"),
+                                WXSIZEOF(choices), choices);
+
+    //dialog.SetSelection(0);
+
+    if (dialog.ShowModal() == wxID_OK)
+    {
+                       wxBusyCursor busy;
+        int sel=dialog.GetSelection();
+       bool repair=false;
+       bool checkAttributes=false;
+       if(sel==2 || sel==3){repair=true;}
+       if(sel==1 || sel==3){checkAttributes=true;}
+       std::string mess=mGimmick->Synchronize(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),repair, checkAttributes);
+       wxMessageBox(std2wx(mess),_T("Synchronization result"),wxOK,this);
+       if(sel==2 || sel==3){
+               GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->UpdateLevel(1);
+       }
+               
+    }
+  }
+  //=================================================
+
+  //=================================================
+  void WxGimmickView::OnSettings(wxCommandEvent& event)
+  {
+    wxDialog* dial= new wxDialog (this,-1,_T("System Settings"),wxDefaultPosition, wxSize(450,220));
+    wxBoxSizer *siz = new wxBoxSizer(wxVERTICAL);
+    // Notebook
+    wxNotebook* nb= new wxNotebook(dial, -1, wxDefaultPosition, wxDefaultSize, 0);
+    
+    siz->Add( nb,1,wxGROW  ,0);  
+    CreateSettingsDialog(nb,dial);
+    dial->SetSizer(siz);
+    dial->ShowModal();
+  }
+
+  //=================================================
+  void WxGimmickView::OnImportExport(wxCommandEvent &Event)
+  {
+       wxBusyCursor busy;
+       // Test if one image is selected => export
+       // if not =>import
+    if (GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))])
+       {
+               ExportImages();
+       }
+       else
+       {
+               ImportImages();
+       }
+  }
+
+  void WxGimmickView::ExportImages()
+  {
+               //Archive selection: name, emplacement
+               //same process than copy local but to a zip
+               // if settings are yes "always ask for descriptor addition", ask
+               // if settings are yes, adding descriptor
+  }
+
+  void WxGimmickView::ImportImages()
+  {
+               //Find the *.zip
+               //dezip
+               // Contain a descriptor.text
+               // create a new database, and add to database
+               // if not, add to current database
+               // 
+  }
+
+  //=================================================
+  //AndresDonadio
+  void WxGimmickView::OnTools(wxCommandEvent& event)
+  {
+       mViewer->StopPlayer();
+               
+       wxDialog* dial = new wxDialog (this,-1,_T("Tools"),wxDefaultPosition, wxSize(550,350));
+
+       wxSizer* buttonsSizer = dial->CreateSeparatedButtonSizer(wxOK|wxCANCEL);
+       wxNotebook* nb= new wxNotebook(dial, -1, wxDefaultPosition, wxDefaultSize, 0);
+       wxBoxSizer *dialSizer = new wxBoxSizer(wxVERTICAL);     
+       dialSizer->Add(nb,1,wxGROW,0);
+       dialSizer->Add(buttonsSizer,0,wxGROW);
+
+#if defined(BUILD_BRUKER)
+       //First page: Bruker Image Reader
+       WxGimmickTools * gimmickTools = new WxGimmickTools(nb, mCurrentDirectory);
+       nb->AddPage( gimmickTools, _T("Bruker Image Reader") );
+#endif
+
+       dial->SetSizer(dialSizer, true);
+       dial->Layout();
+       dial->ShowModal();
+
+       if (dial->GetReturnCode() == wxID_OK)
+       {
+#if defined(BUILD_BRUKER)
+               if (nb->GetSelection()==0)//Selection: Bruker Image Reader
+               {
+                       std::string inputDir  = crea::wx2std(gimmickTools->getInputDir());
+                       std::string outputDir = crea::wx2std(gimmickTools->getOutputDir());
+                       
+                       bool addToDB = gimmickTools->getAddToDBCheckBoxValue();
+
+                       if (inputDir.compare("")!=0 && outputDir.compare("")!=0)
+                       {
+                               if ( wxMessageBox(_T("Depending on the amount of Data the process can take between 1 and 5 minutes. Do you want to continue?"),
+                                                 _T("Please confirm"), wxICON_QUESTION | wxYES_NO) == wxYES )
+                               {
+                                       Bruker2Dicom b2d;    
+                                       b2d.SetInputDirectory(inputDir);
+                                       b2d.SetOutputDirectory(outputDir);
+                                       b2d.SetConvertModeToDicom();
+                                       b2d.verbose=false;
+                                       b2d.Execute();
+
+                                       if (addToDB)
+                                       {
+                                               mProgressDialog = new wxProgressDialog(_T("Adding directory"),_T(""),1000,this,wxPD_ELAPSED_TIME |wxPD_CAN_ABORT );
+                                               mCurrentDirectory = gimmickTools->getOutputDir();
+                                               mGimmick->AddDir(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),outputDir,true);
+                                               mProgressDialog->Pulse(_T("Updating view..."));
+
+                                               UpdateTreeViewLevel(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),1);
+                                               delete mProgressDialog;
+                                               DisplayAddSummary();
+                                       }       
+                               }
+                       }
+                       else
+                       {
+                               wxMessageBox(_T("One or both of the directory fields are empty"),_T("Empty Fields"),wxOK,this);
+                       }
+       }
+       delete gimmickTools;
+#endif
+       }
+       mViewer->StartPlayer();
+  }
+
+  //=================================================
+
+  void WxGimmickView::CreateSettingsDialog(wxNotebook* nb, wxDialog* dial)
+  {
+         //First page: Customization of configurations
+         //Copy Path string
+         std::string cp;
+         mGimmick->GetSetting(SETTINGS_COPY_PATH,cp);
+         //Database Path String
+         std::string dp;
+         mGimmick->GetSetting(SETTINGS_DBPATH,dp);
+         //Syncronization Event String
+         std::string se;
+         mGimmick->GetSetting(SETTINGS_SYNC_EVENT,se);
+         //Syncronization Frequency String
+         std::string sf;
+         mGimmick->GetSetting(SETTINGS_SYNC_FREQ,sf);
+
+         WxCustomizeConfigPanel * customConfig=new WxCustomizeConfigPanel(nb,dial,this,cp,dp,se,sf);
+
+         nb->AddPage( customConfig, crea::std2wx("Customize Configuration") );
+
+         //Second page: Creation of Databases
+         /*wxPanel* databaseCreation=new wxPanel(nb);
+         nb->AddPage( databaseCreation, crea::std2wx("Create Database") );*/
+
+         //Second page (temporary): Connection to PACS
+         WxPACSConnectionPanel* pacs=new WxPACSConnectionPanel(nb,dial, this);
+         nb->AddPage( pacs, crea::std2wx("Connect to PACS") );
+
+         //Third page: CD/DVD Watch
+         WxListenerPanel* cdWatch=new WxListenerPanel(nb,dial, this,true);//, mListener->IsPaused());
+         nb->AddPage( cdWatch, crea::std2wx("CD/DVD") );
+
+         //Fourth page: Selection of attributes to show
+         std::vector<std::string> shown;
+         std::vector<std::string> nShown;
+         GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetAttributes(shown,nShown,1);
+         int nLev=GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetNumberOfLevels();
+         WxAttributeSelectionPanel* attSelection=new WxAttributeSelectionPanel(nb,dial,this,shown,nShown,nLev);
+         nb->AddPage( attSelection, crea::std2wx("Selection of Attributes") );
+  }
+
+  //===================================================================
+  void WxGimmickView::GetVisibleAttributes(std::vector<std::string>& shown, 
+         std::vector<std::string>& nShown, int level)
+  {
+         GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->GetAttributes(shown,nShown,level);
+  }
+
+  //===================================================================
+  void WxGimmickView::OnAttributesChanged(const std::vector<std::string>& nShown, int level)
+  {
+         GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->SetNonVisibleAttributes(nShown,level);
+         std::vector<std::string> n=nShown;
+         GetTreeViewMap()[crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection()))]->CreateCtrl(n,level);
+  }
+  //===================================================================
+  void WxGimmickView::OnSaveSettingsCallback(const std::string& copyPath,
+         const std::string& dbPath,
+         const std::string& syncEvent,
+         const std::string& syncFreq)
+  {
+         mGimmick->UpdateSetting(SETTINGS_COPY_PATH,copyPath);
+         mGimmick->UpdateSetting(SETTINGS_DBPATH,dbPath);
+         mGimmick->UpdateSetting(SETTINGS_SYNC_EVENT,syncEvent);
+         mGimmick->UpdateSetting(SETTINGS_SYNC_FREQ,syncFreq);
+  }
+
+  //===================================================================
+  void WxGimmickView::OnListenerCallback(const std::string& drive, bool addFiles, bool removeFiles)
+  {
+        mListener->SetMonitoredDrive(drive);
+        mListener->SetAddFilesState(addFiles);
+        mListener->SetRemoveFilesState(removeFiles);
+  }
+
+  //========================================================================
+
+  void WxGimmickView::OnDriveMount(bool mount)
+  {
+         GimmickMessage(1, "Gimmick::OnDriveMount"<<std::endl);
+         std::string drive;
+         mListener->GetMonitoredDrive(drive);
+         
+         if(mount)
+         {
+               mViewer->StopPlayer();
+               wxBusyCursor busy;
+               wxString title(_T("Adding drive"));
+               mProgressDialog = 
+               new wxProgressDialog(_T("Adding drive"),
+                                       _T(""),
+                                       1000,
+                                       this,
+                                       wxPD_ELAPSED_TIME |
+                                       //                             wxPD_ESTIMATED_TIME | 
+                                       //                             wxPD_REMAINING_TIME |
+                                       wxPD_CAN_ABORT );
+               mCurrentDirectory = crea::std2wx(drive);
+               mGimmick->AddDir(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),drive,true);
+               mProgressDialog->Pulse(_T("Updating view..."));
+               
+               UpdateTreeViewLevel(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),1);
+               delete mProgressDialog;
+               DisplayAddSummary();
+               mViewer->StartPlayer();  
+         }
+         else
+         {  
+                 mGimmick->DeleteDrive(drive);
+                 UpdateTreeViewLevel(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),1);
+         } 
+  }
+
+   //========================================================================
+
+  void WxGimmickView::StartListeningThread()
+  {
+         mListener->Resume();
+  }
+
+   //========================================================================
+
+  void WxGimmickView::StopListeningThread()
+  {
+         mListener->Pause();
+  }
+
+  //========================================================================
+  void WxGimmickView::CreateEditFieldsDialog(tree::Node* node, std::vector<std::string> names, std::vector<std::string> keys)
+  {
+    wxDialog* dial= new wxDialog (this,-1,crea::std2wx("Edit Fields for node "+node->GetLabel()),wxDefaultPosition, wxSize(350,155));
+    wxBoxSizer *siz = new wxBoxSizer(wxVERTICAL);
+    WxEditFieldsPanel* ef = new WxEditFieldsPanel(dial, dial, this, node, names, keys);
+
+    siz->Add( ef,1,wxGROW  ,0); 
+    dial->SetSizer(siz);
+    dial->ShowModal();  
+  }
+
+       
+
+ //========================================================================
+  void WxGimmickView::DumpTags(std::string i_filename)
+  {
+    WxDumpPanel* pan= new WxDumpPanel (this,i_filename);
+    pan->ShowModal();  
+  }
+
+  //========================================================================
+  void WxGimmickView::ExportToStorage(const std::vector<std::string> i_filenames)
+  {
+       std::vector<std::string> storages;
+       Gimmick::TreeHandlerMapType::iterator it = mGimmick->GetTreeHandlerMap().begin();
+       for(;it != mGimmick->GetTreeHandlerMap().end(); it++)
+       {
+               storages.push_back(it->first);
+       }
+
+    WxExportDlg* exp= new WxExportDlg(this,storages);
+       if ( exp->ShowModal() ==ID_EXPORT_OK)
+       {
+               std::string storage = exp->GetStorage();
+               mProgressDialog = 
+           new wxProgressDialog(_T("Adding file(s)"),
+                              _T(""),
+                              1000,
+                              this,
+                              wxPD_ELAPSED_TIME |
+                              // wxPD_ESTIMATED_TIME |
+                              // wxPD_REMAINING_TIME |
+                              wxPD_CAN_ABORT );
+               mGimmick->AddFiles(storage,i_filenames);
+               mProgressDialog->Pulse(_T("Updating view..."));
+               UpdateTreeViewLevel(storage,1);
+               delete mProgressDialog;
+               DisplayAddSummary();    
+       }
+  }
+
+
+
+  //========================================================================
+  void WxGimmickView::OnFieldsEdited(tree::Node* node, const std::string& name, const std::string& key, const std::string& val)
+  {
+     mGimmick->EditField(node, crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())), name, key, val);
+     UpdateTreeViewLevel(crea::wx2std(mNotebook->GetPageText(mNotebook->GetSelection())),1);
+  }
+
+  //=================================================
+  /// AddProgress Gimmick callback
+  void WxGimmickView::OnAddProgress( Gimmick::AddProgress& p)
+  {
+    char mess[200];
+    sprintf(mess,"%i dirs : %i files :\n            %i handled - %i added",
+          p.GetNumberScannedDirs(),
+          p.GetNumberScannedFiles(),
+          p.GetNumberHandledFiles(),
+          p.GetNumberAddedFiles());
+    //    std::cout << "OnAddProgress "<<mess<<std::endl;
+    wxString s(wxString::From8BitData(mess));
+    //  std::cout << "Pulse"<<std::endl;
+    if (!mProgressDialog->Pulse(s)) 
+      {
+       p.SetStop();
+      }
+    //  std::cout << "OnAddProgress ok"<<std::endl;
+  }
+  //=================================================
+
+  //=================================================
+  void WxGimmickView::DisplayAddSummary()
+  {
+    const Gimmick::AddProgress& p = mGimmick->GetAddProgress();
+    std::stringstream mess;
+    mess << "Dirs \tscanned\t: " << p.GetNumberScannedDirs()  << "\n";
+    mess << "Files\tscanned\t: " << p.GetNumberScannedFiles() << "\n";
+    mess << "Files\thandled\t: " << p.GetNumberHandledFiles() << "\n\n";
+    mess << "Files\tadded  \t: " << p.GetNumberAddedFiles()   << "\n\n";
+    wxMessageBox(std2wx(mess.str()),_T("Addition result"),wxOK,this);
+  }
+
+  ////////////////////////////////////////////////
+  // Add a DB to application                   //
+  // @param event : WxEvent                    //
+  // @return : -                               //
+  ////////////////////////////////////////////////
+  void WxGimmickView::OnAddDB(wxCommandEvent& event)
+  {
+         //Select DB
+         long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
+         std::string wc("*.sqlite3*");
+         wxFileDialog* FD = new wxFileDialog( 0, 
+                                        _T("Select file"),
+                                        _T(""),
+                                        _T(""),
+                                        crea::std2wx(wc),
+                                        style,
+                                        wxDefaultPosition);
+    
+    if (FD->ShowModal()==wxID_OK)
+       {
+               wxBusyCursor busy;
+               wxArrayString files;
+               FD->GetPaths(files);
+               std::stringstream st;
+               for(int i = 0; i< files.size(); i++)
+               {
+                       //get name of DB (file name)
+                 size_t pos = files[i].find_last_of(_T("\\"));
+                 std::string name = crea::wx2std(files[i].substr(pos+1));
+                 pos = name.find_last_of(".");
+                 name = name.substr(0,pos);
+                 //create TreeHandler
+                 mGimmick->addDB(name, crea::wx2std(files[i]));
+                 //create TreeView
+                 CreateSingleTreeView(name);
+               }
+       }
+  }
+    ////////////////////////////////////////////////////
+  // Create a DB from an Attributes Descriptor files  //
+  // @param event : WxEvent                                    //
+  // @return : -                                               //
+  //////////////////////////////////////////////////
+  void WxGimmickView::OnCreateDB(wxCommandEvent& event)
+  {
+       //  PACSConnection("");
+       WxDescriptorPanel * DescriptorPan = new WxDescriptorPanel(this, mGimmick->GetHomeDirectory());
+       DescriptorPan->Layout();
+       if ( DescriptorPan->ShowModal() == ID_DSCP_APPLY)
+       {
+               wxBusyCursor busy;
+               std::string file(DescriptorPan->GetDescriptor());
+               if (!file.empty())
+               {
+                       size_t pos = file.find_last_of("\\");
+                       std::string name = file.substr(pos+1);
+                       std::string directory = file.substr(0,pos);
+                       pos = name.find_last_of(".");
+                       name = name.substr(0,pos);
+                       //get directory to store DB
+                       directory +=  "\\" + name + ".sqlite3";
+                       //create createDB
+                       mGimmick->createDB(name, file,directory);
+                       //create TreeHandler
+                       mGimmick->addDB(name, directory);
+                       //create TreeView
+                       CreateSingleTreeView(name);
+               }
+       }
+  }
+
+   //=================================================
+
+   //=================================================
+  BEGIN_EVENT_TABLE(WxGimmickView, wxPanel)
+    EVT_TOOL(TOOL_CREATEDB_ID, WxGimmickView::OnCreateDB)
+    EVT_TOOL(TOOL_ADDFILES_ID, WxGimmickView::OnAddFiles)
+    EVT_TOOL(TOOL_ADDDIR_ID, WxGimmickView::OnAddDir)
+    EVT_TOOL(TOOL_ADDDATABASE_ID, WxGimmickView::OnAddDB)
+    EVT_TOOL(TOOL_REMOVE_ID, WxGimmickView::OnRemove)
+    EVT_TOOL(TOOL_SYNCHRONIZE_ID, WxGimmickView::OnSynchronize)
+    EVT_TOOL(TOOL_SETTINGS_ID, WxGimmickView::OnSettings)
+    EVT_TOOL(TOOL_TOOLS_ID, WxGimmickView::OnTools)
+  END_EVENT_TABLE()
+  //=================================================
+
+} // EO namespace creaImageIO
+
diff --git a/src/creaImageIOWxGimmickView.h b/src/creaImageIOWxGimmickView.h
new file mode 100644 (file)
index 0000000..f676ece
--- /dev/null
@@ -0,0 +1,243 @@
+#ifndef __creaImageIOWxGimmickView_h_INCLUDED__
+#define __creaImageIOWxGimmickView_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+
+#include <creaImageIOGimmickView.h>
+#include <creaImageIOWxViewer.h>
+#include <creaImageIOWxGimmickTools.h>
+#include <creaImageIOListener.h>
+#include <creaWx.h>
+
+#include "wx/progdlg.h"
+
+#include "wx/wx.h"
+#include <wx/splitter.h>
+#include <wx/toolbar.h> 
+#include <wx/tbarbase.h> 
+#include <wx/notebook.h>
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup View
+   */
+  //=====================================================================
+  
+  //=====================================================================
+  /// Concrete derivative of GimmickView which implements a wxWidgets-based view
+
+  class WxGimmickView : public wxPanel, virtual public GimmickView
+  {
+  public:
+    
+    typedef int EventType;
+    
+    /// Ctor
+    WxGimmickView(boost::shared_ptr<Gimmick>, 
+                 wxWindow *parent, 
+                 const wxWindowID id,
+                 const wxPoint& pos, const wxSize& size,
+                 int min_dim = GIMMICK_2D_IMAGE_SELECTION,
+                 int max_dim = GIMMICK_3D_IMAGE_SELECTION,
+                 int number_of_threads = 0);
+    /// Virtual destructor
+    virtual ~WxGimmickView();
+    
+    /// Returns the selected files
+    ///(overloaded from GimmickView)
+    void GetSelectedFiles(std::vector<std::string>& s);
+    
+    /// Returns the selected Images so that they comply with the 
+    /// given parameter(4D) (overloaded from GimmickView)
+    void GetSelectedImages(std::vector<vtkImageData*>& s, int dim);
+    void GetSelectedImagesInVector(std::vector<vtkImageData*>& s, int dim);
+
+    /// Returns the images indicated by the filenames in the vector 
+    /// so that they comply with the given parameter(dim)
+    //(overloaded from GimmickView) 
+    void GetImages(int dim, const std::vector<std::string>& files, 
+                  std::vector<vtkImageData*>& s);
+    
+    /// Callback called when a selection from a TreeView has changed 
+    //(overloaded from GimmickView)
+    void OnSelectionChange(const std::vector<tree::Node*>& s, 
+                          bool isSelection, int selection, bool mProcess);
+    ///Stops the player
+    void StopPlayer(){mViewer->StopPlayer();}
+    ///Adds a file to ignore
+    void AddIgnoreFile(tree::Node* toRemove);
+    ///Resets the default image
+    void ClearSelection();
+       ///Copies selected files
+    void CopyFiles(const std::vector<std::string>& filenames);
+       ///Add selected files to the Database
+    void AddDir(std::string dirName);
+    
+    
+    ///Sends a request to read the currently selected node and the ones that surround it.
+    void ReadImageThreaded(const std::vector<tree::Node*>& sel);
+
+       ///Saves the settings to the file
+       void OnSaveSettingsCallback(const std::string& copyPath,
+         const std::string& dbPath,
+         const std::string& syncEvent,
+         const std::string& syncFreq);
+       
+       ///Changes listener state
+       void OnListenerCallback(const std::string& drive, bool addFiles, bool removeFiles);
+
+       ///Acts upon a drive mount
+       void OnDriveMount(bool mount);
+
+       ///Starts the listening thread on the CD/DVD drive
+       void StartListeningThread();
+
+       ///Stops the listening thread on the CD/DVD drive
+       void StopListeningThread();
+
+       ///Called upon when a field has been edited
+       void OnFieldsEdited(tree::Node* node, const std::string& name, const std::string& key, const std::string& val);
+
+       ///Called upon to return the visible attributes of the current tab
+       void GetVisibleAttributes(std::vector<std::string>& shown,std::vector<std::string>& nShown, int level);
+
+       ///Called when there has been a change in the visible attributes of a tree view
+       void OnAttributesChanged(const std::vector<std::string>& nShown, int level);
+    
+  protected:
+    /// Creates the tool bar
+    void CreateToolBar(); 
+    
+    /// Create the tree view for TreeHandler provided 
+    /// (overloaded from GimmickView)
+    void CreateTreeView( TreeHandler* );
+    
+    
+  private:
+         wxBoxSizer *mbottom_sizer;
+         wxBoxSizer    *msizer;
+    /// Is set to true at the end of constructor 
+    /// (in order to lock callbacks from threaded objects or event 
+    /// before everything is ok)
+    bool mConstructed;
+    /// The ToolBar and the tools
+    wxToolBar*         mToolBar;
+    wxToolBarToolBase* mToolAddFile;
+    wxToolBarToolBase* mToolAddDir;
+    wxToolBarToolBase* mToolRemove;
+    wxToolBarToolBase* mToolAddDatabase;
+    wxToolBarToolBase* mToolHelp;
+       wxToolBarToolBase* mToolSynchronize;
+       wxToolBarToolBase* mToolSettings;
+       wxToolBarToolBase* mToolTools;
+    
+    wxSplitterWindow* mSplitter;
+    wxPanel*          mBottomPanel;
+    wxStaticText *    mText;
+    wxNotebook*       mNotebook;
+    
+    /// The list of icons 
+    wxImageList *    mIcon;
+    void CreateIconList();
+    
+    boost::shared_ptr<Gimmick> mGimmick;
+               
+       Listener* mListener;
+
+    /// Callback for adding files
+    void OnAddFiles(wxCommandEvent& event);
+
+    /// Callback for adding dir
+    void OnAddDir(wxCommandEvent& event);
+
+    /// Callback for removing files
+    void OnRemove(wxCommandEvent& event);
+
+       /// Callback for synchronization
+    void OnSynchronize(wxCommandEvent& event);
+
+       /// Callback for settings edition
+    void OnSettings(wxCommandEvent& event);
+
+       /// Callback for settings edition
+    void OnTools(wxCommandEvent& event);
+
+       /// Callback for Import/Export images
+    void OnImportExport(wxCommandEvent& event);
+
+       // Import Images from an archive
+       void ImportImages();
+
+       //Export Images to an archive
+       void ExportImages();
+
+       ///Creates the settings dialog (the pages inside and the information)
+       void CreateSettingsDialog(wxNotebook* nb, wxDialog* dial);
+    
+    /// Display a message box with the last addition statistics
+    void DisplayAddSummary();
+
+       /// Test a directory to know if contains sub-directory to analyze
+       bool isNeedRecursive(std::string i_name);
+
+       /// Determines number of files potentially to add to database
+       int NumberFilesToAdd(const std::string &dirpath, bool recursive);
+    
+    /// AddProgress Gimmick callback
+    void OnAddProgress( Gimmick::AddProgress& );
+
+#if defined(WIN32)
+    /// Called upon to refresh the viewer once there are no actions to be done
+    void OnInternalIdle();
+#else
+       void UpdateWindowUI(long flags = wxUPDATE_UI_NONE);
+#endif
+       /// callback to add a database
+       void OnAddDB(wxCommandEvent& event);
+    
+       ///Create a DB from an Attributes Descriptor files 
+       void OnCreateDB(wxCommandEvent& event);
+
+       std::string ExtractName(const std::string &i_name);
+
+       ///Edits the fields of a given node
+       void CreateEditFieldsDialog(tree::Node* node, std::vector<std::string> names, std::vector<std::string> keys);
+
+       
+       /// Display all Dicom Tags
+       void DumpTags(const std::string i_filename);
+       /// Export from Storage to Storage
+       void ExportToStorage(const std::vector<std::string> i_filenames);
+    /// Progress dialog
+    wxProgressDialog* mProgressDialog;
+
+    ///The selection's maximum dimension
+    int mSelectionMaxDimension;
+
+    ///The selection's minimum dimension
+    int mSelectionMinDimension;
+
+    ///Image previewer
+    WxViewer* mViewer;
+
+    ///Currently Displayed Node
+    tree::Node* mCurImageItemToShow;
+
+    //Pointer holders for images to be shown
+       std::vector< boost::shared_ptr<ImagePointerHolder> > pointers;
+
+    wxString mCurrentDirectory;
+    
+    DECLARE_EVENT_TABLE()
+      };
+  // EO class WxGimmickView
+  //=====================================================================
+
+} // EO namespace creaImageIO
+
+#endif // USE_WIDGETS
+// EOF
+#endif
diff --git a/src/creaImageIOWxListenerPanel.cpp b/src/creaImageIOWxListenerPanel.cpp
new file mode 100644 (file)
index 0000000..b921276
--- /dev/null
@@ -0,0 +1,95 @@
+#include <creaImageIOWxListenerPanel.h>
+#include <creaImageIOSystem.h>
+
+namespace creaImageIO
+{
+  // CTor
+  WxListenerPanel::WxListenerPanel(wxWindow *parent, wxDialog* dial, WxGimmickView* view, bool stat)
+ :   wxPanel( parent, 
+                 -1, wxDefaultPosition, 
+                 wxDefaultSize,
+                 wxRESIZE_BORDER | 
+             wxSYSTEM_MENU  |
+                 wxCLOSE_BOX |
+                 wxMAXIMIZE_BOX | 
+                 wxMINIMIZE_BOX | 
+                 wxCAPTION  
+              ),       
+                  dialog(dial),
+                  mView(view)
+  {
+    GimmickDebugMessage(1,"WxListener::WxListener"
+                       <<std::endl);
+       state=stat;
+       wxStaticText * cp=new wxStaticText(this,-1,_T(" Drive to monitor: "), wxPoint(5,15));
+       const wxString choices[] = { _T("D:"), 
+               _T("E:"), 
+               _T("F:"), 
+               _T("G:") };
+       drives=new wxComboBox(this, -1,crea::std2wx("E:"),wxPoint(100, 10),wxDefaultSize,4,choices);
+
+       addCheckBox = new wxCheckBox(this, -1, _T("Automatically add images to the database when CD/DVD is mounted?"), wxPoint(5,45) );
+       addCheckBox->SetValue(true);
+       removeCheckBox = new wxCheckBox(this, -1, _T("Automatically remove images from the database when CD/DVD is unmounted?"), wxPoint(5,75) );
+       removeCheckBox->SetValue(true);
+       Connect( addCheckBox->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, (wxObjectEventFunction) &WxListenerPanel::OnAdd );
+       Connect( removeCheckBox->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, (wxObjectEventFunction) &WxListenerPanel::OnRemove );
+       std::string name;
+       if (state){name="Start Monitoring Drive";}
+       else {name="Stop Monitoring Drive";}
+       wxButton *start = new wxButton(this,wxID_ANY,crea::std2wx(name), wxPoint(5,110) );
+       Connect( start->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxListenerPanel::OnChangeThreadState ); 
+
+       wxButton *save = new wxButton(this,wxID_ANY,_T("Save Changes"), wxPoint(130,110) );
+       Connect( save->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxListenerPanel::OnChangeListenState ); 
+  
+
+    //topsizer->Add( mView,1,wxGROW,0);
+
+//    SetSizer( topsizer );     
+    Layout(); 
+  }
+
+  /// Destructor
+  WxListenerPanel::~WxListenerPanel()
+  {
+    GimmickDebugMessage(1,"WxCustomizeConfigPanel::~WxCustomizeConfigPanel"
+                       <<std::endl);
+  }
+
+  void WxListenerPanel::OnAdd(wxCommandEvent& event)
+  {
+               addFiles = addCheckBox->GetValue();
+  }
+
+  void WxListenerPanel::OnRemove(wxCommandEvent& event)
+  {
+               removeFiles = removeCheckBox->GetValue();
+  }
+
+  void WxListenerPanel::OnChangeListenState(wxCommandEvent& event)
+  {
+         mView->OnListenerCallback(crea::wx2std(drives->GetValue()),addFiles, removeFiles);
+         dialog->Destroy();
+  }
+
+  void WxListenerPanel::OnChangeThreadState(wxCommandEvent& event)
+  {
+         if(state)
+         {
+               mView->StartListeningThread();
+         }
+         else
+         {
+               mView->StopListeningThread();
+         }
+         dialog->Destroy();
+  }
+  
+//======================================================================
+  
+//====================================================================== 
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxListenerPanel.h b/src/creaImageIOWxListenerPanel.h
new file mode 100644 (file)
index 0000000..cf66794
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __creaImageIOWxListenerPanel_h_INCLUDED__
+#define __creaImageIOWxListenerPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <creaImageIOWxGimmickView.h>
+
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  class WxListenerPanel : public wxPanel
+  {
+  public:
+    WxListenerPanel();    
+       WxListenerPanel(wxWindow *parent, 
+               wxDialog* dial,
+               WxGimmickView* view,
+               bool stat);
+    
+    ~WxListenerPanel();
+       ///Saves the configuration
+        void OnChangeListenState(wxCommandEvent& event);
+    ///Changes the thread state(start/stop)
+        void OnChangeThreadState(wxCommandEvent& event);
+       ///Changes the state of the add boolean
+        void OnAdd(wxCommandEvent& event);
+    ///Changes the state of the remove boolean
+        void OnRemove(wxCommandEvent& event);
+  
+
+  private :
+       bool addFiles;
+       bool removeFiles;
+       bool state;
+       wxCheckBox* addCheckBox;
+       wxCheckBox* removeCheckBox;
+       wxComboBox* drives;
+       wxDialog* dialog;
+       WxGimmickView* mView;
+
+
+  }; // class WxListener
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
diff --git a/src/creaImageIOWxPACSConnectionPanel.cpp b/src/creaImageIOWxPACSConnectionPanel.cpp
new file mode 100644 (file)
index 0000000..36b22d4
--- /dev/null
@@ -0,0 +1,61 @@
+#include <creaImageIOWxPACSConnectionPanel.h>
+#include <creaImageIOPACSConnection.h>
+#include <creaImageIOSystem.h>
+
+namespace creaImageIO
+{
+  // CTor
+  WxPACSConnectionPanel::WxPACSConnectionPanel(wxWindow *parent, wxDialog* dial, WxGimmickView* view)
+ :   wxPanel( parent, 
+                 -1, wxDefaultPosition, 
+                 wxDefaultSize,
+                 wxRESIZE_BORDER | 
+             wxSYSTEM_MENU  |
+                 wxCLOSE_BOX |
+                 wxMAXIMIZE_BOX | 
+                 wxMINIMIZE_BOX | 
+                 wxCAPTION  
+              ),       
+                  dialog(dial),
+                  mView(view)
+  {
+    GimmickDebugMessage(1,"WxPACSConnectionPanel::WxPACSConnectionPanel"
+                       <<std::endl);
+       wxStaticText * dicId=new wxStaticText(this,-1,_T(" DICOM Identification: "), wxPoint(5,5));
+       wxStaticText * aet=new wxStaticText(this,-1,_T(" AETitle: "), wxPoint(5,25));
+       aeTitle=new wxTextCtrl(this, wxID_ANY, _T("MyAeTitle"), wxPoint(75,25), wxSize(220,20));
+
+       wxStaticText * pn=new wxStaticText(this,-1,_T(" Port Number: "), wxPoint(5,53));
+       pNumber=new wxTextCtrl(this, wxID_ANY, _T("3306"), wxPoint(75,50), wxSize(220,20));
+       wxStaticText * adv1=new wxStaticText(this,-1,_T(" (1 - 131072) "), wxPoint(300,53));
+
+       wxStaticText * ad=new wxStaticText(this,-1,_T(" Address: "), wxPoint(5,80));
+       address=new wxTextCtrl(this, wxID_ANY, _T("localhost"), wxPoint(75,75), wxSize(220,20));
+       
+       wxButton *query = new wxButton(this,wxID_ANY,_T("Query PACS Server"), wxPoint(5,110) );
+       Connect( query->GetId(), wxEVT_COMMAND_BUTTON_CLICKED , (wxObjectEventFunction) &WxPACSConnectionPanel::OnQueryPACS ); 
+   
+    Layout(); 
+  }
+
+  /// Destructor
+  WxPACSConnectionPanel::~WxPACSConnectionPanel()
+  {
+    GimmickDebugMessage(1,"WxPACSConnectionPanel::~WxPACSConnectionPanel"
+                       <<std::endl);
+  }
+
+  void WxPACSConnectionPanel::OnQueryPACS(wxCommandEvent& event)
+  {
+         PACSConnection* pc=new PACSConnection(crea::wx2std(aeTitle->GetValue()));
+         //mView->OnListenerCallback(crea::wx2std(drives->GetValue()),addFiles, removeFiles);
+         //dialog->Destroy();
+  }
+  
+//======================================================================
+  
+//====================================================================== 
+
+} // EO namespace creaImageIO
+
+
diff --git a/src/creaImageIOWxPACSConnectionPanel.h b/src/creaImageIOWxPACSConnectionPanel.h
new file mode 100644 (file)
index 0000000..6904a28
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __creaImageIOWxPACSConnectionPanel_h_INCLUDED__
+#define __creaImageIOWxPACSConnectionPanel_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+#include <creaWx.h>
+#include <creaImageIOWxGimmickView.h>
+
+
+namespace creaImageIO
+{
+  /**
+   * \ingroup GUI
+   */
+  //=====================================================================
+ //=====================================================================
+  class WxPACSConnectionPanel : public wxPanel
+  {
+  public:
+    WxPACSConnectionPanel();    
+       WxPACSConnectionPanel(wxWindow *parent, 
+               wxDialog* dial,
+               WxGimmickView* view);
+    
+    ~WxPACSConnectionPanel();
+       ///Queries the PACS
+        void OnQueryPACS(wxCommandEvent& event);  
+
+  private :
+       wxTextCtrl* aeTitle;
+       wxTextCtrl* pNumber;
+       wxTextCtrl*     address;
+       wxDialog* dialog;
+       WxGimmickView* mView;
+
+
+  }; // class WxPACSConnectionPanel
+  //=====================================================================
+
+  
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif
+
+
diff --git a/src/creaImageIOWxTreeView.cpp b/src/creaImageIOWxTreeView.cpp
new file mode 100644 (file)
index 0000000..3b30d4c
--- /dev/null
@@ -0,0 +1,1385 @@
+#include <creaImageIOWxTreeView.h>
+#include <creaImageIOGimmickView.h>
+#include <creaImageIOSystem.h>
+#include <wx/splitter.h>
+#include <wx/gdicmn.h>
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <creaImageIOGimmick.h>
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+//=====================================================================
+namespace creaImageIO
+{
+
+  //=====================================================================
+}
+//=====================================================================
+
+//=====================================================================
+///Comparing function for ordering algorithm. Takes parameters as strings.
+int wxCALLBACK CompareFunctionStrings(long item1, long item2, long sortData)
+{      
+  creaImageIO::ItemData* data1 = (creaImageIO::ItemData*)item1;
+  creaImageIO::ItemData* data2 = (creaImageIO::ItemData*)item2;
+
+  const std::string& s1(*(data1->attr));
+  const std::string& s2(*(data2->attr));
+  if(sortData==1)
+    {
+      // inverse the order
+      if (s1 < s2)
+       return 1;
+      if (s1 > s2)
+       return -1;
+      
+      return 0;
+    }
+  else
+    {
+      if (s1 < s2)
+       return -1;
+      if (s1 > s2)
+       return 1;
+      
+      return 0;
+      
+    }
+}
+//=====================================================================
+
+//=====================================================================
+///Comparing function for ordering algorithm. Takes parameters as ints.
+int wxCALLBACK CompareFunctionInts(long item1, long item2, long sortData)
+{      
+  creaImageIO::ItemData* data1 = (creaImageIO::ItemData*)item1;
+  creaImageIO::ItemData* data2 = (creaImageIO::ItemData*)item2;
+
+  const std::string& s1(*(data1->attr));
+  const std::string& s2(*(data2->attr));
+
+  int val1=atoi(s1.c_str());
+  int val2=atoi(s2.c_str());
+
+  if(sortData==1)
+    {
+      // inverse the order
+      if (val1 < val2)
+       return 1;
+      if (val1 > val2)
+       return -1;
+      
+      return 0;
+    }
+  else
+    {
+      if (val1 < val2)
+       return -1;
+      if (val1 > val2)
+       return 1;
+
+      return 0;
+      
+    }
+  
+}
+
+//=====================================================================
+
+
+//=====================================================================
+namespace creaImageIO
+{
+  //=====================================================================
+  // CTor
+  WxTreeView::WxTreeView(TreeHandler* handler,
+                        GimmickView* gimmick,
+                        wxWindow* parent,
+                        const wxWindowID id)
+    : wxPanel(parent,id),
+      TreeView(handler, gimmick)
+  {
+    GimmickDebugMessage(1,"WxTreeView::WxTreeView"
+                       <<std::endl);
+
+    
+    // Split part below toolbar into notebook for views and panel
+    // for preview, messages...
+    // TO DO : Splitter
+    //    mSplitter = new wxSplitterWindow( this , -1);
+
+    // Global sizer
+    msizer = new wxBoxSizer(wxHORIZONTAL);
+    
+    int ctrl_style = wxLC_REPORT | wxLC_VRULES;
+    int col_style = wxLIST_FORMAT_LEFT;
+
+    // Creating the ListCtrl for the levels > 0 (not for Root level)
+    for (int i = 0;
+        i < handler->GetTree().GetNumberOfLevels() -1;
+        ++i)
+      {
+       GimmickDebugMessage(5,"Creating view for level "<<i
+                           <<std::endl);
+       LevelType level;
+       level.SelectedUpToDate = true;
+       level.SortColumn = 0;
+
+       // If the first level : parent = this
+       wxWindow* sparent = this;
+       // else parent = last splitter
+       if (i>0) 
+               sparent = mLevelList[i-1].wxSplitter;
+
+       level.wxSplitter = new wxSplitterWindow( sparent , -1);
+       if(i!=0)
+       {
+       level.wxSplitter->Show(false);
+       }
+       //          level.wxSplitter->SetMinimumPaneSize(100);
+       
+       wxListCtrl* ctrl = new wxListCtrl(level.wxSplitter,
+                                         i,
+                                         wxDefaultPosition, 
+                                         wxDefaultSize,
+                                         ctrl_style);
+       level.wxCtrl = ctrl;
+       level.wxSplitter->Initialize(ctrl);
+   
+       // Create the columns : one for each attribute of the level
+       int col = 0;
+       std::string title;
+
+       tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+       for (a  = handler->GetTree().GetAttributeDescriptorList(i+1).begin();
+            a != handler->GetTree().GetAttributeDescriptorList(i+1).end();
+            ++a)
+
+{
+       
+           GimmickDebugMessage(5,"Creating column "<<col<<" : "
+                               <<a->GetName()
+                               <<std::endl);
+           
+           if(a->GetFlags()!=creaImageIO::tree::AttributeDescriptor::PRIVATE)
+             {
+               
+               if(a->GetName()=="UNKNOWN")
+                 {
+                   title = "#";
+                   title += handler->GetTree().GetLevelDescriptor(i+1).GetName();
+                   if (title[title.size()-1]!='s')
+                     title += "s";
+                   
+                 }
+               else
+                 {
+                   title=a->GetName();
+                 }
+                 std::string temp = a->GetKey();
+                 if (temp.compare("ID") != 0)
+                 {
+               
+               ctrl->InsertColumn(col, 
+                                  crea::std2wx(title),
+                                  col_style);
+               col++;
+                 }
+               level.key.push_back(a->GetKey());
+             }
+               
+         }
+         
+       mLevelList.push_back(level);
+      }
+    
+#if wxUSE_MENUS
+
+        // Column Menu
+    menu =new wxMenu;
+       wxMenuItem* m1=menu->Append(wxID_ANY, _T("&Sort ascending"));
+       wxMenuItem* m2=menu->Append(wxID_ANY, _T("&Sort descending"));
+       wxMenuItem* m3=menu->Append(wxID_ANY, _T("&Filter"));
+       mAscendingID=m1->GetId();
+       mDescendingID=m2->GetId();
+       mFilterID=m3->GetId();
+       Connect( mAscendingID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnPopupSort) );
+       Connect( mDescendingID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnPopupSort) );
+       Connect( mFilterID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnPopupFilter) );
+
+
+       ////SubMenuItem EXPORT
+       subExportMenu = new wxMenu;
+       wxMenuItem *subExp1 = subExportMenu->Append(wxID_ANY, _T("&Export to Storage"));
+       Connect( subExp1->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnExportToStorage) );
+
+       //ItemMenu
+       menuItem =new wxMenu;
+
+
+       wxMenuItem* m2Item=menuItem->Append(wxID_ANY, _T("&Local Copy"));
+       wxMenuItem* m3Item=menuItem->Append(wxID_ANY, _T("&Edit Fields"));
+       wxMenuItem* m4Item=menuItem->Append(wxID_ANY, _T("&Display Dicom Tags"));
+       menuItem->AppendSubMenu(subExportMenu, wxT("&Export"));
+
+#if defined(USE_GDCM_ANOM)
+       wxMenuItem* m1Item=menuItem->Append(wxID_ANY, _T("&Anonymize"));
+       mAnonymizingID=m1Item->GetId();
+       Connect( mAnonymizingID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnAnonymize) );
+#endif
+       mLocalCopyID=m2Item->GetId();
+       mEditFieldID=m3Item->GetId();
+       mDumpID=m4Item->GetId();
+       
+       
+       Connect( mLocalCopyID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnLocalCopy) );
+       Connect( mEditFieldID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnEditField) );
+       Connect( mDumpID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnDumpTags) );
+       
+
+       
+#endif // wxUSE_MENUS
+       /// Initialize the first level splitter
+         
+       msizer->Add( mLevelList[0].wxSplitter ,1, wxGROW  ,0);
+       //      mColumnSelected=1;
+       mLastSelected=0;
+       mLastLevel=0;
+       //      mDirection=true;
+
+       mIgnoreSelectedChanged = false;
+
+       //CreateColorPalette();
+    UpdateLevel(1);
+
+    SetSizer( msizer );     
+    SetAutoLayout(true);
+    Layout();
+
+  }
+  //=====================================================================
+
+  //=====================================================================
+  /// Destructor
+  WxTreeView::~WxTreeView()
+  {
+    GimmickDebugMessage(1,"WxTreeView::~WxTreeView"
+                       <<std::endl);
+       delete menu;
+       delete menuItem;
+
+  }
+  //=====================================================================
+  
+  
+  
+  //=====================================================================
+  const std::vector<tree::Node*>& WxTreeView::GetSelected(int level)
+  {
+         std::vector<tree::Node*>& sel = mLevelList[0].Selected;
+    //  if (GetSelectedUpToDate(level)) 
+    int l = level - 1;
+    // the selection of upper level
+       if(mLevelList.size() == level -1)
+                sel = mLevelList.back().Selected;
+       else
+                 sel=  mLevelList[l].Selected;
+       if (sel.size() > 0)
+       {
+               sel.clear();
+       }
+         if (level == 1) 
+      {
+       sel.push_back(GetTreeHandler()->GetTree().GetTree());
+      }
+         else if (level < mLevelList.size()+2 ) 
+    {
+               long item = -1;
+               for ( ;; )
+               {
+                       item = GetCtrl(l-1)->GetNextItem(item,
+                                                                                wxLIST_NEXT_ALL,
+                                                                                wxLIST_STATE_SELECTED);
+                       if ( item == -1 )
+                               break;
+                       long adr = GetCtrl(l-1)->GetItemData(item);
+                       tree::Node* n = ((ItemData*)adr)->node;
+                       if(mLastSelected==item)
+                       {
+                               std::vector<tree::Node*>::iterator it;
+                               it = sel.begin();
+                               it = sel.insert ( it , n );
+                       }
+                       else
+                       {
+                               
+                               sel.push_back(n);
+                       }                       
+                       
+               }
+               /*int n = GetCtrl(l-1)->GetItemCount();
+               for (int i = 0; i<n; i++)
+               {
+                       std::cout<<GetCtrl(l-1)->GetItemState(i,wxLIST_STATE_SELECTED)<<std::endl;
+                       if ( GetCtrl(l-1)->GetItemState(i,wxLIST_STATE_SELECTED))
+                       {
+                               long adr = GetCtrl(l-1)->GetItemData(i);
+                               tree::Node* n = ((ItemData*)adr)->node;
+                               if(mLastSelected==i)
+                               {
+                                       std::vector<tree::Node*>::iterator it;
+                                       it = sel.begin();
+                                       it = sel.insert ( it , n );
+                               }
+                               else
+                               {
+                                       
+                                       sel.push_back(n);
+                               }
+                       }
+             }*/
+         }
+       else
+       {
+               // NOTHING
+       }   
+        
+    //    return mLevelList[level-1].Selected;
+    return sel;
+  }
+
+  //=====================================================================
+  
+  //=====================================================================
+  ///Removes selected nodes on last selected level
+   // NOT SPECIFIC 
+  void WxTreeView::RemoveSelected(std::string &i_save)
+  {
+        bool erase=false;
+        
+        unsigned int tempLevel = mLastLevel;
+    mLastLevel+=1;
+    const std::vector<tree::Node*>& sel=GetSelected(mLastLevel+1);
+       // if no selection, no remove action.
+    if(sel.size() != 0)
+       {
+       
+           std::stringstream out;
+           std::string levelName=GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName();
+           out<<"Delete ";
+           out<<sel.size();
+           if(sel.size()>1&&levelName.at(levelName.size()-1)!='s')
+             {
+               out<<" "<<levelName;
+               out<<"s?";
+             }
+           else
+             {
+               out<<" "<<GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName()<<"?";
+             }
+           if (wxMessageBox(crea::std2wx(out.str()),
+                            _T("Remove Files"),
+                            wxYES_NO,this ) == wxYES)
+             {
+               erase = true;
+             }
+           if(erase)
+                 {
+            GetGimmickView()->modifyValidationSignal(false);
+                   bool needRefresh=false;
+                   std::vector<tree::Node*>::const_iterator i;
+                   for (i=sel.begin(); i!=sel.end(); ++i)
+                     {
+                       GimmickMessage(1,
+                                      "deleting '"
+                                      <<(*i)->GetLabel()
+                                      <<"'"<<mLastLevel
+                                      <<std::endl);
+                       if((*i)->GetParent()->GetNumberOfChildren()<2)
+                         {
+                           needRefresh=true;
+                         }
+                         //tree::Node* n = new (tree::Node*)(*i);
+                         GetTreeHandler()->LoadChildren((*i),4);
+                         GetGimmickView()->AddIgnoreFile(*i);
+                         GetTreeHandler()->Remove(*i);
+                     }
+                   
+                   if(needRefresh && mLastLevel>1)
+                     {
+                       UpdateLevel(mLastLevel-2);
+                     }
+                   else if(mLastLevel>1)
+                     {
+                       UpdateLevel(mLastLevel-1);
+                     }
+                   else
+                     {
+                       UpdateLevel(mLastLevel);
+                     }
+                 }
+       }
+       else
+       {
+               // no need to incremente level
+               mLastLevel = tempLevel;
+       }
+    
+       if (erase && mLastLevel == 1 && i_save == "0")
+       {
+       
+               RemoveAlertDlg *dial = new RemoveAlertDlg(this,  crea::std2wx("Remove files"), wxSize(370,100));
+               //dial->ShowModal();
+               if (dial->ShowModal() == wxID_OK)
+               {
+                       i_save = dial->isChecked() == false? "0" : "1";
+               }
+               
+       }
+  }
+  
+  
+  //=====================================================================
+  /// Updates a level of the view (adds or removes children, etc.)
+  void WxTreeView::UpdateLevel( int level )
+  {
+    GimmickDebugMessage(1,
+                       GetTreeHandler()->GetTree().GetLabel()
+                       <<"WxTreeView::UpdateLevel(level "
+                       <<level
+                       <<")"
+                       <<std::endl);
+    
+    wxBusyCursor busy;
+    RecursiveUpdateLevel(level);
+    int i;
+    for (i=0; i<level-1; i++)
+      {
+       if (!GetSplitter(i)->IsSplit()) 
+         GetSplitter(i)->SplitVertically(  GetCtrl(i), GetSplitter(i+1),
+                                           100 );
+      }
+    if (GetSplitter(i)->IsSplit()) GetSplitter(i)->Unsplit();    
+    
+  }
+  //=====================================================================
+  
+  //=====================================================================
+  /// Recursive method called upon by UpdateLevel to refresh all windows
+  void WxTreeView::RecursiveUpdateLevel( int level )
+  {
+    GimmickDebugMessage(1,
+                       GetTreeHandler()->GetTree().GetLabel()
+                       <<"WxTreeView::RecursiveUpdateLevel(level "
+                       <<level
+                       <<")"<<std::endl);
+    
+    
+    const std::vector<tree::Node*>& sel(GetSelected(level));
+    
+    int l = level - 1;
+    
+    // to speed up inserting we hide the control temporarily
+    GetCtrl(l)->Hide();
+    GetCtrl(l)->DeleteAllItems();
+    
+    std::vector<tree::Node*>::const_iterator i;
+    
+    for (i=sel.begin(); i!=sel.end(); ++i)
+      {
+       GimmickDebugMessage(1,
+                           "adding children of '"
+                           <<(*i)->GetLabel()
+                           <<"'"
+                           <<std::endl);
+       int _id=0;
+       
+       //Adds items and sets their attributes 
+       
+       GetTreeHandler()->LoadChildren(*i,1);
+       tree::Node::ChildrenListType::reverse_iterator j;
+       for (j = (*i)->GetChildrenList().rbegin(); 
+            j!= (*i)->GetChildrenList().rend(); 
+            ++j)
+         {
+           GimmickDebugMessage(1,
+                               "adding children "
+                               <<(*j)->GetLabel()
+                               <<"'"
+                               <<std::endl);
+           
+           wxListItem item;
+           item.SetMask(wxLIST_MASK_STATE | 
+                        wxLIST_MASK_TEXT |
+                        //                      wxLIST_MASK_IMAGE |
+                        wxLIST_MASK_DATA |
+                        //                      wxLIST_MASK_WIDTH |
+                        wxLIST_MASK_FORMAT
+                        );
+           
+               ItemData* data = new ItemData();
+           data->node = *j;
+           data->id = _id;
+               
+           item.SetId(_id);
+           item.SetData(data);
+
+           _id++;
+           GetCtrl(l)->InsertItem(item);
+           
+           //Setting attributes
+           for (int k=0; k<GetCtrl(l)->GetColumnCount(); ++k)                          
+             {
+               std::string val;
+               //  Temporary correction : it works but no explanation about the problem FCY
+               
+               if(k==0 && level <3)
+               {
+                 val = (*j)->GetAttribute("NumberOfChildren");
+               }
+               else
+                 val = (*j)->GetAttribute(mLevelList[l].key[k]);
+               if(((*j)->GetAttributeDescriptor(mLevelList[l].key[k])).isDateEntry()) // Date
+                 {
+                   //                                    std::cout << "["<<val<< "]" << std::endl;
+                   std::string valtmp(val);
+                   try
+                     {
+                       boost::gregorian::date d1(boost::gregorian::from_undelimited_string(val));                                 
+                       val = to_iso_extended_string(d1);
+                     }
+                   catch (...)
+                     {
+                       val =  valtmp;
+                     }
+                   //                                    std::cout << "["<<val<< "]" << std::endl;     
+                 }
+               else if(((*j)->GetAttributeDescriptor(mLevelList[l].key[k])).isTimeEntry()) // Time
+                 {
+                   if ((val.size()>6) && 
+                       (val != "" || val != " "))
+                     val = val.substr(0,2) + " : " 
+                       + val.substr(2,2) + " : " 
+                       + val.substr(4,2);
+                 }
+               else
+                 {
+                   if (val.size()==0) val = "?";
+                 }
+               if (val.size()==0) val = "X";
+               item.SetText( crea::std2wx(val));
+               item.SetColumn(k);
+                 
+                 GetCtrl(l)->SetItem(item);
+                 }
+               item.Clear();
+           
+         }
+      }
+    
+    SortLevel(l);
+    GetCtrl(l)->Show();
+  }
+  //=====================================================================
+  
+  
+  //================================================================
+  void WxTreeView::OnItemDeSelected(wxListEvent& event)
+  { 
+    GimmickDebugMessage(1,
+                       GetTreeHandler()->GetTree().GetLabel()
+                       <<" WxTreeView::OnItemDeselected"<<std::endl);
+    // retrieve the level
+    wxObject* obj = event.GetEventObject();   
+    unsigned int level = 0;
+    for (level = 0; level<mLevelList.size(); ++level)
+      {
+       if ( GetCtrl(level) == obj ) break;
+      } 
+    SetSelectedUpToDate(level,false);
+    // to allow a first selection in images TreeView
+    if (level==mLevelList.size()-1) 
+      OnItemSelected(event);
+  }
+  //================================================================
+  
+  //================================================================
+  void WxTreeView::OnItemSelected(wxListEvent& event)
+  { 
+         
+    GimmickDebugMessage(1,
+                       GetTreeHandler()->GetTree().GetLabel()
+                       <<" WxTreeView::OnItemSelected"<<std::endl);
+
+    if (mIgnoreSelectedChanged) 
+      {
+       GimmickDebugMessage(1,
+                           " mIgnoreSelectedChanged true: returning"
+                           <<std::endl);
+       return;
+      }
+    
+
+    
+    wxListItem info;
+    info.m_itemId = event.m_itemIndex;
+    mLastSelected = event.m_itemIndex;
+    // retrieve the level
+    wxObject* obj = event.GetEventObject();   
+    unsigned int level = 0;
+    for (level = 0; level<mLevelList.size(); ++level)
+      {
+       if ( GetCtrl(level) == obj ) break;
+      }
+       mLastLevel=level;
+    GimmickDebugMessage(1,
+                       " Level "<<level+1
+                       <<std::endl);
+    
+    // Update the children level (if selection not at last level)
+    if (level<mLevelList.size()-1) 
+      {
+               
+       UpdateLevel( level + 2 ); 
+       // Reset the viewer setting the default image
+       GetGimmickView()->ClearSelection();
+      }
+    // Select all images if the selection is at series level
+    if (level==mLevelList.size()-2) 
+               SelectAll(level+1);
+    // Validate selected images if the selection is at image level
+    if (level==(mLevelList.size()-1)) //&&mProcess) 
+      {
+       if(event.GetEventType()==wxEVT_COMMAND_LIST_ITEM_SELECTED)
+         {
+                 ValidateSelectedImages (true);
+         }
+       else
+         {
+                 ValidateSelectedImages (false);
+         }
+      }
+    
+  }
+  //================================================================
+
+  //================================================================
+  void WxTreeView::SelectAll(int level)
+  {
+    long item = -1;
+    //    int level=mLevelList.size()-1;
+    for ( ;; )
+      {
+       item = GetCtrl(level)->GetNextItem(item,
+                                          wxLIST_NEXT_ALL);
+        if ( item == -1 )
+         break;
+       
+       if(item==(GetCtrl(level)->GetItemCount()-1))
+         {
+           mIgnoreSelectedChanged = false;//mProcess=true;
+         }
+       else
+         {
+           mIgnoreSelectedChanged = true;//    mProcess=false;
+         }
+       GetCtrl(level)->SetItemState(item,wxLIST_STATE_SELECTED, wxLIST_MASK_STATE 
+                                    | wxLIST_MASK_TEXT |wxLIST_MASK_IMAGE | wxLIST_MASK_DATA | wxLIST_MASK_WIDTH | wxLIST_MASK_FORMAT);
+      }
+  }
+
+  //================================================================
+  //================================================================
+
+  void WxTreeView::OnColClick(wxListEvent& event)
+  { 
+    mColumnSelected = event.m_col;
+    wxPoint clientpt;
+    clientpt.x = wxGetMousePosition().x - this->GetScreenPosition().x;
+    clientpt.y = wxGetMousePosition().y - this->GetScreenPosition().y;
+    senderCtrl = event.GetEventObject(); 
+    unsigned int level = 0;
+    for (level = 0; level<mLevelList.size(); ++level)
+      {
+       if ( GetCtrl(level) == senderCtrl ) break;
+      }
+    PopupMenu(menu, clientpt);
+    
+  }
+
+   //================================================================
+  //================================================================
+
+  void WxTreeView::OnItemMenu(wxListEvent &event)
+  {
+        wxPoint clientpt;
+    clientpt.x = wxGetMousePosition().x - this->GetScreenPosition().x;
+    clientpt.y = wxGetMousePosition().y - this->GetScreenPosition().y;
+    senderCtrl = event.GetEventObject();
+    unsigned int level = 0;
+    for (level = 0; level<mLevelList.size(); ++level)
+      {
+               if ( GetCtrl(level) == senderCtrl ) break;
+      }
+         long* ptr=0;
+         int flag;
+         mLastRightLevel=level;
+         mLastRightSelected=GetCtrl(level)->HitTest(wxPoint(0,clientpt.y-8),flag,ptr);
+    PopupMenu(menuItem, clientpt);
+    
+  }
+  
+  //================================================================
+  //================================================================
+
+  void WxTreeView::OnPopupFilter(wxCommandEvent& event)
+  {
+    wxBusyCursor busy;
+    GimmickDebugMessage(7,
+                       "WxTreeView::OnEndLabelEdit" 
+                       <<std::endl);
+    unsigned int level = 0;
+    for (level = 0; level<mLevelList.size(); ++level)
+      {
+       if ( GetCtrl(level) == senderCtrl ) break;
+      }
+    std::string filter = crea::wx2std(wxGetTextFromUser(_T("Enter the filter to apply"), _T("Filter On Column")));
+    
+    std::string att;
+    
+    long it = -1;
+    UpdateLevel(level+1);
+    
+    std::vector<long> items;
+    bool in=false;
+    int del=0;
+    for ( ;; )
+      {
+       it = GetCtrl(level)->GetNextItem(it,
+                                        wxLIST_NEXT_ALL);
+       if ( it == -1 )
+         break;
+       
+       long adr = GetCtrl(level)->GetItemData(it);
+       tree::Node* nod = ((ItemData*)adr)->node;
+       att=(*nod).GetAttribute(mLevelList[level].key[mColumnSelected]);
+       
+       
+       if(att.find(filter)>900)
+         {
+           
+           if(!in)
+             {
+               in=true;
+             }
+           else
+             {
+               del+=1;
+             }
+           
+           items.push_back(it-del);
+         }
+       
+      }
+    std::vector<long>::iterator iter;
+    for(iter=items.begin();iter!=items.end();++iter)
+      {
+       GetCtrl(level)->DeleteItem(*iter);
+      }
+    GetGimmickView()->ClearSelection();
+  }
+  //================================================================
+  
+  //================================================================
+  void WxTreeView::OnPopupSort(wxCommandEvent& event)
+  {
+    wxBusyCursor busy;
+    unsigned int level = 0;
+    for (level = 0; level<mLevelList.size(); ++level)
+      {
+       if ( GetCtrl(level) == senderCtrl ) break;
+      }
+    mLevelList[level].SortColumn = mColumnSelected;
+
+    if(event.GetId()==mAscendingID)
+      {
+       mLevelList[level].SortAscending = true;
+      }
+    else if(event.GetId()==mDescendingID)
+      {
+       mLevelList[level].SortAscending = false;
+      }
+         
+    SortLevel(level);
+  }
+  //================================================================
+
+  void WxTreeView::OnAnonymizer(wxCommandEvent &event)
+  {
+          wxBusyCursor busy;
+          std::vector<std::string> filesname;
+          std::vector<tree::Node*> nodes;
+//        nodes.push_back(((ItemData*)GetCtrl(mLastRightLevel)->GetItemData(mLastRightSelected))->node);
+          if(nodes.size() != 0)
+          {
+                  GetFilenamesAsString(nodes,filesname);
+               //   GetGimmickView()->Anonymize(filesname,0);
+          }
+       
+  }
+
+  //================================================================
+  void WxTreeView::OnLocalCopy(wxCommandEvent& event)
+  {
+    wxBusyCursor busy;
+    
+       unsigned int tempLevel = mLastLevel;
+    mLastLevel+=1;
+    const std::vector<tree::Node*>& sel=GetSelected(mLastLevel+1);
+       
+    if(sel.size() != 0)
+       {
+           bool copy=false;
+           std::stringstream out;
+           std::string levelName=GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName();
+           out<<"Copy ";
+           out<<sel.size();
+           if(sel.size()>1&&levelName.at(levelName.size()-1)!='s')
+             {
+               out<<" "<<levelName;
+               out<<"s to .gimmick?";
+             }
+           else
+             {
+               out<<" "<<GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName()<<" to .gimmick?";
+             }
+           if (wxMessageBox(crea::std2wx(out.str()),
+                            _T("Remove Files"),
+                            wxYES_NO,this ) == wxYES)
+             {
+               copy = true;
+             }
+           if(copy)
+                 {
+                       std::vector<std::string> s;
+                       GetFilenamesAsString(sel,s);
+            GetGimmickView()->CopyFiles(s);
+                 }
+       }
+       else
+       {
+               mLastLevel = tempLevel;
+       }
+    
+    
+  }
+  //================================================================
+
+   //================================================================
+  void WxTreeView::OnEditField(wxCommandEvent& event)
+  {
+       if(mLastRightSelected!=-1)
+       {
+    tree::Node* node=((ItemData*)GetCtrl(mLastRightLevel)->GetItemData(mLastRightSelected))->node;
+       tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+       std::vector<std::string> names;
+       std::vector<std::string> keys;
+       for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).begin();
+            a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).end();
+            ++a)
+       {
+               if(a->GetFlags()==creaImageIO::tree::AttributeDescriptor::EDITABLE)
+           {
+                       names.push_back(a->GetName());
+                       keys.push_back(a->GetKey());
+               }
+       }
+       GetGimmickView()->CreateEditFieldsDialog(node,names,keys);
+       }
+  }
+
+  //================================================================
+
+  //================================================================
+
+  void WxTreeView::OnExportToStorage(wxCommandEvent &event)
+  {
+       std::vector<std::string> filesname;
+       std::vector<tree::Node*> nodes;
+       nodes.push_back(((ItemData*)GetCtrl(mLastRightLevel)->GetItemData(mLastRightSelected))->node);
+       GetFilenamesAsString(nodes,filesname);
+       GetGimmickView()->ExportToStorage(filesname);
+  }
+
+  //================================================================
+
+  //================================================================
+
+  void WxTreeView::OnDumpTags(wxCommandEvent &event)
+  {
+         if(mLastRightSelected!=-1)
+       {
+               tree::Node* node=((ItemData*)GetCtrl(mLastRightLevel)->GetItemData(mLastRightSelected))->node;
+               tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+               std::vector<std::string> names;
+               std::vector<std::string> keys;
+               for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).begin();
+                        a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).end();
+                        ++a)
+                       {
+                               if(a->GetKey()=="FullFileName")
+                               {
+                                       GetGimmickView()->DumpTags(node->GetAttribute("FullFileName"));
+                                       return;
+                               }
+                       }
+         }
+  }
+  
+
+  //================================================================
+
+  //================================================================
+  void WxTreeView::SortLevel(int level)
+  {      
+    GimmickDebugMessage(1,
+                       "WxTreeView::SortLevel(" 
+                       <<level<<")"
+                       <<std::endl);  
+    //Obtain the column name and the level that needs to be organized
+    
+    //    int l = level - 1;
+    //Sets the data for the items to be sorted
+    //    std::string att;
+    unsigned int ty=0;
+    int nbselected = 0;
+    int n = GetCtrl(level)->GetItemCount();
+    for (int i = 0; i < n; i++)
+      {
+       
+       //Gets current item data
+       ItemData* data = (ItemData*)GetCtrl(level)->GetItemData(i);
+       
+       //Extracts the node and the type of attribute   
+       tree::Node* nod = data->node;
+       if(i==0)
+         {
+           (*nod).GetAttributeDescriptor
+             (mLevelList[level].key[mLevelList[level].SortColumn])
+             .DecodeType( ty );
+         }
+       //Obtains the organizing attribute
+       data->attr = & (*nod).GetAttribute
+         (mLevelList[level].key[mLevelList[level].SortColumn]);
+       //Selected ?
+       data->selected = false;
+       if (GetCtrl(level)->GetItemState(i,wxLIST_STATE_SELECTED)>0)
+         {
+           data->selected = true;
+           nbselected++;
+         }
+
+      }        
+    GimmickDebugMessage(1,
+                       "WxTreeView::OnSort : " 
+                       <<nbselected<<" selected before sorting"
+                       <<std::endl);  
+
+    mIgnoreSelectedChanged = true; 
+    // 
+    if (mLevelList[level].SortAscending)
+      {
+       
+       if(ty==1)
+         {
+           GetCtrl(level)->SortItems(CompareFunctionInts, 0);
+         }
+       else
+         {
+           GetCtrl(level)->SortItems(CompareFunctionStrings, 0);
+         }
+       
+      }
+    else
+      {
+       if(ty==1)
+         {
+           GetCtrl(level)->SortItems(CompareFunctionInts, 1);
+         }
+       else
+         {
+           GetCtrl(level)->SortItems(CompareFunctionStrings, 1);
+         }
+      }
+
+    // Reselects the unselected 
+    n = GetCtrl(level)->GetItemCount();
+    int after = 0;
+    for (int i = 0; i < n; i++)
+      {
+       
+       //Gets current item data
+       ItemData* data = (ItemData*)GetCtrl(level)->GetItemData(i);
+  
+       //  long item = -1;
+       //    for ( ;; )
+       //      {
+       //      item = GetCtrl(level)->GetNextItem(item,wxLIST_NEXT_ALL);
+       //      if ( item == -1 ) break;
+       //Gets current item data
+       //      ItemData* data = (ItemData*)GetCtrl(level)->GetItemData(item);
+       // was selected ?
+       
+       if (data->selected)
+         {
+           nbselected--;
+           if (nbselected==0)
+             {
+               // if it is the last one we must process the selection
+               mIgnoreSelectedChanged = false;
+             }
+           GetCtrl(level)->SetItemState(i,
+                                        wxLIST_STATE_SELECTED, 
+                                        wxLIST_MASK_STATE 
+                                        | wxLIST_MASK_TEXT 
+                                        | wxLIST_MASK_IMAGE 
+                                        | wxLIST_MASK_DATA 
+                                        | wxLIST_MASK_WIDTH 
+                                        | wxLIST_MASK_FORMAT);   
+         }
+       if (GetCtrl(level)->GetItemState(i,wxLIST_STATE_SELECTED)>0)
+         {
+           after++;
+         }
+
+       
+      }
+    mIgnoreSelectedChanged = false; 
+     GimmickDebugMessage(1,
+                       "WxTreeView::SortLevel : " 
+                       <<after<<" selected after sorting"
+                       <<std::endl);  
+  
+  }
+  //================================================================
+
+  
+  //================================================================
+  void WxTreeView::ValidateSelectedImages(bool isSelection)
+  {
+    GimmickDebugMessage(7,
+                       "WxTreeView::ValidateSelectedImages" 
+                       <<std::endl);
+    const std::vector<tree::Node*>& sel(GetSelected(mLevelList.size()+1));
+    GetGimmickView()->OnSelectionChange(sel,
+                                       isSelection,(mLastSelected-1),
+                                       !mIgnoreSelectedChanged);
+  }
+  //================================================================
+
+
+  //================================================================
+  void WxTreeView::GetNodes(std::vector<tree::Node*>& nodes, bool direction)
+  {
+       long item = mLastSelected;
+       int level=mLevelList.size()-1;
+       //Gets current item data
+       long adr = GetCtrl(level)->GetItemData(item);
+       //Extracts the node
+       tree::Node* nod = ((ItemData*)adr)->node;
+    for ( ;; )
+    {
+               if(direction)
+               {
+                       item = GetCtrl(level)->GetNextItem(item,
+                                     wxLIST_NEXT_ABOVE);
+               }
+               else
+               {
+                       item = GetCtrl(level)->GetNextItem(item,
+                                     wxLIST_NEXT_BELOW);
+               }
+        if ( item == -1 || item==0  )
+               {
+            break;
+               }
+               if(GetCtrl(level)->GetItemState(item, wxLIST_STATE_SELECTED)==0 )
+               {
+
+                       adr = GetCtrl(level)->GetItemData(item);
+                       nod = ((ItemData*)adr)->node;
+                       nodes.push_back(nod);
+               }
+    }
+
+  }
+  //================================================================
+   //=================================================
+  void WxTreeView::OnKeyDown(wxListEvent &event)
+  {
+         if(event.GetKeyCode() == WXK_DELETE)
+         {
+                  wxBusyCursor busy;
+                  std::string temp = "0";
+                  RemoveSelected(temp);
+                  GetGimmickView()->ClearSelection();
+         }
+                 
+  }
+  //================================================================
+
+  //================================================================
+  // Should be in another place : not specific !
+  void WxTreeView::GetSelectedAsString(std::vector<std::string>&s)
+  {
+    int level=mLevelList.size();
+    const std::vector<tree::Node*>& sel=GetSelected(level+1);
+    std::vector<tree::Node*>::const_iterator i;
+    
+    for (i=sel.begin(); i!=sel.end(); ++i)
+      {
+       std::string filename=(*i)->GetAttribute("FullFileName");
+       s.push_back(filename);
+      }
+  }
+
+  //================================================================
+  void WxTreeView::GetFilenamesAsString(const std::vector<tree::Node*>& nodes, std::vector<std::string>&s)
+  {
+    std::vector<tree::Node*>::const_iterator i;
+    
+    for (i=nodes.begin(); i!=nodes.end(); ++i)
+      {
+                 if((*i)->GetLevel()<mLevelList.size())
+                 {
+                        GetTreeHandler()->LoadChildren(*i,0);
+                        GetFilenamesAsString((*i)->GetChildrenList(),s);
+                 }
+                 else
+                 {
+                       std::string filename=(*i)->GetAttribute("FullFileName");
+                       s.push_back(filename);
+                 }
+      }
+  }
+
+   //================================================================
+
+   //================================================================
+  void WxTreeView::GetAttributes(std::vector<std::string>& areShown, std::vector<std::string>& notShown, int level)
+  {
+         areShown.clear();
+         notShown.clear();
+       tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+       for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(level).begin();
+            a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(level).end();
+            ++a)
+       {
+               if(a->GetFlags()==creaImageIO::tree::AttributeDescriptor::EDITABLE && IsAttributeVisible(a->GetName(),level))
+           {
+                       areShown.push_back(a->GetName());
+               }
+       }
+       notShown=mLevelList[level-1].notShownAtts;
+  }
+
+  //================================================================
+  void WxTreeView::SetNonVisibleAttributes(const std::vector<std::string>& notShown, int nlevel)
+  {
+       mLevelList[nlevel].notShownAtts=notShown;
+  }
+
+  //================================================================
+   void WxTreeView::CreateCtrl(std::vector<std::string>& notShown, int nlevel)
+  {
+       int ctrl_style = wxLC_REPORT | wxLC_VRULES;
+    int col_style = wxLIST_FORMAT_LEFT;
+       LevelType level;
+       mLevelList[nlevel].SelectedUpToDate = true;
+       mLevelList[nlevel].SortColumn = 0;
+       mLevelList[nlevel].key.clear();
+       
+       mLevelList[nlevel].wxCtrl = new wxListCtrl(mLevelList[nlevel].wxSplitter,
+                                         nlevel,
+                                         wxDefaultPosition, 
+                                         wxDefaultSize,
+                                         ctrl_style);
+       wxWindow* oldWin=mLevelList[nlevel].wxSplitter->GetWindow1();
+       mLevelList[nlevel].wxSplitter->ReplaceWindow(oldWin,mLevelList[nlevel].wxCtrl);
+       mLevelList[nlevel].wxSplitter->Initialize(mLevelList[nlevel].wxCtrl);
+   
+       // Create the columns : one for each attribute of the level
+       int col = 0;
+       std::string title;
+
+       tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+       for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(nlevel+1).begin();
+            a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(nlevel+1).end();
+            ++a)
+
+       {   
+           if(a->GetFlags()!=creaImageIO::tree::AttributeDescriptor::PRIVATE && IsAttributeVisible(a->GetName(),nlevel+1))
+             {
+                 title=a->GetName();
+                 std::string temp = a->GetKey();
+                 if (temp.compare("ID") != 0)
+                 {
+                       mLevelList[nlevel].wxCtrl->InsertColumn(col, 
+                                       crea::std2wx(title),
+                                       col_style);
+                       col++;
+                 }
+               mLevelList[nlevel].key.push_back(a->GetKey());
+             }
+               
+         }
+       oldWin->Destroy();
+       UpdateLevel(1);
+       }
+
+   //================================================================
+  bool WxTreeView::IsAttributeVisible(const std::string& val, int level)
+  {
+         std::vector<std::string> ns=mLevelList[level-1].notShownAtts;
+         std::vector<std::string>::iterator it;
+         bool found=false;
+         for(it=ns.begin();it!=ns.end()&&!found;++it)
+         {
+                 if(val.compare(*it)==0)
+                 {
+                         found=true;
+                 }
+         }
+
+         return !found;
+  }
+ //================================================================
+  //================================================================
+
+       RemoveAlertDlg::RemoveAlertDlg(wxWindow *parent, 
+                                              wxString title,    
+                                                  const wxSize& size)
+ :   wxDialog( parent, 
+                 wxID_ANY, 
+                 title,
+                 wxDefaultPosition,
+                 size,
+                 wxDEFAULT_DIALOG_STYLE)
+       {
+           wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
+
+               //std::string out("To reload deleted patient, you should synchronize your database before.");  // JPR
+               //wxTextCtrl *text = new wxTextCtrl(this, wxID_ANY,crea::std2wx(out),wxDefaultPosition, wxSize(500,20));
+               wxTextCtrl *text = new wxTextCtrl(this, wxID_ANY,
+                                       _T("To reload deleted patient, you should synchronize your database before."),
+                                       wxDefaultPosition, wxSize(500,20));
+               mcheck = new wxCheckBox(this, 5478, _T("Do not display this warning again!"));
+               Connect( mcheck->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED , (wxObjectEventFunction) &RemoveAlertDlg::onCheck ); 
+               wxSizer* buttonsSizer = this->CreateSeparatedButtonSizer(wxOK|wxCANCEL);
+               
+               topsizer->Add(text);
+               topsizer->Add(mcheck,0,wxGROW);
+               topsizer->Add(buttonsSizer,0,wxGROW);
+               SetSizer(topsizer, true);
+               mSave = false;
+               Layout();
+       }
+       RemoveAlertDlg::~RemoveAlertDlg(){};
+       bool RemoveAlertDlg::isChecked()
+       {
+               return mSave;
+       }
+       void RemoveAlertDlg::onCheck(wxCommandEvent &Event)
+       {
+               mSave = mcheck->IsChecked();
+       }
+       
+
+  //================================================================
+  //================================================================
+  BEGIN_EVENT_TABLE(WxTreeView, wxPanel)   
+  /*
+    EVT_SIZE(MyFrame::OnSize)
+
+    EVT_MENU(LIST_QUIT, MyFrame::OnQuit)
+    EVT_MENU(LIST_ABOUT, MyFrame::OnAbout)
+    EVT_MENU(LIST_LIST_VIEW, MyFrame::OnListView)
+    EVT_MENU(LIST_REPORT_VIEW, MyFrame::OnReportView)
+    EVT_MENU(LIST_ICON_VIEW, MyFrame::OnIconView)
+    EVT_MENU(LIST_ICON_TEXT_VIEW, MyFrame::OnIconTextView)
+    EVT_MENU(LIST_SMALL_ICON_VIEW, MyFrame::OnSmallIconView)
+    EVT_MENU(LIST_SMALL_ICON_TEXT_VIEW, MyFrame::OnSmallIconTextView)
+    EVT_MENU(LIST_VIRTUAL_VIEW, MyFrame::OnVirtualView)
+    EVT_MENU(LIST_SMALL_VIRTUAL_VIEW, MyFrame::OnSmallVirtualView)
+
+    EVT_MENU(LIST_FOCUS_LAST, MyFrame::OnFocusLast)
+    EVT_MENU(LIST_TOGGLE_FIRST, MyFrame::OnToggleFirstSel)
+    EVT_MENU(LIST_DESELECT_ALL, MyFrame::OnDeselectAll)
+    EVT_MENU(LIST_SELECT_ALL, MyFrame::OnSelectAll)
+    EVT_MENU(LIST_DELETE, MyFrame::OnDelete)
+    EVT_MENU(LIST_ADD, MyFrame::OnAdd)
+    EVT_MENU(LIST_EDIT, MyFrame::OnEdit)
+    EVT_MENU(LIST_DELETE_ALL, MyFrame::OnDeleteAll)
+    EVT_MENU(LIST_SORT, MyFrame::OnSort)
+    EVT_MENU(LIST_SET_FG_COL, MyFrame::OnSetFgColour)
+    EVT_MENU(LIST_SET_BG_COL, MyFrame::OnSetBgColour)
+    EVT_MENU(LIST_TOGGLE_MULTI_SEL, MyFrame::OnToggleMultiSel)
+    EVT_MENU(LIST_SHOW_COL_INFO, MyFrame::OnShowColInfo)
+    EVT_MENU(LIST_SHOW_SEL_INFO, MyFrame::OnShowSelInfo)
+    EVT_MENU(LIST_FREEZE, MyFrame::OnFreeze)
+    EVT_MENU(LIST_THAW, MyFrame::OnThaw)
+    EVT_MENU(LIST_TOGGLE_LINES, MyFrame::OnToggleLines)
+    EVT_MENU(LIST_MAC_USE_GENERIC, MyFrame::OnToggleMacUseGeneric)
+
+    EVT_UPDATE_UI(LIST_SHOW_COL_INFO, MyFrame::OnUpdateShowColInfo)
+    EVT_UPDATE_UI(LIST_TOGGLE_MULTI_SEL, MyFrame::OnUpdateToggleMultiSel)
+END_EVENT_TABLE()
+
+BEGIN_EVENT_TABLE(MyListCtrl, wxListCtrl)
+    EVT_LIST_BEGIN_DRAG(LIST_CTRL, MyListCtrl::OnBeginDrag)
+    EVT_LIST_BEGIN_RDRAG(LIST_CTRL, MyListCtrl::OnBeginRDrag)
+       
+    EVT_LIST_BEGIN_LABEL_EDIT(-1, WxTreeView::OnBeginLabelEdit)
+    EVT_LIST_END_LABEL_EDIT(-1, WxTreeView::OnEndLabelEdit)
+       
+    EVT_LIST_DELETE_ITEM(LIST_CTRL, MyListCtrl::OnDeleteItem)
+    EVT_LIST_DELETE_ALL_ITEMS(LIST_CTRL, MyListCtrl::OnDeleteAllItems)
+#if WXWIN_COMPATIBILITY_2_4
+    EVT_LIST_GET_INFO(LIST_CTRL, MyListCtrl::OnGetInfo)
+    EVT_LIST_SET_INFO(LIST_CTRL, MyListCtrl::OnSetInfo)
+#endif
+  */
+    EVT_LIST_KEY_DOWN(-1, WxTreeView::OnKeyDown)
+    EVT_LIST_ITEM_SELECTED(-1, WxTreeView::OnItemSelected)
+       EVT_LIST_ITEM_RIGHT_CLICK(-1, WxTreeView::OnItemMenu)
+    EVT_LIST_ITEM_DESELECTED(-1, WxTreeView::OnItemDeSelected)
+       /*
+    EVT_LIST_KEY_DOWN(LIST_CTRL, MyListCtrl::OnListKeyDown)
+    EVT_LIST_ITEM_ACTIVATED(LIST_CTRL, MyListCtrl::OnActivated)
+    EVT_LIST_ITEM_FOCUSED(LIST_CTRL, MyListCtrl::OnFocused)
+*/
+    EVT_LIST_COL_RIGHT_CLICK(-1, WxTreeView::OnColClick)
+       
+    EVT_LIST_COL_CLICK(-1, WxTreeView::OnColClick)
+
+       //EVT_LEFT_DOWN(WxTreeView::OnMouseClick)
+       /*
+    EVT_LIST_COL_BEGIN_DRAG(LIST_CTRL, MyListCtrl::OnColBeginDrag)
+    EVT_LIST_COL_DRAGGING(LIST_CTRL, MyListCtrl::OnColDragging)
+    EVT_LIST_COL_END_DRAG(LIST_CTRL, MyListCtrl::OnColEndDrag)
+
+    EVT_LIST_CACHE_HINT(LIST_CTRL, MyListCtrl::OnCacheHint)
+
+#if USE_CONTEXT_MENU
+    EVT_CONTEXT_MENU(MyListCtrl::OnContextMenu)
+#endif
+    EVT_CHAR(MyListCtrl::OnChar)
+
+    EVT_RIGHT_DOWN(MyListCtrl::OnRightClick)
+  */
+END_EVENT_TABLE()
+  
+} // EO namespace creaImageIO
+
diff --git a/src/creaImageIOWxTreeView.h b/src/creaImageIOWxTreeView.h
new file mode 100644 (file)
index 0000000..db62a0a
--- /dev/null
@@ -0,0 +1,236 @@
+#ifndef __creaImageIOWxTreeView_h_INCLUDED__
+#define __creaImageIOWxTreeView_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+
+#include <creaImageIOTreeView.h>
+#include <creaWx.h>
+
+#include <wx/listctrl.h>
+#include <wx/splitter.h>
+//#include <vector>
+const std::string empty_string("");
+namespace creaImageIO
+{
+
+         //=====================================================================
+  /// Data stored by the list items
+  struct ItemData
+  {
+    ItemData() : node(0), id(-1), attr(&empty_string) {}
+    // The corresponding Node
+    tree::Node* node;
+    // The id ?
+    int id;
+    // The pointer on the current attribute string to sort on
+    const std::string* attr;
+    // Was the item previously selected ?
+    // Useful for reselecting the item after sort
+    bool selected;
+  };
+  /**
+   * \ingroup View
+   */
+  //=====================================================================
+  
+  //=====================================================================
+  /// Abstract class that handles the view of a Tree through its TreeHandler
+  class WxTreeView : public wxPanel, virtual public TreeView
+    {
+    public:
+      /// Ctor
+      WxTreeView(TreeHandler*, GimmickView*, 
+                wxWindow* parent, const wxWindowID id);
+      /// Virtual destructor
+      virtual ~WxTreeView();
+
+      
+      /// Updates the view of a level given the selected items of upper level
+      virtual void UpdateLevel( int );
+
+      ///Removes selected nodes on given level
+         virtual void RemoveSelected(std::string &i_save);
+
+         ///Returns the last selected level
+         virtual unsigned int GetLastSelectedLevel(){return mLastLevel;}
+
+      /// Callback for item selection
+      void OnItemSelected(wxListEvent& event);
+
+      /// Callback for item deselection
+      void OnItemDeSelected(wxListEvent& event);
+      
+      /// Callback for column click
+      void OnColClick(wxListEvent& event);
+      
+      /// Callback when the user needs the items sorted
+      void OnPopupSort(wxCommandEvent& event);
+      
+      ///Callback when the user need the items filtered
+      void OnPopupFilter(wxCommandEvent& event);
+
+         ///Callback when the user needs the item copied to the local disk
+      void OnLocalCopy(wxCommandEvent& event);
+
+
+         ///Callback when the user needs the item copied to the local disk
+      void OnAnonymizer(wxCommandEvent& event);
+
+
+         ///Callback when the user needs to edit a field
+      void OnEditField(wxCommandEvent& event);
+
+         ///Callback when the user needs to display alll dicom tags for a file
+         void OnDumpTags(wxCommandEvent &event);
+      
+         ///Callback when the user needs to transfer data from storage to storage
+         void OnExportToStorage(wxCommandEvent &event);
+      
+      ///Callback on mouse click
+      void OnMouseClick(wxMouseEvent& event);
+
+         /// Displays a menu for items
+         void OnItemMenu(wxListEvent &event);
+         
+         /// Gets the attributes that are being shown and the ones that have been blocked on a specific level
+         void GetAttributes(std::vector<std::string>& areShown, std::vector<std::string>& notShown, int level);
+
+         ///Sets the non visible attributes and refreshes the GUI
+         void SetNonVisibleAttributes(const std::vector<std::string>& notShown, int level);
+
+         ///Creates a new listctrl
+         void CreateCtrl(std::vector<std::string>& notShown, int nlevel);
+  
+         ///Returns true if the attribute passed as a parameter is visible or not
+         bool IsAttributeVisible(const std::string& val, int level);
+      
+      /// Actual processing of item selection/deselection 
+      /// Called by OnItemSelected and OnItemDeSelected
+      //      void ProcessItem
+    private:
+               wxBoxSizer      *msizer;
+      /// The struct holding the data for one level
+      /// Holds the wx control and other data
+      /// such as the vector of attribute keys corresponding to the columns
+      struct LevelType
+      {
+       // The List Control
+       wxListCtrl* wxCtrl;
+       wxSplitterWindow* wxSplitter;
+       std::vector<std::string> key;
+       // The vector of currently selected nodes of the level
+       std::vector<tree::Node*> Selected;
+       // True iff the vector Selected is up to date
+       bool SelectedUpToDate;
+       // The column used for sorting
+       unsigned int SortColumn;
+       ///Boolean that defines the direction of the sort
+       ///True is ascending order and false is descending
+       bool SortAscending;
+       //The vector of not shown attributes
+       std::vector<std::string> notShownAtts; 
+      };
+      /// The vector of levels : one for each level of the tree      
+      std::vector<LevelType> mLevelList;
+      
+      /// return the wxListCtrl of one level
+      wxListCtrl* GetCtrl(int l) { return mLevelList[l].wxCtrl; }
+      /// return the wxSplitter of one level
+      wxSplitterWindow* GetSplitter(int l) { return mLevelList[l].wxSplitter; }
+      //Returns the maximum number of levels
+      int GetNumberOfLevels(){ return mLevelList.size(); }
+      /// Gets the user selected data from the level passed as a parameter
+      /// Updates the vector if necessary
+      const std::vector<tree::Node*>& GetSelected(int level);
+      /// Set the bool SelectedUpToDate for level l
+      void SetSelectedUpToDate(int l, bool v) { mLevelList[l].SelectedUpToDate = v; }
+      /// Get the bool SelectedUpToDate for level l
+      bool GetSelectedUpToDate(int l) { return mLevelList[l].SelectedUpToDate; }
+       ///Validates the selected images
+      void ValidateSelectedImages(bool isSelection);   
+      ///Gets selected filenames
+      void GetSelectedAsString(std::vector<std::string>&s);
+         ///Gets the filenames of the given nodes and returns them on the given vector. Is recursive.
+         void GetFilenamesAsString(const std::vector<tree::Node*>& nodes, std::vector<std::string>&s);
+      /// Gets the next nodes on the list, be it up(true) or down(false).
+      void GetNodes(std::vector<tree::Node*>& nodes, bool direction);
+      /// Updates the view of a level given the selected items of upper level
+      /// Recursive method
+      virtual void RecursiveUpdateLevel( int );
+      ///Selects all the elements of a level 
+      void SelectAll(int level);
+      ///UnSelects all the elements of a level 
+      void UnSelectAll(int level);
+
+         void OnKeyDown(wxListEvent &event);
+      /// Sorts the level
+      void SortLevel(int level);
+      
+      /// Currently Selected Column
+      int mColumnSelected;
+      ///The last selected item on the list (left click)
+      long mLastSelected;
+
+         ///The last selected item on the list (right click)
+         long mLastRightSelected;
+
+         ///The last selected level (by right click)
+         int mLastRightLevel;
+      ///The color map
+      typedef std::map<tree::Node*,wxColour> ColorMap;
+      typedef std::pair<tree::Node*,wxColour> NodeColorPair;
+      ColorMap mColorMap;
+      ///Initial color palette
+      std::vector<std::string> mColorPalette;
+
+      wxMenu* menu;
+         
+      wxObject* senderCtrl;
+      int mAscendingID;
+      int mDescendingID;
+      int mFilterID;
+      unsigned int mLastLevel;
+      
+         wxMenu* menuItem;
+         wxMenu *subExportMenu;
+         int mAnonymizingID;
+         int mLocalCopyID;
+         int mEditFieldID;
+         int mDumpID;
+         int mExportID;
+         int mExport2StorageID;
+         
+      // If set to true then OnSelectedChanged returns immediately.
+      // Used to do avoid useless process during multiple selections 
+      // or sorting
+      bool mIgnoreSelectedChanged;
+
+      DECLARE_EVENT_TABLE()
+    };
+    // EO class WxTreeView
+    //=====================================================================
+
+       class RemoveAlertDlg : public wxDialog
+       {
+       public:
+               RemoveAlertDlg(wxWindow *parent, 
+                                              wxString title,    
+                                                  const wxSize& size);
+               ~RemoveAlertDlg();
+
+               bool isChecked();
+
+       private :
+               void onCheck(wxCommandEvent &Event);
+               bool mSave;
+               wxCheckBox *mcheck;
+
+       };
+
+
+} // EO namespace creaImageIO
+
+
+#endif // USE_WIDGETS
+// EOF
+#endif  
diff --git a/src/creaImageIOWxViewer.cpp b/src/creaImageIOWxViewer.cpp
new file mode 100644 (file)
index 0000000..c0180a0
--- /dev/null
@@ -0,0 +1,362 @@
+
+#include <creaImageIOWxViewer.h>
+#include <creaImageIOSystem.h>
+#include <fstream>
+#include <vtkCamera.h>
+#include <vtkRenderer.h>
+#include <vtkImageData.h>
+#include <creawxVTKRenderWindowInteractor.h>
+#include <creaMessageManager.h>
+#include <stdio.h>
+#include <time.h>
+
+
+using namespace crea;
+
+namespace creaImageIO
+{
+  
+  //=====================================================================
+
+  //=====================================================================
+  class WxViewerPlayer: public wxThread
+  {
+  public:
+    WxViewerPlayer(WxViewer* v) :
+      mWxViewer(v)
+    {}
+    
+    void* Entry();
+    void  OnExit();
+       
+  private:
+
+    WxViewer* mWxViewer;
+  };
+  
+  //=====================================================================
+
+
+
+  
+
+  //=====================================================================
+  // CTor
+  WxViewer::WxViewer(wxWindow *parent, 
+                    wxWindowID id,
+                    wxString title,
+                    const wxPoint& pos,
+                    const wxSize& size)
+    :   wxPanel( parent, 
+                id, 
+                pos,
+                size)
+  {
+    wxMutexLocker lock(mMutex);
+    GimmickDebugMessage(6,"WxViewer::WxViewer"
+                       <<std::endl);
+
+    mNeedRefresh = false;
+    mLastImageShown = NULL;
+       
+       // previewer    
+    mInteractor = new crea::creawxVTKRenderWindowInteractor(this,-1);
+    mInteractor->UseCaptureMouseOn();  
+    mViewer    = vtkImageViewer2::New();
+    mViewer->SetupInteractor ( mInteractor );
+    
+    mCurrent = 0;
+       mPlayer = 0;
+
+       // Grid to place checkbox and slider 
+       mflexSizer = new wxFlexGridSizer(1,2,1,1);
+       //Slider
+       mslide = new wxSlider(this,-1,0,0,1, wxDefaultPosition, wxSize(400,40), wxSL_HORIZONTAL | wxSL_LABELS);
+       Connect( mslide->GetId(), wxEVT_COMMAND_SLIDER_UPDATED , (wxObjectEventFunction) &WxViewer::OnSlide ); 
+       //CheckBox
+       mcheck = new wxCheckBox(this,5123,crea::std2wx("Cine Loop"));
+       Connect( mcheck->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED , (wxObjectEventFunction) &WxViewer::OnCineLoop ); 
+       mcheck->SetValue(false);
+       mflexSizer->Add(mcheck,0, wxFIXED_MINSIZE);
+       mflexSizer-> Add( mslide,1,wxALIGN_CENTER | wxFIXED_MINSIZE );
+
+       // Sizer for Previewer and GridSizer
+       mtopSizer = new wxBoxSizer(wxVERTICAL);
+       mtopSizer->Add(mflexSizer,0);
+    mtopSizer-> Add( mInteractor ,1,wxGROW,0);
+       SetSizer(mtopSizer,true);
+       
+       Update();  
+    Layout(); 
+  }
+  //=====================================================================
+
+  //=====================================================================
+  /// Destructor
+  WxViewer::~WxViewer()
+  {
+    wxMutexLocker lock(mMutex);
+    GimmickDebugMessage(6,"WxViewer::~WxViewer"
+                       <<std::endl);
+    // TO DO : desallocate cleanly
+       if(mPlayer)
+       {
+               mPlayer->Pause();
+               mPlayer->Delete();
+               mPlayer = 0;
+       }
+       delete mInteractor;
+       //delete mslide;
+       //delete mflexSizer;
+  }
+  //=====================================================================
+
+  //================================================================
+   void WxViewer::SetImageVector(std::vector<boost::shared_ptr<ImagePointerHolder> >& pointers)
+  {
+       wxMutexLocker lock(mMutex);
+       GimmickDebugMessage(6,"WxViewer::SetImageVector"<<std::endl);
+       imagePointers=pointers;
+       
+       mslide->SetMax(pointers.size());
+       // Refresh don't work, TO MODIFY
+       mslide->Refresh();
+       mslide->ClearTicks();
+       mslide->Hide();
+       mslide->Show();
+       StartPlayer();
+  }
+
+  //================================================================
+
+  void WxViewer::ShowNextImage()
+  {
+        
+       
+         mMutex.Unlock();
+       wxMutexLocker lock(mMutex);
+       
+           
+    GimmickMessage(2,"WxViewer::ShowNextImage() "
+                  <<mCurrent+1<<"/"
+                  <<imagePointers.size()<<std::endl);
+    
+    if(imagePointers.size()>0)
+       {
+               if (mCurrent<imagePointers.size()) 
+               {
+                       boost::shared_ptr<ImagePointerHolder> iph = imagePointers[mCurrent];
+                       //ImagePointerHolder* iph= imagePointers[mCurrent];
+                       vtkImageData* currIm=iph->Get();
+                       ShowImage(currIm);
+                       if ( currIm != mLastImageShown ) 
+                       {
+                               mNeedRefresh = true;
+                               mLastImageShown = currIm;
+                       }
+               mCurrent++;
+           }
+               else
+               {
+                       mCurrent = 0;
+                       //ImagePointerHolder* iph=imagePointers[mCurrent];
+                       boost::shared_ptr<ImagePointerHolder> iph = imagePointers[mCurrent];
+                       vtkImageData* currIm=iph->Get();
+                       ShowImage(currIm);
+                       if ( currIm != mLastImageShown ) 
+                       {
+                               mNeedRefresh = true;
+                               mLastImageShown = currIm;
+                       }
+                       mCurrent++;
+               }
+       }
+  }
+  //================================================================
+
+  //=====================================================================
+  void WxViewer::ShowImage(vtkImageData* im)
+  {
+    GimmickDebugMessage(6,"WxViewer::ShowImage"
+                       <<std::endl);
+    if (im==0) return;
+
+    mViewer->SetInput(im);
+
+    mViewer->SetSlice( 0 );
+
+    int x1,x2,y1,y2,z1,z2;
+    double spx,spy,spz;
+    im->Update();
+
+//std::cout << "in WxViewer::ShowImage PrintSelf() =";
+//im->PrintSelf(std::cout, vtkIndent(2));
+
+    im->GetSpacing(spx,spy,spz);
+    //im->GetExtent (x1,x2,y1,y2,z1,z2);  // JPR
+    im->GetWholeExtent (x1,x2,y1,y2,z1,z2); 
+/*       
+std::cout << "in WxViewer::ShowImage GetWholeExtent ext =";
+       std::cout << "   [x1]=" << x1;
+       std::cout << "   [x2]=" << x2;
+       std::cout << "   [y1]=" << y1;
+       std::cout << "   [y2]=" << y2;
+       std::cout << "   [z1]=" << z1;
+       std::cout << "   [z2]=" << z2;
+std::cout << std::endl; 
+*/   
+    if ((x1!=mx1) ||
+       (x2!=mx2) ||
+       (y1!=my1) ||
+       (y2!=my2) ||
+       (z1!=mz1) ||
+       (z2!=mz2) ||
+       (spx!=mspx) ||
+       (spy!=mspy) ||
+       (spz!=mspz) 
+       )
+      {
+       mx1 = x1;
+       mx2 = x2;
+       my1 = y1;
+       my2 = y2;
+       mz1 = z1;
+       mz2 = z2;
+       mspx = spx;
+       mspy = spy;
+       mspz = spz;
+
+       double *range = im->GetScalarRange();
+       mViewer->SetColorWindow(range[1] - range[0]);
+       mViewer->SetColorLevel(0.5 * (range[1] + range[0]));
+
+       mViewer->GetRenderer()->ResetCamera();
+       double bounds[6];
+
+       mViewer->GetRenderer()->ComputeVisiblePropBounds(bounds);
+
+       mViewer->GetRenderer()->ResetCameraClippingRange(bounds);
+       mViewer->GetRenderer()->SetBackground(0.1,0.1,0.2);  
+      }
+  } 
+  //================================================================
+  
+  //================================================================
+  bool WxViewer::RefreshIfNecessary()
+  {
+    if (mNeedRefresh)
+      {
+       GimmickDebugMessage(10,"WxViewer : Refreshing"<<std::endl);
+
+       mInteractor->Render();
+       mNeedRefresh = false;
+       return true;
+      }
+    return false;
+  }
+  //================================================================
+  
+  //==================================================
+  void WxViewer::StopPlayer()
+  {
+         wxMutexLocker lock(mMutex);
+         if (mPlayer==0 ) return;
+         mPlayer->Delete();  
+         mPlayer=0;
+  }
+  //================================================================
+  
+  //==================================================
+  void WxViewer::StartPlayer()
+       {
+               if(mcheck->IsChecked())
+               {
+                       //      wxMutexLocker lock(mMutex);
+                       if (mPlayer != 0) return;
+                       mPlayer = new WxViewerPlayer(this);
+                       mPlayer->Create();
+                       mPlayer->Run();  
+               }
+               else
+               {
+                       ShowNextImage();
+               }
+       }
+
+  //================================================================
+  
+  //==================================================
+
+    void WxViewer::OnCineLoop(wxCommandEvent &Event)
+       {
+               if(!mcheck->IsChecked())
+               {
+                       mPlayer->Pause();
+                       mPlayer->Delete();
+                       mPlayer = 0;
+               }
+               StartPlayer();
+       }
+       
+ //================================================================
+  
+  //==================================================
+       
+       void WxViewer::OnSlide(wxCommandEvent &Event)
+        {
+                mCurrent = mslide->GetValue();
+                StartPlayer();
+        }
+        //================================================================
+  
+  //==================================================
+
+        void WxViewer::SetValue()
+        {
+                mslide->SetValue(mCurrent);
+        }
+
+  //  BEGIN_EVENT_TABLE(WxGimmickFrame, wxDialog)
+  //    END_EVENT_TABLE()
+  //================================================================
+
+//========================================================================
+//========================================================================
+//========================================================================
+//========================================================================
+//========================================================================
+//========================================================================
+//========================================================================
+//========================================================================
+
+  void*  WxViewerPlayer::Entry()
+  {
+         
+    GimmickDebugMessage(6,"WxViewerPlayer::Entry()"<<std::endl);
+       
+       while(!TestDestroy())
+           { 
+                       
+                       mWxViewer->ShowNextImage();
+                       mWxViewer->SetValue();
+                       ::wxWakeUpIdle();
+                       clock_t endwait;
+                       endwait = clock () + 0.2 * CLOCKS_PER_SEC ;
+                       while (clock() < endwait ) {}
+                       
+      }
+    return 0;
+  }
+
+  //=====================================================================
+
+  //=====================================================================
+  void WxViewerPlayer::OnExit()
+  {
+    GimmickDebugMessage(6,"WxViewerPlayer::OnExit() "<<std::endl);
+  }
+
+} // EO namespace creaImageIO
+
diff --git a/src/creaImageIOWxViewer.h b/src/creaImageIOWxViewer.h
new file mode 100644 (file)
index 0000000..1e4e2f2
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef __creaImageIOWxViewer_h_INCLUDED__
+#define __creaImageIOWxViewer_h_INCLUDED__
+
+#ifdef USE_WXWIDGETS
+
+// wx
+#include <creaWx.h>
+#include <wx/image.h>
+#include <wx/imaglist.h>
+#include <wx/splitter.h>
+
+#include <creaImageIOSystem.h>
+#include <creaImageIOImagePointerHolder.h>
+
+// For image preview 
+// vtk and wxvtk classes
+#include "creawxVTKRenderWindowInteractor.h"
+#include "vtkImageViewer2.h"
+
+namespace creaImageIO
+{
+
+  class WxViewerPlayer;
+
+  class WxViewer : public wxPanel
+  {
+  public:
+    /// Ctors 
+    WxViewer();
+    WxViewer(wxWindow *parent, 
+                  const wxWindowID id,
+                  wxString title,
+                  const wxPoint& pos, 
+                  const wxSize& size);
+    /// Dtor
+    virtual ~WxViewer();
+    /// Shows the next image in the image vector
+    void ShowNextImage();
+       ///Starts the image player
+       void StartPlayer();
+       ///Stops the image player
+    void StopPlayer();
+       ///Refreshes the interface if the current image shown has changed
+    bool RefreshIfNecessary();
+       ///Sets a new image vector to be read
+       void SetImageVector(std::vector<boost::shared_ptr<ImagePointerHolder> > &pointers);
+
+       /// Set value of slider control
+       void SetValue();
+
+  private:
+
+    /// Event to resume or start cine loop
+       void OnCineLoop(wxCommandEvent &Event);
+
+       /// Event to change displayed frames with slide control
+       void OnSlide(wxCommandEvent &Event);
+
+
+    ///Shows the image passed as parameter
+    void ShowImage(vtkImageData* im);
+    /// Previewer
+    vtkImageViewer2* mViewer;
+
+       ///Slider
+       wxSlider *mslide ;
+
+       ///CheckBox to cine loop
+       wxCheckBox  *mcheck;
+
+    /// Associated wxvtk interactor
+       crea::creawxVTKRenderWindowInteractor  *mInteractor;
+       
+    /// Current extent 
+    int mx1,mx2,my1,my2,mz1,mz2;
+    /// Current spacing
+    double mspx,mspy,mspz;
+    /// Current image shown
+    int mCurrent;
+    ///The threaded movie player
+    WxViewerPlayer* mPlayer;
+    /// The mutex
+    wxMutex mMutex;
+    /// Boolean that declares if the player needs to be refreshed
+    bool mNeedRefresh;
+       ///Last image shown
+    vtkImageData* mLastImageShown;
+       ///The vectors of images to be shown
+       std::vector< boost::shared_ptr<ImagePointerHolder> > imagePointers;
+
+       /// Sizers to preview images 
+       wxFlexGridSizer *mflexSizer;
+       wxBoxSizer *mtopSizer;
+
+  };
+
+}
+
+#endif // USE_WIDGETS
+// EOF
+#endif  
diff --git a/src/creatisIO.cpp b/src/creatisIO.cpp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/creatisIOComparator.cpp b/src/creatisIOComparator.cpp
new file mode 100644 (file)
index 0000000..efb2f5d
--- /dev/null
@@ -0,0 +1,62 @@
+#include <creatisIOComparator.h>
+
+namespace creaImageIO{
+
+       Comparator::Comparator(tree::Node *i_tree, std::string i_tag) : m_discr(i_tag): bdiscr(false)
+       {
+               std::map< std::string, std::string>  attr;
+               i_tree->GetDescriptor().BuildAttributeMap(attr);
+               std::map<std::string, std::string>::iterator it_att = attr.begin();
+               for(; it_att != attr.end(); it_att++)
+               {
+                       if (it_att->first == m_discr)
+                       {
+                               bdiscr = true;
+                               break;
+                       }
+               }
+               tree::Node::ChildrenListType::reverse_iterator j;
+       for (j = (*i)->GetChildrenList().rbegin(); 
+            j!= (*i)->GetChildrenList().rend(); 
+            ++j)
+         {
+           GimmickDebugMessage(1,
+                               "adding children "
+                               <<(*j)->GetLabel()
+                               <<"'"
+                               <<std::endl);
+           
+           wxListItem item;
+           item.SetMask(wxLIST_MASK_STATE | 
+                        wxLIST_MASK_TEXT |
+                        //                      wxLIST_MASK_IMAGE |
+                        wxLIST_MASK_DATA |
+                        //                      wxLIST_MASK_WIDTH |
+                        wxLIST_MASK_FORMAT
+                        );
+           
+               ItemData* data = new ItemData();
+           data->node = *j;
+           data->id = _id;
+               
+           item.SetId(_id);
+           item.SetData(data);
+
+           _id++;
+           GetCtrl(l)->InsertItem(item);
+           
+           //Setting attributes
+           for (int k=0; k<GetCtrl(l)->GetColumnCount(); ++k)                          
+             {
+               std::string val;
+               //  Temporary correction : it works but no explanation about the problem FCY
+               
+               if(k==0 && level <3)
+               {
+                 val = (*j)->GetAttribute("NumberOfChildren");
+               }
+               else
+                 val = (*j)->GetAttribute(mLevelList[l].key[k]);
+               
+       }
+}
\ No newline at end of file
diff --git a/src/creatisIOComparator.h b/src/creatisIOComparator.h
new file mode 100644 (file)
index 0000000..e7b0df4
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __creatisIOComparator_h_INCLUDED__
+#define __creatisIOComparator_h_INCLUDED__
+
+#include <creaImageIOTreeHandler.h>
+
+namespace creaImageIO{
+       class Comparator{
+       public:
+
+               Comparator(tree::Node *tr, std::string i_tag);
+               ~Comparator();
+               bool compare(std::string i_SOPIID);
+               void add(std::string i_SOPIID);
+               bool hasToCompare(){return bdiscr);
+
+       private:
+               std::vector<std::string> m_SOPIID;
+               std::string m_discr;            //tag_discriminant
+               bool bdiscr;
+
+       };
+}
+#endif 
\ No newline at end of file
diff --git a/src/creatisIOWxDumpPanel.cpp b/src/creatisIOWxDumpPanel.cpp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/data/localdatabase_Descriptor.dscp b/src/data/localdatabase_Descriptor.dscp
new file mode 100644 (file)
index 0000000..3694fcf
--- /dev/null
@@ -0,0 +1,56 @@
+<level>
+Root
+O Name Name 4
+<level>
+Patient
+O NumberOfChildren     #Series
+D 0x0010 0x0010 4
+D 0x0010 0x0040 3
+D 0x0010 0x0030 3 
+D 0x0010 0x0020 2
+<level>
+Series
+O NumberOfChildren        #Images
+D 0x0008 0x0060 4 
+D 0x0008 0x1030 3 
+D 0x0008 0x103E 3
+D 0x0008 0x0080 3
+#D 0x0008 0x0081 3 
+#D 0x0008 0x1010 3
+#D 0x0008 0x1048 3 
+#D 0x0008 0x1050 3 
+D 0x0018 0x1030 3 
+D 0x0020 0x0010 3
+D 0x0008 0x0020 3
+D 0x0008 0x0030 3
+D 0x0008 0x0050 3 
+#D 0x0008 0x0005 3
+D 0x0008 0x0021 3 
+D 0x0008 0x0031 3
+D 0x0020 0x000D 3
+D 0x0020 0x000E 2
+<level>
+Image
+D 0x0020 0x0013 3
+D 0x0028 0x0010 3
+D 0x0028 0x0011 3 
+D 0x0028 0x0008 3 
+#D 0x0028 0x0103 3
+D 0x0020 0x0032 3 
+D 0x0020 0x0037 3 
+D 0x0020 0x1041 3 
+D 0x0028 0x0030 3 
+#D 0x0028 0x0100 3
+#D 0x0028 0x0101 3 
+#D 0x0008 0x0008 3 
+D 0x0008 0x0023 3 
+D 0x0008 0x0033 3 
+D 0x0020 0x4000 3 
+#D 0x0004 0x1500 4 
+#D 0x0004 0x1501 4 
+#D 0x0028 0x1052 3 
+#D 0x0028 0x1053 3 
+#D 0x0050 0x0004 3 
+#D 0x0020 0x0052 3 
+#D 0x0008 0x0016 3 
+O FullFileName Full_file_name 2
diff --git a/src/doxygen/Architecture.htm b/src/doxygen/Architecture.htm
new file mode 100644 (file)
index 0000000..3d1fd07
--- /dev/null
@@ -0,0 +1,348 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Architecture</title>
+</head>
+
+<body>
+
+<h1 id="head-854b062d360d04ce4f5012114afa9ff5f11f21ba">Architecture</h1>
+<span class="anchor" id="line-6"></span><span class="anchor" id="line-7"></span>
+<p class="line867"></p>
+<h2 id="head-230b785b2112730d4f8aaffcda83ccd28c9c8d83">Generalities</h2>
+<span class="anchor" id="line-8"></span><span class="anchor" id="line-9"></span>
+<ul>
+       <li>cvs : creatis/creaImageIO <span class="anchor" id="line-10"></span>
+       <ul>
+               <li style="list-style-type: none;">
+               <p class="line862">cvs co -D 
+               :PROTOCOL:USERNAME@cvs.creatis.insa-lyon.fr:/cvs/creatis creaImageIO
+               <span class="anchor" id="line-11"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>09/02/09 : <span class="anchor" id="line-12"></span>
+       <ul>
+               <li>new sources in src2 : create a lib called creaImageIO2
+               <span class="anchor" id="line-13"></span></li>
+               <li>command line app : appli/gimmick <span class="anchor" id="line-14">
+               </span></li>
+               <li>cmake option : BUILD_V2 to build the new version
+               <span class="anchor" id="line-15"></span></li>
+       </ul>
+       </li>
+       <li>All C++ files begin with creaImageIO <span class="anchor" id="line-16">
+       </span></li>
+       <li>All creaImageIO classes are in a namespace creaImageIO
+       <span class="anchor" id="line-17"></span><span class="anchor" id="line-18">
+       </span></li>
+</ul>
+<p class="line867"></p>
+<h2 id="head-fd2930d25892babc425be6c8bf5e10dd28f776bb">General stucture</h2>
+<span class="anchor" id="line-19"></span><span class="anchor" id="line-20">
+</span>
+<ul>
+       <li>The main data structure : attributed tree
+       <span class="anchor" id="line-21"></span>
+       <ul>
+               <li>all related files are of the form : creaImageIOTree
+               <span class="anchor" id="line-22"></span></li>
+               <li>all related classes are in a namespace : creaImageIO::tree
+               <span class="anchor" id="line-23"></span></li>
+       </ul>
+       </li>
+       <li>
+       <p class="line862">The abstract &#39;Model&#39; : <a class="nonexistent">TreeHandler</a> 
+       = manages a data source (read-only; read/write)
+       <span class="anchor" id="line-24"></span></p>
+       <ul>
+               <li>
+               <p class="line862">Concrete models : now SQLiteTreeHandler; future 
+               IRodsTreeHandler, <a class="nonexistent">FavoritesTreeHandler</a>?
+               <span class="anchor" id="line-25"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>
+       <p class="line862">The controller &#39;Gimmick&#39; : controls different
+       <a class="nonexistent">TreeHandlers</a>: <span class="anchor" id="line-26">
+       </span></p>
+       <ul>
+               <li>Local database handler <span class="anchor" id="line-27"></span>
+               </li>
+               <li>Favorites handler <span class="anchor" id="line-28"></span></li>
+               <li>Other which are open on user demand
+               <span class="anchor" id="line-29"></span></li>
+       </ul>
+       </li>
+       <li>The Views: <span class="anchor" id="line-30"></span>
+       <ul>
+               <li>
+               <p class="line862">Abstract <a class="nonexistent">GimmickView</a> : 
+               Dialog <span class="anchor" id="line-31"></span></p>
+               </li>
+               <li>
+               <p class="line862">Concrete <a class="nonexistent">GimmickView</a> : now
+               <a class="nonexistent">WxGimmickView</a>; future QGimmickView ?
+               <span class="anchor" id="line-32"></span></p>
+               </li>
+               <li>
+               <p class="line862">Do we need to have abstract classes for
+               <a class="nonexistent">GimmickView</a> components ?
+               <span class="anchor" id="line-33"></span></p>
+               <ul>
+                       <li>
+                       <p class="line891"><a class="nonexistent">TreeView</a> : is 
+                       associated with a <a class="nonexistent">TreeHandler</a> to 
+                       visualize its Tree <span class="anchor" id="line-34"></span></p>
+                       </li>
+                       <li>
+                       <p class="line891"><a class="nonexistent">AttributeView</a> : 
+                       visualizes a set of attributes (only one for a
+                       <a class="nonexistent">GimmickView</a>)
+                       <span class="anchor" id="line-35"></span></p>
+                       </li>
+                       <li>
+                       <p class="line891"><a class="nonexistent">ImageView</a> : preview of 
+                       images <span class="anchor" id="line-36"></span>
+                       <span class="anchor" id="line-37"></span>
+                       <span class="anchor" id="line-38"></span></p>
+                       </li>
+               </ul>
+               </li>
+       </ul>
+       </li>
+</ul>
+<p class="line867"></p>
+<h2 id="head-b16e3563d729255863452b289e971da6a51d945b">Classes</h2>
+<span class="anchor" id="line-39"></span><span class="anchor" id="line-40">
+</span>
+<p class="line867"></p>
+<h3 id="head-4b6a5f3be677d7dfd21607ab2394efda67858131">Data structure: 
+Attributed tree</h3>
+<span class="anchor" id="line-41"></span><span class="anchor" id="line-42">
+</span>
+<p class="line874">in namespace creaImageIO::tree
+<span class="anchor" id="line-43"></span><span class="anchor" id="line-44">
+</span></p>
+<ul>
+       <li>Tree <span class="anchor" id="line-45"></span>
+       <ul>
+               <li>Attributed tree structure <span class="anchor" id="line-46"></span>
+               </li>
+               <li>inherits Node <span class="anchor" id="line-47"></span></li>
+               <li>
+               <p class="line862">holds a vector of root <a class="nonexistent">
+               TreeNode</a> <span class="anchor" id="line-48"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">TreeData</a>
+       <span class="anchor" id="line-49"></span></p>
+       <ul>
+               <li>Abstract class to store user data on a tree
+               <span class="anchor" id="line-50"></span></li>
+       </ul>
+       </li>
+       <li>Node <span class="anchor" id="line-51"></span>
+       <ul>
+               <li>belong to a Tree, <span class="anchor" id="line-52"></span></li>
+               <li>holds a pointer on parent Node, <span class="anchor" id="line-53">
+               </span></li>
+               <li>holds a vector of children Node <span class="anchor" id="line-54">
+               </span></li>
+       </ul>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">NodeData</a>
+       <span class="anchor" id="line-55"></span></p>
+       <ul>
+               <li>Abstract class to store user data on a tree node
+               <span class="anchor" id="line-56"></span></li>
+       </ul>
+       </li>
+       <li>Descriptor <span class="anchor" id="line-57"></span>
+       <ul>
+               <li>Descriptor of the structure a tree (number of levels, descriptors of 
+               each level, ...) <span class="anchor" id="line-58"></span></li>
+               <li>
+               <p class="line862">holds a vector of <a class="nonexistent">
+               LevelDescriptor</a> <span class="anchor" id="line-59"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">LevelDescriptor</a>
+       <span class="anchor" id="line-60"></span></p>
+       <ul>
+               <li>
+               <p class="line862">holds a vector of <a class="nonexistent">
+               TreeAttributeDescriptor</a> <span class="anchor" id="line-61"></span>
+               </p>
+               </li>
+       </ul>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">AttributeDescriptor</a>
+       <span class="anchor" id="line-62"></span></p>
+       <ul>
+               <li>stores name, dicom group/elem, flags
+               <span class="anchor" id="line-63"></span></li>
+       </ul>
+       </li>
+       <li>Comparator <span class="anchor" id="line-64"></span>
+       <ul>
+               <li>Abstract definition of a comparator of Node
+               <span class="anchor" id="line-65"></span></li>
+               <li>
+               <p class="line862">Comparison is done by operator()(Node* const &amp;, Node* 
+               const &amp;) <span class="anchor" id="line-66"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">ComparatorWithOrder</a>
+       <span class="anchor" id="line-67"></span></p>
+       <ul>
+               <li>Abstract Comparator whose order can be reversed
+               <span class="anchor" id="line-68"></span></li>
+               <li>
+               <p class="line862">Concrete comparison is done by method compare(Node* 
+               const &amp;, Node* const &amp;) <span class="anchor" id="line-69"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">LexicographicalComparator</a>
+       <span class="anchor" id="line-70"></span></p>
+       <ul>
+               <li>A Comparator which stores a vector of Comparators and which performs 
+               lexicographical comparison <span class="anchor" id="line-71"></span>
+               </li>
+       </ul>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">IntComparator</a> : Compares the 
+       values of a given Attribute of the Nodes which is decoded as an int value
+       <span class="anchor" id="line-72"></span></p>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">FloatComparator</a> : Compares the 
+       values of a given Attribute of the Nodes which is decoded as a float value
+       <span class="anchor" id="line-73"></span></p>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">StringComparator</a> : Compares 
+       the values of a given Attribute of the Nodes which is decoded as a string 
+       value <span class="anchor" id="line-74"></span>
+       <span class="anchor" id="line-75"></span><span class="anchor" id="line-76">
+       </span></p>
+       </li>
+</ul>
+<p class="line867"></p>
+<h3 id="head-df11fea98849928d47fd0fca777300beeb1de441">Models : TreeHandler and 
+descendants</h3>
+<span class="anchor" id="line-77"></span><span class="anchor" id="line-78">
+</span>
+<ul>
+       <li>
+       <p class="line891"><a class="nonexistent">TreeHandler</a> : Abstract class 
+       which &#39;handles&#39; a Tree structure. <span class="anchor" id="line-79"></span>
+       </p>
+       <ul>
+               <li style="list-style-type: none;">Can:
+               <span class="anchor" id="line-80"></span>Load the children of a given 
+               Node <span class="anchor" id="line-81"></span>
+               <span class="anchor" id="line-82"></span></li>
+       </ul>
+       </li>
+       <li class="gap">
+       <p class="line862">SQLiteTreeHandler : Concrete <a class="nonexistent">
+       TreeHandler</a> which manages a tree stored in a sqlite database
+       <span class="anchor" id="line-83"></span></p>
+       </li>
+       <li>CppSQLite3.h / CppSQLite3.cpp : C++ interface to sqlite db
+       <span class="anchor" id="line-84"></span></li>
+</ul>
+<p class="line874">... <span class="anchor" id="line-85"></span>
+<span class="anchor" id="line-86"></span></p>
+<ul>
+       <li>
+       <p class="line891"><a class="nonexistent">ImageFinder</a> : Parses (recursively) 
+       a part of a filesystem to look for known images and load their attributes in 
+       order to add the images to a Tree (submission via a <a class="nonexistent">
+       TreeHandler</a>::<a class="nonexistent">AddBranch</a>)
+       <span class="anchor" id="line-87"></span><span class="anchor" id="line-88">
+       </span><span class="anchor" id="line-89"></span></p>
+       </li>
+</ul>
+<p class="line867"></p>
+<h3 id="head-5d6e60823befe28469fe2d44ec8a889c06ea3b72">Image handling</h3>
+<span class="anchor" id="line-90"></span><span class="anchor" id="line-91">
+</span>
+<ul>
+       <li>creaImageIOImageReader.h/cpp : <span class="anchor" id="line-92"></span>
+       <ul>
+               <li>
+               <p class="line891"><a class="nonexistent">SpecificImageReader</a>
+               <span class="anchor" id="line-93"></span></p>
+               </li>
+               <li>
+               <p class="line891"><a class="nonexistent">ImageReader</a>
+               <span class="anchor" id="line-94"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>creaImageIOMultiThreadImageReader.h/cpp
+       <span class="anchor" id="line-95"></span></li>
+       <li>creaImageIOIndexedHeap.h/txx <span class="anchor" id="line-96"></span>
+       <span class="anchor" id="line-97"></span></li>
+</ul>
+<p class="line867"></p>
+<h3 id="head-6b69e886af29f9ef5bb7eb8b646980dd2963c2cf">Controller</h3>
+<span class="anchor" id="line-98"></span><span class="anchor" id="line-99">
+</span>
+<ul>
+       <li>Gimmick <span class="anchor" id="line-100"></span>
+       <span class="anchor" id="line-101"></span></li>
+</ul>
+<p class="line867"></p>
+<h3 id="head-4e100fce838267c2c7182a13a0137ed08ed1c75a">Views</h3>
+<span class="anchor" id="line-102"></span><span class="anchor" id="line-103">
+</span>
+<ul>
+       <li>
+       <p class="line891"><a class="nonexistent">GimmickView</a> : Abstract
+       <span class="anchor" id="line-104"></span></p>
+       </li>
+       <li>
+       <p class="line891"><a class="nonexistent">WxGimmickView</a>
+       <span class="anchor" id="line-105"></span></p>
+       <ul>
+               <li>
+               <p class="line891"><a class="nonexistent">WxTreeVie</a>w</p>
+               </li>
+               <li>
+               <p class="line891"><a class="nonexistent">WxAttributeView</a>
+               <span class="anchor" id="line-107"></span></p>
+               </li>
+               <li>
+               <p class="line891"><a class="nonexistent">WxImageView</a>
+               <span class="anchor" id="line-108"></span></p>
+               </li>
+       </ul>
+       </li>
+       <li>QGimmickView <span class="anchor" id="line-109"></span>
+       <ul>
+               <li>... </li>
+       </ul>
+       </li>
+</ul>
+
+</body>
+
+</html>
diff --git a/src/doxygen/CMakeLists.txt b/src/doxygen/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0e1db6d
--- /dev/null
@@ -0,0 +1,122 @@
+
+
+MACRO(CREA_BUILD_DOXYGEN_DOC NAME INPUT DOC_RELATIVE_INSTALL_PATH PREDEFINED)
+
+  #--------------------------------------------------------------------------
+  SET(USE_DOXYGEN ON CACHE BOOL "" FORCE)
+  
+  # Name
+  SET(DOXYGEN_PROJECT_NAME "${NAME}")
+
+  # Inputs
+  STRING(REGEX REPLACE ";" " " DOXYGEN_INPUT "${INPUT}")
+
+  # Output dirs
+  SET(DOXYGEN_HTML_OUTPUT ".")
+  SET(DOXYGEN_OUTPUT ${PROJECT_BINARY_DIR}/${DOC_RELATIVE_INSTALL_PATH})
+  IF(NOT IS_DIRECTORY ${DOXYGEN_OUTPUT}/${DOXYGEN_HTML_OUTPUT})
+    FILE(MAKE_DIRECTORY ${DOXYGEN_OUTPUT}/${DOXYGEN_HTML_OUTPUT})
+  ENDIF(NOT IS_DIRECTORY ${DOXYGEN_OUTPUT}/${DOXYGEN_HTML_OUTPUT})
+
+  # Doc exclude
+  SET(DOXYGEN_EXCLUDE "CppSQLite3.h;CppSQLite3.cpp")
+  STRING(REGEX REPLACE ";" " " DOXYGEN_EXCLUDE "${DOXYGEN_EXCLUDE}")
+
+  # Log file name 
+  SET(DOXYGEN_LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/doxygen.log")
+
+  # Predefined symbols
+  STRING(REGEX REPLACE ";" " " DOXYGEN_DOC_PREDEFINED "${PREDEFINED}")
+  
+  #---------------------------------------------------------------------------
+  # DOT verification
+  IF(DOT)
+    GET_FILENAME_COMPONENT(DOXYGEN_DOT_PATH ${DOT} PATH)
+    SET(DOXYGEN_HAVE_DOT "YES")
+  ELSE(DOT)
+    SET(DOXYGEN_DOT_PATH "")
+    SET(DOXYGEN_HAVE_DOT "NO")
+  ENDIF(DOT)
+  
+  #---------------------------------------------------------------------------
+  # Create file and project
+  CONFIGURE_FILE(
+    ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.txt.in
+    ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.txt
+    @ONLY IMMEDIATE
+    )
+  
+  ADD_CUSTOM_COMMAND(
+    OUTPUT ${DOXYGEN_OUTPUT}/${DOXYGEN_HTML_OUTPUT}/index.html
+    COMMAND 
+    ${DOXYGEN}
+    ARGS
+    ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.txt
+    #  DEPENDS bbtk bbi 
+    )
+  
+  ADD_CUSTOM_TARGET(doxygen_${NAME} ALL
+    DEPENDS  ${DOXYGEN_OUTPUT}/${DOXYGEN_HTML_OUTPUT}/index.html
+    )
+  
+#  INSTALL(
+#    DIRECTORY
+#    ${DOXYGEN_OUTPUT}/${DOXYGEN_HTML_OUTPUT}
+#    DESTINATION
+#    ${BBTK_DOXYGEN_INSTALL_PATH}/${DOC_RELATIVE_INSTALL_PATH}
+#    )
+  #--------------------------------------------------------------------------
+       
+ENDMACRO(CREA_BUILD_DOXYGEN_DOC)
+
+
+
+
+FILE(GLOB PAGES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.htm")
+#MESSAGE(STATUS "DOXYGEN HTML PAGES = ${PAGES}")
+FOREACH(PAGE ${PAGES})
+  CONFIGURE_FILE(
+    ${CMAKE_CURRENT_SOURCE_DIR}/${PAGE}
+    ${PROJECT_BINARY_DIR}/doxygen/${PAGE}
+    IMMEDIATE
+  )
+#MESSAGE(STATUS "COPYING ${PAGE} TO ${PROJECT_BINARY_DIR}/doxygen/${PAGE}")
+ENDFOREACH(PAGE)
+
+
+FILE(GLOB IMAGES_PAGE RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.png" "*.jpg")
+FOREACH(IMAGE_PAGE ${IMAGES_PAGE})
+  CONFIGURE_FILE(
+    ${CMAKE_CURRENT_SOURCE_DIR}/${IMAGE_PAGE}
+    ${PROJECT_BINARY_DIR}/doxygen/${IMAGE_PAGE}
+    COPYONLY
+  )
+ENDFOREACH(IMAGE_PAGE)
+
+
+
+CONFIGURE_FILE(
+  ${CMAKE_CURRENT_SOURCE_DIR}/DoxyMainPage.txt.in
+  ${CMAKE_CURRENT_BINARY_DIR}/DoxyMainPage.txt
+  @ONLY IMMEDIATE
+  )
+
+SET(INPUT 
+  ${CMAKE_CURRENT_BINARY_DIR}/DoxyMainPage.txt
+  ${PROJECT_SOURCE_DIR}/src2
+  ${PROJECT_SOURCE_DIR}/appli/gimmick
+  ${PROJECT_SOURCE_DIR}/appli/wxGimmick
+  ${PROJECT_SOURCE_DIR}/appli/TestWxGimmickReaderDialog
+  )
+
+SET(DOXYGEN_DOC_PREDEFINED USE_WXWIDGETS)
+
+CREA_BUILD_DOXYGEN_DOC(
+  ${CMAKE_PROJECT_NAME}_lib 
+  "${INPUT}" 
+  "doxygen" 
+  "${CREA_DEFINITIONS}"
+  )
+
+#MESSAGE("DOX : ${CREA_DEFINITIONS}")
diff --git a/src/doxygen/ClassDiagram.htm b/src/doxygen/ClassDiagram.htm
new file mode 100644 (file)
index 0000000..e8f683e
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>Class Diagram</strong></p>
+<img src="ClassDiagram.png" width="789" height="326" />
+
+</body>
+
+</html>
diff --git a/src/doxygen/ClassDiagram.png b/src/doxygen/ClassDiagram.png
new file mode 100644 (file)
index 0000000..c697141
Binary files /dev/null and b/src/doxygen/ClassDiagram.png differ
diff --git a/src/doxygen/ComponentDiagram.htm b/src/doxygen/ComponentDiagram.htm
new file mode 100644 (file)
index 0000000..11620e8
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>Component Diagram</strong></p>
+<img src="ComponentDiagram.png"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/ComponentDiagram.png b/src/doxygen/ComponentDiagram.png
new file mode 100644 (file)
index 0000000..11581a2
Binary files /dev/null and b/src/doxygen/ComponentDiagram.png differ
diff --git a/src/doxygen/DoxyMainPage.txt.in b/src/doxygen/DoxyMainPage.txt.in
new file mode 100644 (file)
index 0000000..c85928d
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * \mainpage creaImageIO documentation
+
+\htmlonly 
+<H2>Architecture Description (v2)</H2>
+<br>
+<a href="Architecture.htm"> Architecture </a>
+<br>
+
+<H2>Diagrams of the architecture</H2>
+<br>
+<a href="ClassDiagram.htm"> Class Diagram </a>
+<br>
+<a href="ComponentDiagram.htm"> Component Diagram </a>
+<br>
+<a href="LayerDiagram.htm"> Layer Diagram </a>
+<br>
+
+<H2>Sequence Diagrams</H2>
+<br>
+<a href="SeqAddFile.htm"> On "Add Files" to a database </a>
+<br>
+<a href="SeqAddDir.htm"> On "Add Directories" to a database </a>
+<br>
+<a href="SeqRemove.htm"> On "Remove Files" from database </a>
+<br>
+<a href="SeqCreateDB.htm"> On "Create a database" </a>
+<br>
+<a href="SeqSelChanged.htm"> On "Selection has changed" </a>
+<br>
+<a href="SeqGetImages.htm"> On "Get Selected Images as VTK structures" </a>
+<br>
+
+\endhtmlonly
+
+
+
+
+         
+ */
\ No newline at end of file
diff --git a/src/doxygen/Doxyfile.txt.in b/src/doxygen/Doxyfile.txt.in
new file mode 100644 (file)
index 0000000..af8e0fb
--- /dev/null
@@ -0,0 +1,1358 @@
+# Doxyfile 1.5.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = @DOXYGEN_PROJECT_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = @PROJECT_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = @DOXYGEN_OUTPUT@
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, 
+# and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+# DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = @DOXYGEN_LOGFILE@
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = @DOXYGEN_INPUT@
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.h \
+                         *.cxx \
+                         *.txx
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = @DOXYGEN_EXCLUDE@
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.cxx
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 3
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = @DOXYGEN_HTML_OUTPUT@
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = @DOXYGEN_DOC_PREDEFINED@
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = @DOXYGEN_HAVE_DOT@
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = "@DOXYGEN_DOT_PATH@"
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is enabled by default, which results in a transparent 
+# background. Warning: Depending on the platform used, enabling this option 
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they 
+# become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/src/doxygen/LayerDiagram.htm b/src/doxygen/LayerDiagram.htm
new file mode 100644 (file)
index 0000000..cd5a33d
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Layer Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>Currently implemented Layer Architecture (includes  GUI less applications and wxWidgets derived applications)</strong></p>
+<img src="LayerDiagram.jpg"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/LayerDiagram.jpg b/src/doxygen/LayerDiagram.jpg
new file mode 100644 (file)
index 0000000..e55caeb
Binary files /dev/null and b/src/doxygen/LayerDiagram.jpg differ
diff --git a/src/doxygen/SeqAddDir.htm b/src/doxygen/SeqAddDir.htm
new file mode 100644 (file)
index 0000000..d094eff
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>Adding a Directory</strong></p>
+<img src="SeqAddDir.png"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/SeqAddDir.png b/src/doxygen/SeqAddDir.png
new file mode 100644 (file)
index 0000000..0c367cf
Binary files /dev/null and b/src/doxygen/SeqAddDir.png differ
diff --git a/src/doxygen/SeqAddFile.htm b/src/doxygen/SeqAddFile.htm
new file mode 100644 (file)
index 0000000..45d7da1
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>Adding a File</strong></p>
+<img src="SeqAddFile.png"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/SeqAddFile.png b/src/doxygen/SeqAddFile.png
new file mode 100644 (file)
index 0000000..dd2929a
Binary files /dev/null and b/src/doxygen/SeqAddFile.png differ
diff --git a/src/doxygen/SeqCreateDB.htm b/src/doxygen/SeqCreateDB.htm
new file mode 100644 (file)
index 0000000..2424392
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>Creating a Database</strong></p>
+<img src="SeqCreateDB.png"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/SeqCreateDB.png b/src/doxygen/SeqCreateDB.png
new file mode 100644 (file)
index 0000000..52ee278
Binary files /dev/null and b/src/doxygen/SeqCreateDB.png differ
diff --git a/src/doxygen/SeqGetImages.htm b/src/doxygen/SeqGetImages.htm
new file mode 100644 (file)
index 0000000..0495671
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>On Get Images</strong></p>
+<img src="SeqGetImages.png"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/SeqGetImages.png b/src/doxygen/SeqGetImages.png
new file mode 100644 (file)
index 0000000..950df62
Binary files /dev/null and b/src/doxygen/SeqGetImages.png differ
diff --git a/src/doxygen/SeqRemove.htm b/src/doxygen/SeqRemove.htm
new file mode 100644 (file)
index 0000000..e8fd222
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>Remove a file</strong></p>
+<img src="SeqRemove.png"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/SeqRemove.png b/src/doxygen/SeqRemove.png
new file mode 100644 (file)
index 0000000..503a753
Binary files /dev/null and b/src/doxygen/SeqRemove.png differ
diff --git a/src/doxygen/SeqSelChanged.htm b/src/doxygen/SeqSelChanged.htm
new file mode 100644 (file)
index 0000000..d3fc8f3
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Language" content="es-co" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Class Diagram</title>
+<style type="text/css">
+.style1 {
+       font-size: x-large;
+}
+</style>
+</head>
+
+<body>
+
+<p class="style1"><strong>On Selection Changed</strong></p>
+<img src="SeqSelChanged.png"/>
+
+</body>
+
+</html>
diff --git a/src/doxygen/SeqSelChanged.png b/src/doxygen/SeqSelChanged.png
new file mode 100644 (file)
index 0000000..3f6a95e
Binary files /dev/null and b/src/doxygen/SeqSelChanged.png differ
diff --git a/src/icons/accept-48x48.png b/src/icons/accept-48x48.png
new file mode 100644 (file)
index 0000000..d929648
Binary files /dev/null and b/src/icons/accept-48x48.png differ
diff --git a/src/icons/accept.xpm b/src/icons/accept.xpm
new file mode 100644 (file)
index 0000000..6f6be66
--- /dev/null
@@ -0,0 +1,824 @@
+/* XPM */
+static const char * accept_xpm[] = {
+"48 48 773 2",
+"      c None",
+".     c #D8DBD9",
+"+     c #D4D5D4",
+"@     c #D4D3D3",
+"#     c #D6D5D5",
+"$     c #D5D4D4",
+"%     c #D3D2D2",
+"&     c #D3D4D2",
+"*     c #D6D9D7",
+"=     c #D5D6D5",
+"-     c #DBDBDB",
+";     c #E5E4E4",
+">     c #ECECEC",
+",     c #F2F2F2",
+"'     c #F5F5F5",
+")     c #F7F7F7",
+"!     c #F8F7F7",
+"~     c #F6F6F6",
+"{     c #F5F4F4",
+"]     c #F0F0F0",
+"^     c #EAE9E9",
+"/     c #E1E1E1",
+"(     c #D7D7D7",
+"_     c #D0D1D0",
+":     c #D9D9D9",
+"<     c #E7E7E7",
+"[     c #F3F3F3",
+"}     c #FAFAFA",
+"|     c #FDFDFD",
+"1     c #F3F9F4",
+"2     c #E0F0E2",
+"3     c #FCFCFC",
+"4     c #F8F8F8",
+"5     c #EFEFEF",
+"6     c #E2E1E1",
+"7     c #D3D3D2",
+"8     c #DADADA",
+"9     c #F9F9F9",
+"0     c #FEFEFE",
+"a     c #FCFDFC",
+"b     c #D7EBDC",
+"c     c #99CEAA",
+"d     c #5CB17B",
+"e     c #28994F",
+"f     c #078938",
+"g     c #008536",
+"h     c #E6E5E5",
+"i     c #D6D7D6",
+"j     c #E8E7E7",
+"k     c #F2F8F3",
+"l     c #A6D5B4",
+"m     c #41A564",
+"n     c #0C8C3E",
+"o     c #008736",
+"p     c #038938",
+"q     c #048939",
+"r     c #058A3A",
+"s     c #008735",
+"t     c #F2F8F4",
+"u     c #E0DFDF",
+"v     c #CDCFCD",
+"w     c #DCDDDC",
+"x     c #F2F1F1",
+"y     c #A9D7B6",
+"z     c #2E9D56",
+"A     c #008836",
+"B     c #018937",
+"C     c #0F9042",
+"D     c #1C964C",
+"E     c #269B54",
+"F     c #2B9E59",
+"G     c #2FA05B",
+"H     c #30A15D",
+"I     c #A9D6B6",
+"J     c #D3D4D3",
+"K     c #E1E0E0",
+"L     c #DFF0E3",
+"M     c #44A866",
+"N     c #008936",
+"O     c #088E3C",
+"P     c #1C984C",
+"Q     c #2DA15A",
+"R     c #32A35E",
+"S     c #31A45D",
+"T     c #32A45E",
+"U     c #31A35D",
+"V     c #2DA05A",
+"W     c #F1F1F1",
+"X     c #D7D6D6",
+"Y     c #E4E3E3",
+"Z     c #B3DBBE",
+"`     c #1C9749",
+" .    c #008A36",
+"..    c #058E3A",
+"+.    c #1B994B",
+"@.    c #2EA25B",
+"#.    c #31A55D",
+"$.    c #32A55E",
+"%.    c #31A65D",
+"&.    c #32A65E",
+"*.    c #32A75E",
+"=.    c #1C9649",
+"-.    c #F3F2F2",
+";.    c #D9D9D8",
+">.    c #E2E2E2",
+",.    c #A1D4AF",
+"'.    c #0B903C",
+").    c #008C36",
+"!.    c #0D9340",
+"~.    c #2AA157",
+"{.    c #31A75D",
+"].    c #31A85D",
+"^.    c #31A95D",
+"/.    c #31AA5D",
+"(.    c #2AA057",
+"_.    c #0B903D",
+":.    c #A0D3B0",
+"<.    c #DFDFDF",
+"[.    c #A0D4AF",
+"}.    c #018D36",
+"|.    c #018E37",
+"1.    c #169847",
+"2.    c #30A55C",
+"3.    c #32A75D",
+"4.    c #32A95D",
+"5.    c #32AA5D",
+"6.    c #31AA5C",
+"7.    c #32AB5D",
+"8.    c #33AB5D",
+"9.    c #34AC5D",
+"0.    c #35AC5D",
+"a.    c #36AC5D",
+"b.    c #37AC5C",
+"c.    c #37AC5D",
+"d.    c #35AC5C",
+"e.    c #32AB5C",
+"f.    c #38AC62",
+"g.    c #36AA61",
+"h.    c #30A45C",
+"i.    c #DADBDA",
+"j.    c #F4F4F4",
+"k.    c #B3DCBF",
+"l.    c #0B923C",
+"m.    c #018F37",
+"n.    c #189B4A",
+"o.    c #30A75C",
+"p.    c #37AD5D",
+"q.    c #3CAD5C",
+"r.    c #40AE5D",
+"s.    c #43AE5D",
+"t.    c #46AF5C",
+"u.    c #47B05D",
+"v.    c #48B05D",
+"w.    c #48B05C",
+"x.    c #47AF5C",
+"y.    c #45AF5D",
+"z.    c #42AE5D",
+"A.    c #3EAE5C",
+"B.    c #3AAD5D",
+"C.    c #39AE5F",
+"D.    c #A8DCBA",
+"E.    c #B0DEC0",
+"F.    c #3BAE65",
+"G.    c #189A4A",
+"H.    c #ECEBEB",
+"I.    c #1D9B49",
+"J.    c #009036",
+"K.    c #169C47",
+"L.    c #30A95C",
+"M.    c #33AC5C",
+"N.    c #37AD5C",
+"O.    c #3EAD5C",
+"P.    c #44AF5C",
+"Q.    c #49B05C",
+"R.    c #4CB05C",
+"S.    c #4EB15C",
+"T.    c #4FB25C",
+"U.    c #51B25C",
+"V.    c #52B35C",
+"W.    c #53B35C",
+"X.    c #51B35C",
+"Y.    c #50B25C",
+"Z.    c #4DB15C",
+"`.    c #4BB05C",
+" +    c #8ECE9C",
+".+    c #BCE3CA",
+"++    c #3CB065",
+"@+    c #30A85C",
+"#+    c #169B47",
+"$+    c #008F36",
+"%+    c #1C9A49",
+"&+    c #FBFBFB",
+"*+    c #45AD66",
+"=+    c #009236",
+"-+    c #0D9A40",
+";+    c #30AA5B",
+">+    c #33AC5D",
+",+    c #43AE5C",
+"'+    c #49B05D",
+")+    c #56B45B",
+"!+    c #58B45C",
+"~+    c #5AB55C",
+"{+    c #5BB65B",
+"]+    c #5CB65C",
+"^+    c #5DB65C",
+"/+    c #5DB75B",
+"(+    c #5DB75C",
+"_+    c #5CB65B",
+":+    c #5BB65C",
+"<+    c #59B55C",
+"[+    c #57B45B",
+"}+    c #7DC583",
+"|+    c #F6FBF7",
+"1+    c #FFFFFF",
+"2+    c #D1ECDA",
+"3+    c #47B36B",
+"4+    c #30A95B",
+"5+    c #0D9940",
+"6+    c #009136",
+"7+    c #44AC66",
+"8+    c #A9DAB6",
+"9+    c #009336",
+"0+    c #059739",
+"a+    c #2AA856",
+"b+    c #39AD5D",
+"c+    c #4AB05D",
+"d+    c #56B45C",
+"e+    c #5CB75C",
+"f+    c #5EB75B",
+"g+    c #60B85B",
+"h+    c #62B95B",
+"i+    c #63B95B",
+"j+    c #64BA5B",
+"k+    c #65BA5B",
+"l+    c #61B95B",
+"m+    c #6FBF6B",
+"n+    c #EAF6EA",
+"o+    c #D8EEDF",
+"p+    c #58B974",
+"q+    c #2AA756",
+"r+    c #A9D9B6",
+"s+    c #E1E1E0",
+"t+    c #F2F9F3",
+"u+    c #2EA755",
+"v+    c #009635",
+"w+    c #1EA34A",
+"x+    c #3FAE5C",
+"y+    c #5FB75B",
+"z+    c #66BB5A",
+"A+    c #68BC5A",
+"B+    c #69BC5A",
+"C+    c #6BBD5A",
+"D+    c #6CBD5A",
+"E+    c #6CBD5B",
+"F+    c #6CBE5B",
+"G+    c #6ABD5A",
+"H+    c #6CBE5F",
+"I+    c #CFEACB",
+"J+    c #B7E0C5",
+"K+    c #3AAA58",
+"L+    c #3AAD5C",
+"M+    c #1CA24A",
+"N+    c #009535",
+"O+    c #2EA656",
+"P+    c #A5D9B3",
+"Q+    c #009634",
+"R+    c #109C3B",
+"S+    c #42AE5A",
+"T+    c #4CB15C",
+"U+    c #57B45C",
+"V+    c #5FB85B",
+"W+    c #69BC5B",
+"X+    c #6BBD5B",
+"Y+    c #6DBE5B",
+"Z+    c #6FBF5C",
+"`+    c #71BF5D",
+" @    c #72C05E",
+".@    c #73C05F",
+"+@    c #74C05F",
+"@@    c #72BF5E",
+"#@    c #AFDBA4",
+"$@    c #E7F5ED",
+"%@    c #29A35C",
+"&@    c #31A551",
+"*@    c #4AB05C",
+"=@    c #3DAD5A",
+"-@    c #0C9B3B",
+";@    c #A5D9B4",
+">@    c #42B163",
+",@    c #109B34",
+"'@    c #33A74B",
+")@    c #54B35C",
+"!@    c #66BB5B",
+"~@    c #6ABD5B",
+"{@    c #70BF5D",
+"]@    c #74C060",
+"^@    c #75C161",
+"/@    c #76C162",
+"(@    c #78C163",
+"_@    c #78C263",
+":@    c #79C264",
+"<@    c #92CE81",
+"[@    c #F5FBF4",
+"}@    c #FBFDFC",
+"|@    c #53B57D",
+"1@    c #25A04A",
+"2@    c #52B25C",
+"3@    c #2FA64B",
+"4@    c #0B9A34",
+"5@    c #40B063",
+"6@    c #E6E6E5",
+"7@    c #D8EEDB",
+"8@    c #1B9E3C",
+"9@    c #52B02E",
+"0@    c #4EB158",
+"a@    c #65BB5B",
+"b@    c #77C162",
+"c@    c #7BC366",
+"d@    c #7DC467",
+"e@    c #7EC468",
+"f@    c #7FC469",
+"g@    c #80C46A",
+"h@    c #7FC46A",
+"i@    c #82C66D",
+"j@    c #E5F3E0",
+"k@    c #FEFFFE",
+"l@    c #91D0AC",
+"m@    c #159A44",
+"n@    c #5DB759",
+"o@    c #5AB55B",
+"p@    c #4BB058",
+"q@    c #4CAE2F",
+"r@    c #149D3D",
+"s@    c #D7EEDC",
+"t@    c #EFEEEE",
+"u@    c #A1D6A9",
+"v@    c #26A033",
+"w@    c #7CC034",
+"x@    c #75C056",
+"y@    c #67BC5A",
+"z@    c #76C161",
+"A@    c #81C56B",
+"B@    c #83C66D",
+"C@    c #84C66D",
+"D@    c #84C76E",
+"E@    c #83C66C",
+"F@    c #84C76D",
+"G@    c #C4E4B9",
+"H@    c #C6E6D4",
+"I@    c #129949",
+"J@    c #5EB757",
+"K@    c #61B85B",
+"L@    c #73BF56",
+"M@    c #76BE35",
+"N@    c #219E33",
+"O@    c #9ED5A9",
+"P@    c #F6F5F5",
+"Q@    c #6FC079",
+"R@    c #3CA830",
+"S@    c #8BC63D",
+"T@    c #94CC50",
+"U@    c #6EBE5B",
+"V@    c #75C160",
+"W@    c #7DC468",
+"X@    c #7EC469",
+"Y@    c #82C56A",
+"Z@    c #7DC364",
+"`@    c #79C05E",
+" #    c #76BF5A",
+".#    c #75BE57",
+"+#    c #75BD57",
+"@#    c #91CB7A",
+"##    c #F8FCF7",
+"$#    c #ECF7F1",
+"%#    c #31A663",
+"&#    c #47AE53",
+"*#    c #67BB5B",
+"=#    c #68BB5A",
+"-#    c #86C43E",
+";#    c #37A631",
+">#    c #6DBF7A",
+",#    c #47AD4E",
+"'#    c #51AF2E",
+")#    c #93CA45",
+"!#    c #9CCF4F",
+"~#    c #88C853",
+"{#    c #6EBE5C",
+"]#    c #7AC265",
+"^#    c #97D086",
+"/#    c #CBE7C2",
+"(#    c #86C772",
+"_#    c #7EC364",
+":#    c #76BE5A",
+"<#    c #73BD54",
+"[#    c #74BD54",
+"}#    c #75BD55",
+"|#    c #76BE56",
+"1#    c #77BE56",
+"2#    c #77BE57",
+"3#    c #7ABF5B",
+"4#    c #DCEED3",
+"5#    c #6CC090",
+"6#    c #2BA24D",
+"7#    c #7AC266",
+"8#    c #71C05E",
+"9#    c #87C753",
+"0#    c #8EC846",
+"a#    c #4CAD2F",
+"b#    c #44AC4E",
+"c#    c #D7DAD7",
+"d#    c #E3E3E3",
+"e#    c #33A436",
+"f#    c #62B52E",
+"g#    c #97CC4A",
+"h#    c #9BCE4E",
+"i#    c #9BCE4F",
+"j#    c #83C659",
+"k#    c #D9EDD3",
+"l#    c #D6EDD5",
+"m#    c #7CC161",
+"n#    c #74BC54",
+"o#    c #76BD56",
+"p#    c #79BE57",
+"q#    c #7BBF59",
+"r#    c #7CBF5A",
+"s#    c #7EC15B",
+"t#    c #7FC15B",
+"u#    c #7FC15C",
+"v#    c #B5DBA1",
+"w#    c #FEFEFD",
+"x#    c #BBE2CC",
+"y#    c #109743",
+"z#    c #76C168",
+"A#    c #82C56C",
+"B#    c #82C558",
+"C#    c #94CB4A",
+"D#    c #5CB32F",
+"E#    c #2FA236",
+"F#    c #F5FAF4",
+"G#    c #35A533",
+"H#    c #6BB92D",
+"I#    c #99CD4C",
+"J#    c #9ACE4F",
+"K#    c #84C661",
+"L#    c #80C56A",
+"M#    c #9FD38E",
+"N#    c #FDFEFD",
+"O#    c #D9EED7",
+"P#    c #87C56C",
+"Q#    c #7DC05B",
+"R#    c #80C15C",
+"S#    c #82C25E",
+"T#    c #84C35F",
+"U#    c #85C460",
+"V#    c #86C460",
+"W#    c #93CA71",
+"X#    c #F6FBF3",
+"Y#    c #EAF6EF",
+"Z#    c #2BA35E",
+"`#    c #4DAE4C",
+" $    c #75BE59",
+".$    c #81C569",
+"+$    c #82C66C",
+"@$    c #82C55F",
+"#$    c #97CC4D",
+"$$    c #66B72F",
+"%$    c #31A334",
+"&$    c #E4E4E4",
+"*$    c #E5F3E2",
+"=$    c #3AA733",
+"-$    c #70BB2D",
+";$    c #9ACE4E",
+">$    c #99CE51",
+",$    c #8CCA6A",
+"'$    c #DCEFD5",
+")$    c #E4F3E2",
+"!$    c #91CA75",
+"~$    c #87C561",
+"{$    c #89C662",
+"]$    c #8BC763",
+"^$    c #8DC864",
+"/$    c #8EC966",
+"($    c #D2E9C2",
+"_$    c #FEFFFF",
+":$    c #6FC192",
+"<$    c #29A047",
+"[$    c #72BC54",
+"}$    c #7EC466",
+"|$    c #89C866",
+"1$    c #98CD4E",
+"2$    c #6BB92F",
+"3$    c #37A633",
+"4$    c #E6F3E2",
+"5$    c #40AA32",
+"6$    c #72BB2D",
+"7$    c #B3DA7A",
+"8$    c #EFF8EE",
+"9$    c #9ED182",
+"0$    c #91CA66",
+"a$    c #93CB67",
+"b$    c #95CB69",
+"c$    c #AED88C",
+"d$    c #FCFDFA",
+"e$    c #B7E0C9",
+"f$    c #179A47",
+"g$    c #75BD5B",
+"h$    c #7EC05B",
+"i$    c #7ABE58",
+"j$    c #78BE43",
+"k$    c #90C940",
+"l$    c #98CD4F",
+"m$    c #6CBA2F",
+"n$    c #3DA833",
+"o$    c #E3E2E2",
+"p$    c #45AC32",
+"q$    c #99CD4D",
+"r$    c #94CA41",
+"s$    c #DDEEC4",
+"t$    c #F1F8F0",
+"u$    c #AED892",
+"v$    c #9BCE6C",
+"w$    c #9FD071",
+"x$    c #E6F3DA",
+"y$    c #F2F9F5",
+"z$    c #28A25B",
+"A$    c #5CB557",
+"B$    c #80C159",
+"C$    c #7EC03D",
+"D$    c #82C025",
+"E$    c #84C226",
+"F$    c #93CA40",
+"G$    c #6AB92E",
+"H$    c #42AB32",
+"I$    c #4EB036",
+"J$    c #6CBA2E",
+"K$    c #9BCF4F",
+"L$    c #97CC47",
+"M$    c #85C227",
+"N$    c #A3D160",
+"O$    c #F4FAF1",
+"P$    c #F5FAF5",
+"Q$    c #B8DD9D",
+"R$    c #C2E1A2",
+"S$    c #7AC69B",
+"T$    c #33A54C",
+"U$    c #91CA67",
+"V$    c #8FC965",
+"W$    c #88C550",
+"X$    c #83C12F",
+"Y$    c #83C124",
+"Z$    c #82C023",
+"`$    c #95CB4A",
+" %    c #67B82F",
+".%    c #4BAE35",
+"+%    c #D5D5D4",
+"@%    c #E9E9E9",
+"#%    c #FBFAFA",
+"$%    c #67BA50",
+"%%    c #66B730",
+"&%    c #9ACD4C",
+"*%    c #88C42D",
+"=%    c #97CC57",
+"-%    c #F3F9EF",
+";%    c #F6FBF4",
+">%    c #CFEADB",
+",%    c #159A4A",
+"'%    c #8BC864",
+")%    c #92C953",
+"!%    c #87C334",
+"~%    c #90C946",
+"{%    c #61B631",
+"]%    c #64B94E",
+"^%    c #DADCD9",
+"/%    c #8ECC7C",
+"(%    c #60B636",
+"_%    c #8DC73D",
+":%    c #90C83A",
+"<%    c #9ACD5A",
+"[%    c #F0F8EA",
+"}%    c #FAFDFB",
+"|%    c #4BB176",
+"1%    c #48AC37",
+"2%    c #86C22C",
+"3%    c #88C53F",
+"4%    c #5DB435",
+"5%    c #8DCB7C",
+"6%    c #B8DFAC",
+"7%    c #5EB53E",
+"8%    c #82C235",
+"9%    c #98CD4A",
+"0%    c #85C228",
+"a%    c #98CD57",
+"b%    c #F0F8EC",
+"c%    c #A9DABE",
+"d%    c #1C9B3C",
+"e%    c #7CBE25",
+"f%    c #7CC036",
+"g%    c #5BB43C",
+"h%    c #B7DEAB",
+"i%    c #E2F1DD",
+"j%    c #66B84B",
+"k%    c #73BC31",
+"l%    c #8CC636",
+"m%    c #93CA4C",
+"n%    c #EEF7E9",
+"o%    c #F1F9F5",
+"p%    c #209F53",
+"q%    c #5FB42B",
+"r%    c #8AC537",
+"s%    c #6EBA32",
+"t%    c #63B748",
+"u%    c #E2F1DC",
+"v%    c #E4E4E3",
+"w%    c #FDFDFC",
+"x%    c #86C770",
+"y%    c #6CBA3E",
+"z%    c #7FBF25",
+"A%    c #96CB50",
+"B%    c #EBF5E4",
+"C%    c #FDFEFE",
+"D%    c #2EA234",
+"E%    c #80C024",
+"F%    c #82C024",
+"G%    c #7ABE26",
+"H%    c #68B83D",
+"I%    c #84C66F",
+"J%    c #D6D6D5",
+"K%    c #C6E4BA",
+"L%    c #6BBA4C",
+"M%    c #79BD2A",
+"N%    c #95CB4D",
+"O%    c #EBF6E6",
+"P%    c #D8EEE2",
+"Q%    c #159A48",
+"R%    c #73BB27",
+"S%    c #80BF24",
+"T%    c #73BB2C",
+"U%    c #68B94A",
+"V%    c #C4E4BA",
+"W%    c #F6FAF4",
+"X%    c #84C56A",
+"Y%    c #75BC41",
+"Z%    c #7EBF25",
+"`%    c #8FC843",
+" &    c #E9F5E3",
+".&    c #58B780",
+"+&    c #42A930",
+"@&    c #7ABD26",
+"#&    c #71BB41",
+"$&    c #81C469",
+"%&    c #DAD9D9",
+"&&    c #F7F6F6",
+"*&    c #CBE6BE",
+"=&    c #76BD54",
+"-&    c #7ABE31",
+";&    c #81C024",
+">&    c #92C948",
+",&    c #E6F3DD",
+"'&    c #C0E4D0",
+")&    c #1A9B41",
+"!&    c #78BD25",
+"~&    c #7EBF24",
+"{&    c #75BC32",
+"]&    c #74BC52",
+"^&    c #C9E5BE",
+"/&    c #98CE7D",
+"(&    c #7DC050",
+"_&    c #7CBE28",
+":&    c #91C845",
+"<&    c #E5F3DE",
+"[&    c #3EAC6D",
+"}&    c #4EAE2E",
+"|&    c #77BD29",
+"1&    c #79BE4F",
+"2&    c #95CC7C",
+"3&    c #ECF5E7",
+"4&    c #8CC86B",
+"5&    c #80C149",
+"6&    c #7DBF25",
+"7&    c #8CC63C",
+"8&    c #E3F2DB",
+"9&    c #AADABF",
+"0&    c #1C9B38",
+"a&    c #7DBF24",
+"b&    c #7CC049",
+"c&    c #8AC669",
+"d&    c #EBF5E7",
+"e&    c #D5EBC9",
+"f&    c #8BC765",
+"g&    c #82C243",
+"h&    c #8EC740",
+"i&    c #D1EACA",
+"j&    c #2EA560",
+"k&    c #5EB32B",
+"l&    c #7BBE26",
+"m&    c #7EC144",
+"n&    c #89C564",
+"o&    c #D4EAC9",
+"p&    c #D8D8D6",
+"q&    c #E9E9E8",
+"r&    c #CEE7BE",
+"s&    c #8FC964",
+"t&    c #86C445",
+"u&    c #7DBF2F",
+"v&    c #3DA731",
+"w&    c #82C346",
+"x&    c #8CC863",
+"y&    c #CDE6BD",
+"z&    c #DDDDDC",
+"A&    c #D1E8BF",
+"B&    c #99CE6D",
+"C&    c #8EC851",
+"D&    c #7DBF29",
+"E&    c #7FBF24",
+"F&    c #7ABE2A",
+"G&    c #8AC650",
+"H&    c #97CD6C",
+"I&    c #D0E8BF",
+"J&    c #EEEEED",
+"K&    c #DBEDCC",
+"L&    c #A5D37A",
+"M&    c #97CC5F",
+"N&    c #81C135",
+"O&    c #7CBE26",
+"P&    c #7FC136",
+"Q&    c #95CB5F",
+"R&    c #A3D278",
+"S&    c #DAEDCC",
+"T&    c #EFF7E9",
+"U&    c #B3DA8E",
+"V&    c #9FD06D",
+"W&    c #90C951",
+"X&    c #7EC02D",
+"Y&    c #7DBE25",
+"Z&    c #7BBF2E",
+"`&    c #B2DA8D",
+" *    c #D9ECC7",
+".*    c #AED884",
+"+*    c #A2D26F",
+"@*    c #93CA55",
+"#*    c #85C33A",
+"$*    c #7DBF28",
+"%*    c #7BBE29",
+"&*    c #83C33B",
+"**    c #91CA56",
+"=*    c #ADD784",
+"-*    c #D8ECC7",
+";*    c #E0E0DF",
+">*    c #F8FBF5",
+",*    c #D9EDC7",
+"'*    c #B6DB8F",
+")*    c #A8D476",
+"!*    c #A2D16A",
+"~*    c #97CC5A",
+"{*    c #8EC84A",
+"]*    c #87C43E",
+"^*    c #82C236",
+"/*    c #80C132",
+"(*    c #8DC84A",
+"_*    c #A1D16A",
+":*    c #A7D475",
+"<*    c #B5DB8F",
+"[*    c #DCDCDA",
+"}*    c #ECF5E3",
+"|*    c #D5EABF",
+"1*    c #C2E1A0",
+"2*    c #AED77F",
+"3*    c #A7D473",
+"4*    c #AAD575",
+"5*    c #AAD574",
+"6*    c #ADD77F",
+"7*    c #EEF6E7",
+"8*    c #E6E6E6",
+"                                        . + @ # $ % & *                                         ",
+"                                = - ; > , ' ) ! ! ~ { ] ^ / ( _                                 ",
+"                            : < [ } | | | | 1 2 2 1 | | | 3 4 5 6 7                             ",
+"                        8 > 9 0 a b c d e f g g g g f e d c b a | ' h %                         ",
+"                    i j 4 | k l m n o o o p q r r q p o o s n m l t 3 [ u v                     ",
+"                  w x 3 | y z s A B C D E F G H H G F E D C B A s z I | } ^ J                   ",
+"                K 4 0 L M N N O P Q R R S T T S T T S T R U V P O N A M L | W X                 ",
+"              Y 9 | Z `  ...+.@.S #.$.$.%.&.&.%.*.&.%.$.$.#.$.S @.+... .=.Z | -.;.              ",
+"            >.9 | ,.'.).!.~.#.%.{.{.].^.^././././././.^.^.].{.%.#.S (.!.)._.:.| -.X             ",
+"          <.9 | [.}.|.1.2.3.].4.5.6.7.8.9.0.a.b.c.a.d.9.8.e.5.5.f.g.*.h.1.|.}.[.| W J           ",
+"        i.j.0 k.l.m.n.o.^.5.e.9.p.q.r.s.t.u.v.w.v.v.x.y.z.A.B.C.D.E.F.4.o.G.|.l.k.| ^ v         ",
+"        H.| L I.J.K.L./.M.N.O.P.Q.R.S.T.U.V.W.W.W.W.X.Y.T.Z.`. +a 0 .+++/.@+#+$+%+L } u         ",
+"      u &+| *+=+-+;+>+B.,+'+Z.Y.W.)+!+~+{+]+^+/+(+^+_+:+<+[+}+|+1+0 1+2+3+7.4+5+6+7+| [ %       ",
+"      , | 8+9+0+a+b+s.c+S.V.d+<+e+f+g+h+i+j+j+k+j+j+j+h+l+m+n+1+1+0 1+1+o+p+a.q+0+=+r+3 h       ",
+"    s+3 t+u+v+w+x+Q.S.W.[+{+y+l+j+z+A+B+C+D+E+F+F+D+C+G+H+I+0 0 0 0 0 0 0 J+K+L+M+N+O+t+' 7     ",
+"    5 0 P+Q+R+S+T+V.U+]+V+i+z+W+X+Y+Z+`+ @.@.@+@+@.@.@@@#@0 1+1+1+0 1+1+$@%@&@*@=@-@v+;@| 6     ",
+"  <.9 a >@,@'@S.)@~+V+i+!@~@Y+{@ @]@^@/@(@_@:@:@:@:@_@<@[@0 1+1+1+0 1+}@|@1@[+2@T+3@4@5@a 5 _   ",
+"  6@| 7@8@9@0@d+_+l+a@W+Y+`+.@^@b@:@c@d@e@f@g@h@g@h@i@j@1+0 1+1+1+0 k@l@m@n@V+o@)@p@q@r@s@4 (   ",
+"  t@| u@v@w@x@f+h+y@E+{@.@z@_@c@e@g@A@B@C@D@C@B@E@F@G@0 0 0 0 0 0 0 H@I@J@~@z+K@{+L@M@N@O@3 /   ",
+"  P@| Q@R@S@T@B+B+U@ @V@:@W@X@A@B@F@Y@Z@`@ #.#+#+#@###1+1+0 1+1+1+$#%#&#]@{@E+*#=#T@-#;#>#| ^   ",
+"< 9 | ,#'#)#!#~#{#.@z@]#^#/#(#F@_#:#<#[#}#|#1#2#3#4#0 1+1+0 1+1+1+5#6#7#_@V@8#Y+9#!#0#a#b#| ] c#",
+"d#3 | e#f#g#h#i#j#b@c@h@k#0 l#m#n#o#p#q#r#s#t#u#v#w#0 0 0 0 0 0 x#y#z#A#e@]#z@B#i#h#C#D#E#| { & ",
+"6 3 F#G#H#I#!#!#J#K#L#M#N#1+0 O#P#Q#R#S#T#U#V#W#X#1+0 1+1+0 1+Y#Z#`# $.$+$f@@$J#!#!##$$$%$F#~ % ",
+"&$| *$=$-$;$!#!#h#>$,$'$0 1+0 1+)$!$~${$]$^$/$($1+1+0 1+1+0 _$:$<$2#n#[$}$|$>$h#!#!#1$2$3$)$! $ ",
+"; 3 4$5$6$;$h#h#h#h#7$N#0 0 0 0 0 8$9$0$a$b$c$d$0 0 0 0 0 0 e$f$g$h$i$}#j$k$h#h#h#h#l$m$n$*$! # ",
+"o$3 F#p$-$q$!#!#h#r$s$1+0 1+0 1+1+0 t$u$v$w$x$0 1+1+0 1+1+y$z$A${$T#B$C$D$E$F$h#!#!##$G$H$F#) @ ",
+"; 3 | I$J$g#!#K$L$M$N$O$0 1+0 1+1+0 1+P$Q$R$N#0 1+1+0 1+0 S$T$U$V$W$X$Y$Z$Y$M$L$K$!#`$ %.%| ' +%",
+"@%#%| $%%%)#h#&%*%Z$Z$=%-%0 0 0 0 0 0 0 a ;%0 0 0 0 0 0 >%,%'%)%!%Z$Z$Z$Z$Z$Z$*%&%h#~%{%]%| , ^%",
+"  ) | /%(%_%h#:%Y$Y$Y$Y$<%[%0 1+1+0 1+1+0 1+1+0 1+1+0 }%|%1%2%Y$Y$Z$Y$Y$Z$Y$Y$Y$:%h#3%4%5%| >   ",
+"  , | 6%7%8%9%0%Z$Y$Y$Y$Z$a%b%1+1+0 1+1+0 1+1+0 1+1+0 c%d%e%Y$Y$Y$Z$Y$Y$Z$Y$Y$Z$0%g#f%g%h%| ;   ",
+"  ^ | i%j%k%l%Z$Z$Z$Z$Z$Z$Z$m%n%0 0 0 0 0 0 0 0 0 0 o%p%q%Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$r%s%t%u%} -   ",
+"  v%&+w%x%y%z%Y$Z$Y$Y$Y$Z$Y$Z$A%B%0 1+1+0 1+1+0 1+C%S$D%E%Z$Y$Y$Y$Z$Y$Y$Z$Y$Y$Z$F%G%H%I%w%[ J%  ",
+"    j.0 K%L%M%F%Z$Y$Y$Y$Z$Y$Z$Y$N%O%1+1+0 1+1+0 1+P%Q%R%Y$Z$Y$Y$Y$Z$Y$Y$Z$Y$Y$Z$S%T%U%V%0 <     ",
+"    < | W%X%Y%Z%Z$Z$Z$Z$Z$Z$Z$Z$Z$`% &0 0 0 0 0 N#.&+&Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$F%@&#&$&W%9 %&    ",
+"      &&0 *&=&-&;&Y$Y$Y$Z$Y$Z$Y$Y$Z$>&,&0 1+1+0 '&)&!&Y$Y$Z$Y$Y$Y$Z$Y$Y$Z$Y$Y$~&{&]&^&| >       ",
+"      < | | /&(&_&Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$:&<&0 0 0 [&}&Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$;&|&1&2&| 4 8       ",
+"        -.| 3&4&5&6&F%Y$Z$Y$Z$Y$Y$Z$Y$Y$7&8&1+9&0&a&Z$Y$Y$Z$Y$Y$Y$Z$Y$Y$Z$;&G%b&c&d&3 j         ",
+"        v%9 0 e&f&g&Z%F%Z$Y$Z$Y$Y$Z$Y$Y$Z$h&i&j&k&Y$Z$Y$Y$Z$Y$Y$Y$Z$Y$Y$;&l&m&n&o&0 x p&        ",
+"          q&3 | r&s&t&6&Z$Y$Z$Y$Y$Z$Y$Y$Z$Y$u&v&F%Y$Z$Y$Y$Z$Y$Y$Y$Z$Y$;&@&w&x&y&| 4 z&          ",
+"            > 3 | A&B&C&D&;&Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$Z$E&F&G&H&I&| 9 K             ",
+"              J&3 | K&L&M&N&Z%F%Y$Z$Y$Y$Z$Y$Y$Z$Y$Y$Z$Y$Y$Z$Y$F%;&O&P&Q&R&S&| 9 Y               ",
+"                > 3 0 T&U&V&W&X&~&;&Y$Y$Z$Y$Y$Z$Y$Y$Z$Y$Y$Z$;&Y&Z&C&V&`&T&0 9 >.                ",
+"                  @%9 | |  *.*+*@*#*$*~&S%;&;&F%F%;&;&E&Y&%*&***+*=*-*| | j.;*                  ",
+"                    v%-.| 0 >*,*'*)*!*~*{*]*^*/*/*^*-#(*~*_*:*<*,*>*| &+H.[*                    ",
+"                        < &&| 0 | }*|*1*2*3*4*4*4*5*3*6*1*|*}*| 0 3 , u                         ",
+"                            < j.&+| | | | | >*7*7*>*| | | | | 9 5 6                             ",
+"                                &$^ , ) #%3 3 3 | 3 3 9 P@t@8*u                                 ",
+"                                        @%; o$; &$6 d#<                                         "};
diff --git a/src/icons/add-48x48.jpg b/src/icons/add-48x48.jpg
new file mode 100644 (file)
index 0000000..1bb9063
Binary files /dev/null and b/src/icons/add-48x48.jpg differ
diff --git a/src/icons/add-48x48.png b/src/icons/add-48x48.png
new file mode 100644 (file)
index 0000000..2dc3e3e
Binary files /dev/null and b/src/icons/add-48x48.png differ
diff --git a/src/icons/add.xpm b/src/icons/add.xpm
new file mode 100644 (file)
index 0000000..c752ba4
--- /dev/null
@@ -0,0 +1,687 @@
+/* XPM */
+static const char * add_xpm[] = {
+"48 48 636 2",
+"      c None",
+".     c #D8DBD9",
+"+     c #D4D5D4",
+"@     c #D4D3D3",
+"#     c #D6D5D5",
+"$     c #D5D4D4",
+"%     c #D3D2D2",
+"&     c #D3D4D2",
+"*     c #D6D9D7",
+"=     c #D5D6D5",
+"-     c #DBDBDB",
+";     c #E5E4E4",
+">     c #ECECEC",
+",     c #F2F2F2",
+"'     c #F5F5F5",
+")     c #F7F7F7",
+"!     c #F8F7F7",
+"~     c #F6F6F6",
+"{     c #F5F4F4",
+"]     c #F0F0F0",
+"^     c #EAE9E9",
+"/     c #E1E1E1",
+"(     c #D7D7D7",
+"_     c #D0D1D0",
+":     c #D9D9D9",
+"<     c #E7E7E7",
+"[     c #F3F3F3",
+"}     c #FAFAFA",
+"|     c #FDFDFD",
+"1     c #F3F9F4",
+"2     c #E0F0E2",
+"3     c #FCFCFC",
+"4     c #F8F8F8",
+"5     c #EFEFEF",
+"6     c #E2E1E1",
+"7     c #D3D3D2",
+"8     c #DADADA",
+"9     c #F9F9F9",
+"0     c #FEFEFE",
+"a     c #FCFDFC",
+"b     c #D7EBDC",
+"c     c #99CEAA",
+"d     c #5CB17B",
+"e     c #28994F",
+"f     c #078938",
+"g     c #008536",
+"h     c #E6E5E5",
+"i     c #D6D7D6",
+"j     c #E8E7E7",
+"k     c #F2F8F3",
+"l     c #A6D5B4",
+"m     c #41A564",
+"n     c #0C8C3E",
+"o     c #008736",
+"p     c #038938",
+"q     c #048939",
+"r     c #058A3A",
+"s     c #008735",
+"t     c #F2F8F4",
+"u     c #E0DFDF",
+"v     c #CDCFCD",
+"w     c #DCDDDC",
+"x     c #F2F1F1",
+"y     c #A9D7B6",
+"z     c #2E9D56",
+"A     c #008836",
+"B     c #018937",
+"C     c #0F9042",
+"D     c #1C964C",
+"E     c #269B54",
+"F     c #2B9E59",
+"G     c #2FA05B",
+"H     c #30A15D",
+"I     c #A9D6B6",
+"J     c #D3D4D3",
+"K     c #E1E0E0",
+"L     c #DFF0E3",
+"M     c #44A866",
+"N     c #008936",
+"O     c #088E3C",
+"P     c #1C984C",
+"Q     c #2DA15A",
+"R     c #32A35E",
+"S     c #31A45D",
+"T     c #32A45E",
+"U     c #31A35D",
+"V     c #2DA05A",
+"W     c #F1F1F1",
+"X     c #D7D6D6",
+"Y     c #E4E3E3",
+"Z     c #B3DBBE",
+"`     c #1C9749",
+" .    c #008A36",
+"..    c #058E3A",
+"+.    c #1B994B",
+"@.    c #2EA25B",
+"#.    c #31A55D",
+"$.    c #32A55E",
+"%.    c #31A65D",
+"&.    c #32A65E",
+"*.    c #32A75E",
+"=.    c #1C9649",
+"-.    c #F3F2F2",
+";.    c #D9D9D8",
+">.    c #E2E2E2",
+",.    c #A1D4AF",
+"'.    c #0B903C",
+").    c #008C36",
+"!.    c #0D9340",
+"~.    c #2AA157",
+"{.    c #31A75D",
+"].    c #31A85D",
+"^.    c #31A95D",
+"/.    c #31AA5D",
+"(.    c #2AA057",
+"_.    c #0B903D",
+":.    c #A0D3B0",
+"<.    c #DFDFDF",
+"[.    c #A0D4AF",
+"}.    c #018D36",
+"|.    c #018E37",
+"1.    c #169847",
+"2.    c #30A55C",
+"3.    c #32A75D",
+"4.    c #32A95D",
+"5.    c #32AA5D",
+"6.    c #31AA5C",
+"7.    c #32AB5D",
+"8.    c #33AB5D",
+"9.    c #6DC38B",
+"0.    c #B2DFC2",
+"a.    c #5BBA80",
+"b.    c #23A454",
+"c.    c #32AB5C",
+"d.    c #30A45C",
+"e.    c #DADBDA",
+"f.    c #F4F4F4",
+"g.    c #B3DCBF",
+"h.    c #0B923C",
+"i.    c #018F37",
+"j.    c #189B4A",
+"k.    c #30A75C",
+"l.    c #34AC5D",
+"m.    c #37AD5D",
+"n.    c #3CAD5C",
+"o.    c #40AE5D",
+"p.    c #43AE5D",
+"q.    c #9AD3A6",
+"r.    c #FFFFFF",
+"s.    c #73C395",
+"t.    c #23A04E",
+"u.    c #3EAE5C",
+"v.    c #3AAD5D",
+"w.    c #36AC5D",
+"x.    c #33AC5D",
+"y.    c #189A4A",
+"z.    c #ECEBEB",
+"A.    c #1D9B49",
+"B.    c #009036",
+"C.    c #169C47",
+"D.    c #30A95C",
+"E.    c #33AC5C",
+"F.    c #37AD5C",
+"G.    c #3EAD5C",
+"H.    c #44AF5C",
+"I.    c #49B05C",
+"J.    c #4CB05C",
+"K.    c #4EB15C",
+"L.    c #4FB25C",
+"M.    c #A0D5A6",
+"N.    c #2AA24E",
+"O.    c #4DB15C",
+"P.    c #4BB05C",
+"Q.    c #47AF5C",
+"R.    c #42AE5C",
+"S.    c #3BAD5C",
+"T.    c #35AC5C",
+"U.    c #30A85C",
+"V.    c #169B47",
+"W.    c #008F36",
+"X.    c #1C9A49",
+"Y.    c #FBFBFB",
+"Z.    c #45AD66",
+"`.    c #009236",
+" +    c #0D9A40",
+".+    c #30AA5B",
+"++    c #43AE5C",
+"@+    c #49B05D",
+"#+    c #50B25C",
+"$+    c #53B35C",
+"%+    c #56B45B",
+"&+    c #58B45C",
+"*+    c #5AB55C",
+"=+    c #A5D7A6",
+"-+    c #2FA44D",
+";+    c #57B45B",
+">+    c #55B35C",
+",+    c #52B35C",
+"'+    c #4CB15C",
+")+    c #47AF5D",
+"!+    c #37AC5C",
+"~+    c #30A95B",
+"{+    c #0D9940",
+"]+    c #009136",
+"^+    c #44AC66",
+"/+    c #A9DAB6",
+"(+    c #009336",
+"_+    c #059739",
+":+    c #2AA856",
+"<+    c #39AD5D",
+"[+    c #4AB05D",
+"}+    c #56B45C",
+"|+    c #59B55C",
+"1+    c #5CB75C",
+"2+    c #5EB75B",
+"3+    c #60B85B",
+"4+    c #62B95B",
+"5+    c #AAD9A5",
+"6+    c #33A64D",
+"7+    c #5BB65C",
+"8+    c #58B55C",
+"9+    c #51B25C",
+"0+    c #3FAE5D",
+"a+    c #2AA756",
+"b+    c #A9D9B6",
+"c+    c #E1E1E0",
+"d+    c #F2F9F3",
+"e+    c #2EA755",
+"f+    c #009635",
+"g+    c #1EA34A",
+"h+    c #3FAE5C",
+"i+    c #5BB65B",
+"j+    c #5FB75B",
+"k+    c #61B95B",
+"l+    c #64BA5B",
+"m+    c #66BB5A",
+"n+    c #68BC5A",
+"o+    c #69BC5A",
+"p+    c #AEDBA5",
+"q+    c #37A84D",
+"r+    c #67BB5A",
+"s+    c #65BB5B",
+"t+    c #63B95B",
+"u+    c #5AB55B",
+"v+    c #55B45C",
+"w+    c #46AF5C",
+"x+    c #3AAD5C",
+"y+    c #1CA24A",
+"z+    c #009535",
+"A+    c #2EA656",
+"B+    c #A5D9B3",
+"C+    c #009634",
+"D+    c #109C3B",
+"E+    c #42AE5A",
+"F+    c #57B45C",
+"G+    c #5CB65C",
+"H+    c #5FB85B",
+"I+    c #69BC5B",
+"J+    c #6BBD5B",
+"K+    c #6DBE5B",
+"L+    c #6FBF5C",
+"M+    c #71BF5D",
+"N+    c #B2DDA7",
+"O+    c #3CA94E",
+"P+    c #6FBE5C",
+"Q+    c #6ABD5B",
+"R+    c #68BC5B",
+"S+    c #65BA5B",
+"T+    c #5EB85B",
+"U+    c #4AB05C",
+"V+    c #3DAD5A",
+"W+    c #0C9B3B",
+"X+    c #A5D9B4",
+"Y+    c #42B163",
+"Z+    c #109B34",
+"`+    c #33A74B",
+" @    c #54B35C",
+".@    c #66BB5B",
+"+@    c #70BF5D",
+"@@    c #72C05E",
+"#@    c #74C060",
+"$@    c #75C161",
+"%@    c #76C162",
+"&@    c #B5DDAA",
+"*@    c #3FAA50",
+"=@    c #75C060",
+"-@    c #74C05F",
+";@    c #72BF5E",
+">@    c #6CBD5B",
+",@    c #5DB75C",
+"'@    c #52B25C",
+")@    c #2FA64B",
+"!@    c #0B9A34",
+"~@    c #40B063",
+"{@    c #E6E6E5",
+"]@    c #D8EEDB",
+"^@    c #1B9E3C",
+"/@    c #52B02E",
+"(@    c #4EB158",
+"_@    c #5CB65B",
+":@    c #73C05F",
+"<@    c #77C162",
+"[@    c #79C264",
+"}@    c #7BC366",
+"|@    c #7DC467",
+"1@    c #B8DFAD",
+"2@    c #42AC53",
+"3@    c #7AC365",
+"4@    c #75C160",
+"5@    c #63BA5B",
+"6@    c #4BB058",
+"7@    c #4CAE2F",
+"8@    c #149D3D",
+"9@    c #D7EEDC",
+"0@    c #EFEEEE",
+"a@    c #A1D6A9",
+"b@    c #26A033",
+"c@    c #7CC034",
+"d@    c #75C056",
+"e@    c #67BC5A",
+"f@    c #76C161",
+"g@    c #78C263",
+"h@    c #7EC468",
+"i@    c #80C46A",
+"j@    c #81C56B",
+"k@    c #83C66D",
+"l@    c #BCE0AF",
+"m@    c #45AD56",
+"n@    c #7FC469",
+"o@    c #7DC367",
+"p@    c #6EBE5B",
+"q@    c #61B85B",
+"r@    c #73BF56",
+"s@    c #76BE35",
+"t@    c #219E33",
+"u@    c #9ED5A9",
+"v@    c #F6F5F5",
+"w@    c #6FC079",
+"x@    c #3CA830",
+"y@    c #8BC63D",
+"z@    c #94CC50",
+"A@    c #7EC469",
+"B@    c #84C76D",
+"C@    c #82C56A",
+"D@    c #7DC364",
+"E@    c #B6DDA8",
+"F@    c #43AC52",
+"G@    c #81C569",
+"H@    c #83C66C",
+"I@    c #80C56B",
+"J@    c #7DC468",
+"K@    c #7AC265",
+"L@    c #67BB5B",
+"M@    c #68BB5A",
+"N@    c #86C43E",
+"O@    c #37A631",
+"P@    c #6DBF7A",
+"Q@    c #47AD4E",
+"R@    c #51AF2E",
+"S@    c #93CA45",
+"T@    c #9CCF4F",
+"U@    c #88C853",
+"V@    c #6EBE5C",
+"W@    c #9AD28C",
+"X@    c #AFDBA7",
+"Y@    c #AEDBA8",
+"Z@    c #B0DBA9",
+"`@    c #B1DCAB",
+" #    c #B2DCAC",
+".#    c #B4DDAD",
+"+#    c #B3DDAC",
+"@#    c #AFDAA6",
+"##    c #ABD8A1",
+"$#    c #ABD8A0",
+"%#    c #D1EACB",
+"&#    c #B3DEC5",
+"*#    c #91CE9B",
+"=#    c #AEDAA6",
+"-#    c #B3DDAB",
+";#    c #B1DCAA",
+">#    c #AFDBA9",
+",#    c #ADDBA7",
+"'#    c #ACDAA6",
+")#    c #81C884",
+"!#    c #4CB152",
+"~#    c #87C753",
+"{#    c #8EC846",
+"]#    c #4CAD2F",
+"^#    c #44AC4E",
+"/#    c #D7DAD7",
+"(#    c #E3E3E3",
+"_#    c #33A436",
+":#    c #62B52E",
+"<#    c #97CC4A",
+"[#    c #9BCE4E",
+"}#    c #9BCE4F",
+"|#    c #83C659",
+"1#    c #CBE7C3",
+"2#    c #9ED5B6",
+"3#    c #34A645",
+"4#    c #94CB4A",
+"5#    c #5CB32F",
+"6#    c #2FA236",
+"7#    c #F5FAF4",
+"8#    c #35A533",
+"9#    c #6BB92D",
+"0#    c #99CD4C",
+"a#    c #9ACE4F",
+"b#    c #D3EAC1",
+"c#    c #39A744",
+"d#    c #97CC4D",
+"e#    c #66B72F",
+"f#    c #31A334",
+"g#    c #E4E4E4",
+"h#    c #E5F3E2",
+"i#    c #3AA733",
+"j#    c #70BB2D",
+"k#    c #9ACE4E",
+"l#    c #D9EDBD",
+"m#    c #98CD4E",
+"n#    c #6BB92F",
+"o#    c #37A633",
+"p#    c #E4F3E2",
+"q#    c #E6F3E2",
+"r#    c #40AA32",
+"s#    c #72BB2D",
+"t#    c #D9ECBC",
+"u#    c #98CD4F",
+"v#    c #6CBA2F",
+"w#    c #3DA833",
+"x#    c #E3E2E2",
+"y#    c #45AC32",
+"z#    c #99CD4D",
+"A#    c #D9ECBB",
+"B#    c #6AB92E",
+"C#    c #42AB32",
+"D#    c #4EB036",
+"E#    c #6CBA2E",
+"F#    c #9BCF4F",
+"G#    c #97CC47",
+"H#    c #D2E8B0",
+"I#    c #38A743",
+"J#    c #95CB4A",
+"K#    c #67B82F",
+"L#    c #4BAE35",
+"M#    c #D5D5D4",
+"N#    c #E9E9E9",
+"O#    c #FBFAFA",
+"P#    c #67BA50",
+"Q#    c #66B730",
+"R#    c #9ACD4C",
+"S#    c #88C42D",
+"T#    c #A6D362",
+"U#    c #B6DB88",
+"V#    c #B2DA89",
+"W#    c #B3DA8A",
+"X#    c #B8DD97",
+"Y#    c #BFE0A9",
+"Z#    c #C1E1AE",
+"`#    c #DDEFD3",
+" $    c #9DD3A2",
+".$    c #BFE0A8",
+"+$    c #B7DD96",
+"@$    c #8AC867",
+"#$    c #61B532",
+"$$    c #90C946",
+"%$    c #61B631",
+"&$    c #64B94E",
+"*$    c #DADCD9",
+"=$    c #8ECC7C",
+"-$    c #60B636",
+";$    c #8DC73D",
+">$    c #90C83A",
+",$    c #83C124",
+"'$    c #82C023",
+")$    c #86C22C",
+"!$    c #8EC741",
+"~$    c #98CC59",
+"{$    c #CAE5AB",
+"]$    c #4FB048",
+"^$    c #8EC740",
+"/$    c #88C53F",
+"($    c #5DB435",
+"_$    c #8DCB7C",
+":$    c #B8DFAC",
+"<$    c #5EB53E",
+"[$    c #82C235",
+"}$    c #98CD4A",
+"|$    c #85C228",
+"1$    c #84C128",
+"2$    c #BDDE8E",
+"3$    c #45AA30",
+"4$    c #7CC036",
+"5$    c #5BB43C",
+"6$    c #B7DEAB",
+"7$    c #E2F1DD",
+"8$    c #66B84B",
+"9$    c #73BC31",
+"0$    c #8CC636",
+"a$    c #BBDD87",
+"b$    c #45AA2F",
+"c$    c #8AC537",
+"d$    c #6EBA32",
+"e$    c #63B748",
+"f$    c #E2F1DC",
+"g$    c #E4E4E3",
+"h$    c #FDFDFC",
+"i$    c #86C770",
+"j$    c #6CBA3E",
+"k$    c #7FBF25",
+"l$    c #82C024",
+"m$    c #7ABE26",
+"n$    c #68B83D",
+"o$    c #84C66F",
+"p$    c #D6D6D5",
+"q$    c #C6E4BA",
+"r$    c #6BBA4C",
+"s$    c #79BD2A",
+"t$    c #80BF24",
+"u$    c #73BB2C",
+"v$    c #68B94A",
+"w$    c #C4E4BA",
+"x$    c #F6FAF4",
+"y$    c #84C56A",
+"z$    c #75BC41",
+"A$    c #7EBF25",
+"B$    c #7ABD26",
+"C$    c #71BB41",
+"D$    c #81C469",
+"E$    c #DAD9D9",
+"F$    c #F7F6F6",
+"G$    c #CBE6BE",
+"H$    c #76BD54",
+"I$    c #7ABE31",
+"J$    c #81C024",
+"K$    c #7EBF24",
+"L$    c #75BC32",
+"M$    c #74BC52",
+"N$    c #C9E5BE",
+"O$    c #98CE7D",
+"P$    c #7DC050",
+"Q$    c #7CBE28",
+"R$    c #77BD29",
+"S$    c #79BE4F",
+"T$    c #95CC7C",
+"U$    c #ECF5E7",
+"V$    c #8CC86B",
+"W$    c #80C149",
+"X$    c #7DBF25",
+"Y$    c #7CC049",
+"Z$    c #8AC669",
+"`$    c #EBF5E7",
+" %    c #D5EBC9",
+".%    c #8BC765",
+"+%    c #82C243",
+"@%    c #7BBE26",
+"#%    c #7EC144",
+"$%    c #89C564",
+"%%    c #D4EAC9",
+"&%    c #D8D8D6",
+"*%    c #E9E9E8",
+"=%    c #CEE7BE",
+"-%    c #8FC964",
+";%    c #86C445",
+">%    c #A6D262",
+",%    c #D0E7AC",
+"'%    c #79C26B",
+")%    c #5CB22B",
+"!%    c #82C346",
+"~%    c #8CC863",
+"{%    c #CDE6BD",
+"]%    c #DDDDDC",
+"^%    c #D1E8BF",
+"/%    c #99CE6D",
+"(%    c #8EC851",
+"_%    c #7DBF29",
+":%    c #7FBF24",
+"<%    c #7ABE2A",
+"[%    c #8AC650",
+"}%    c #97CD6C",
+"|%    c #D0E8BF",
+"1%    c #EEEEED",
+"2%    c #DBEDCC",
+"3%    c #A5D37A",
+"4%    c #97CC5F",
+"5%    c #81C135",
+"6%    c #7CBE26",
+"7%    c #7FC136",
+"8%    c #95CB5F",
+"9%    c #A3D278",
+"0%    c #DAEDCC",
+"a%    c #EFF7E9",
+"b%    c #B3DA8E",
+"c%    c #9FD06D",
+"d%    c #90C951",
+"e%    c #7EC02D",
+"f%    c #7DBE25",
+"g%    c #7BBF2E",
+"h%    c #B2DA8D",
+"i%    c #D9ECC7",
+"j%    c #AED884",
+"k%    c #A2D26F",
+"l%    c #93CA55",
+"m%    c #85C33A",
+"n%    c #7DBF28",
+"o%    c #7BBE29",
+"p%    c #83C33B",
+"q%    c #91CA56",
+"r%    c #ADD784",
+"s%    c #D8ECC7",
+"t%    c #E0E0DF",
+"u%    c #F8FBF5",
+"v%    c #D9EDC7",
+"w%    c #B6DB8F",
+"x%    c #A8D476",
+"y%    c #A2D16A",
+"z%    c #97CC5A",
+"A%    c #8EC84A",
+"B%    c #87C43E",
+"C%    c #82C236",
+"D%    c #80C132",
+"E%    c #8DC84A",
+"F%    c #A1D16A",
+"G%    c #A7D475",
+"H%    c #B5DB8F",
+"I%    c #DCDCDA",
+"J%    c #ECF5E3",
+"K%    c #D5EABF",
+"L%    c #C2E1A0",
+"M%    c #AED77F",
+"N%    c #A7D473",
+"O%    c #AAD575",
+"P%    c #AAD574",
+"Q%    c #ADD77F",
+"R%    c #EEF6E7",
+"S%    c #E6E6E6",
+"                                        . + @ # $ % & *                                         ",
+"                                = - ; > , ' ) ! ! ~ { ] ^ / ( _                                 ",
+"                            : < [ } | | | | 1 2 2 1 | | | 3 4 5 6 7                             ",
+"                        8 > 9 0 a b c d e f g g g g f e d c b a | ' h %                         ",
+"                    i j 4 | k l m n o o o p q r r q p o o s n m l t 3 [ u v                     ",
+"                  w x 3 | y z s A B C D E F G H H G F E D C B A s z I | } ^ J                   ",
+"                K 4 0 L M N N O P Q R R S T T S T T S T R U V P O N A M L | W X                 ",
+"              Y 9 | Z `  ...+.@.S #.$.$.%.&.&.%.*.&.%.$.$.#.$.S @.+... .=.Z | -.;.              ",
+"            >.9 | ,.'.).!.~.#.%.{.{.].^.^././././././.^.^.].{.%.#.S (.!.)._.:.| -.X             ",
+"          <.9 | [.}.|.1.2.3.].4.5.6.7.8.9.0.0.0.0.0.0.a.b.c.5.5.4.].*.d.1.|.}.[.| W J           ",
+"        e.f.0 g.h.i.j.k.^.5.c.l.m.n.o.p.q.r.r.0 r.r.0 s.t.u.v.w.x.7.5.4.k.y.|.h.g.| ^ v         ",
+"        z.| L A.B.C.D./.E.F.G.H.I.J.K.L.M.0 0 0 0 0 0 s.N.O.P.Q.R.S.T.c./.U.V.W.X.L } u         ",
+"      u Y.| Z.`. +.+x.v.++@+O.#+$+%+&+*+=+r.r.0 r.r.0 s.-+;+>+,+L.'+)+o.!+7.~+{+]+^+| [ %       ",
+"      , | /+(+_+:+<+p.[+K.,+}+|+1+2+3+4+5+r.r.0 r.r.0 s.6+3+2+7+8+>+9+O.Q.0+w.a+_+`.b+3 h       ",
+"    c+3 d+e+f+g+h+I.K.$+;+i+j+k+l+m+n+o+p+0 0 0 0 0 0 s.q+r+s+t+3+2+u+v+9+'+w+x+y+z+A+d+' 7     ",
+"    5 0 B+C+D+E+'+,+F+G+H+t+m+I+J+K+L+M+N+r.r.0 r.r.0 s.O+P+K+Q+R+S+4+T+u+v+#+U+V+W+f+X+| 6     ",
+"  <.9 a Y+Z+`+K. @*+H+t+.@Q+K++@@@#@$@%@&@r.r.0 r.r.0 s.*@=@-@;@L+>@I+S+k+,@8+'@'+)@!@~@a 5 _   ",
+"  {@| ]@^@/@(@}+_@k+s+I+K+M+:@$@<@[@}@|@1@r.r.0 r.r.0 s.2@3@[@<@4@@@L+>@n+5@H+u+ @6@7@8@9@4 (   ",
+"  0@| a@b@c@d@2+4+e@>@+@:@f@g@}@h@i@j@k@l@0 0 0 0 0 0 s.m@j@n@o@3@<@4@@@p@Q+m+q@i+r@s@t@u@3 /   ",
+"  v@| w@x@y@z@o+o+p@@@4@g@}@A@j@k@B@C@D@E@r.r.0 r.r.0 s.F@G@k@H@I@J@K@<@#@+@>@L@M@z@N@O@P@| ^   ",
+"< 9 | Q@R@S@T@U@V@W@X@Y@Z@`@ #.#+#@###$#%#r.r.0 r.r.0 &#*###=#-#+# #;#>#,#'#)#!#~#T@{#]#^#| ] /#",
+"(#3 | _#:#<#[#}#|#1#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2#3#}#[#4#5#6#| { & ",
+"6 3 7#8#9#0#T@T@a#b#r.r.0 r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.r.0 r.r.0 r.2#c#T@T@d#e#f#7#~ % ",
+"g#| h#i#j#k#T@T@[#l#r.r.0 r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.r.0 r.r.0 r.2#c#T@T@m#n#o#p#! $ ",
+"; 3 q#r#s#k#[#[#[#t#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2#c#[#[#u#v#w#h#! # ",
+"x#3 7#y#j#z#T@T@[#A#r.r.0 r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.r.0 r.r.0 r.2#c#T@T@d#B#C#7#) @ ",
+"; 3 | D#E#<#T@F#G#H#r.r.0 r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.0 r.r.r.0 r.r.0 r.2#I#F#T@J#K#L#| ' M#",
+"N#O#| P#Q#S@[#R#S#T#U#V#V#V#V#W#X#Y#Z#Z#`#0 0 0 0 0 0 &# $Z#.$+$W#V#V#V#V#V#@$#$R#[#$$%$&$| , *$",
+"  ) | =$-$;$[#>$,$,$,$,$'$,$'$,$,$)$!$~${$r.r.0 r.r.0 s.]$^$)$,$,$'$,$,$'$,$,$,$>$[#/$($_$| >   ",
+"  , | :$<$[$}$|$'$,$,$,$'$,$'$,$,$'$,$1$2$r.r.0 r.r.0 s.3$'$,$,$,$'$,$,$'$,$,$'$|$<#4$5$6$| ;   ",
+"  ^ | 7$8$9$0$'$'$'$'$'$'$'$'$'$'$'$'$'$a$0 0 0 0 0 0 s.b$'$'$'$'$'$'$'$'$'$'$'$'$c$d$e$f$} -   ",
+"  g$Y.h$i$j$k$,$'$,$,$,$'$,$'$,$,$'$,$,$a$r.r.0 r.r.0 s.b$'$,$,$,$'$,$,$'$,$,$'$l$m$n$o$h$[ p$  ",
+"    f.0 q$r$s$l$'$,$,$,$'$,$'$,$,$'$,$,$a$r.r.0 r.r.0 s.b$'$,$,$,$'$,$,$'$,$,$'$t$u$v$w$0 <     ",
+"    < | x$y$z$A$'$'$'$'$'$'$'$'$'$'$'$'$a$0 0 0 0 0 0 s.b$'$'$'$'$'$'$'$'$'$'$l$B$C$D$x$9 E$    ",
+"      F$0 G$H$I$J$,$,$,$'$,$'$,$,$'$,$,$a$r.r.0 r.r.0 s.b$'$,$,$,$'$,$,$'$,$,$K$L$M$N$| >       ",
+"      < | | O$P$Q$'$'$'$'$'$'$'$'$'$'$'$a$0 0 0 0 0 0 s.b$'$'$'$'$'$'$'$'$'$J$R$S$T$| 4 8       ",
+"        -.| U$V$W$X$l$,$'$,$'$,$,$'$,$,$a$r.r.0 r.r.0 s.b$'$,$,$,$'$,$,$'$J$m$Y$Z$`$3 j         ",
+"        g$9 0  %.%+%A$l$'$,$'$,$,$'$,$,$a$r.r.0 r.r.0 s.b$'$,$,$,$'$,$,$J$@%#%$%%%0 x &%        ",
+"          *%3 | =%-%;%X$'$,$'$,$,$'$,$,$>%,%,%,%,%,%,%'%)%'$,$,$,$'$,$J$B$!%~%{%| 4 ]%          ",
+"            > 3 | ^%/%(%_%J$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$:%<%[%}%|%| 9 K             ",
+"              1%3 | 2%3%4%5%A$l$,$'$,$,$'$,$,$'$,$,$'$,$,$'$,$l$J$6%7%8%9%0%| 9 Y               ",
+"                > 3 0 a%b%c%d%e%K$J$,$,$'$,$,$'$,$,$'$,$,$'$J$f%g%(%c%h%a%0 9 >.                ",
+"                  N#9 | | i%j%k%l%m%n%K$t$J$J$l$l$J$J$:%f%o%p%q%k%r%s%| | f.t%                  ",
+"                    g$-.| 0 u%v%w%x%y%z%A%B%C%D%D%C%N@E%z%F%G%H%v%u%| Y.z.I%                    ",
+"                        < F$| 0 | J%K%L%M%N%O%O%O%P%N%Q%L%K%J%| 0 3 , u                         ",
+"                            < f.Y.| | | | | u%R%R%u%| | | | | 9 5 6                             ",
+"                                g#^ , ) O#3 3 3 | 3 3 9 v@0@S%u                                 ",
+"                                        N#; x#; g#6 (#<                                         "};
diff --git a/src/icons/create-database-48x48.png b/src/icons/create-database-48x48.png
new file mode 100644 (file)
index 0000000..289bc71
Binary files /dev/null and b/src/icons/create-database-48x48.png differ
diff --git a/src/icons/create-database.xpm b/src/icons/create-database.xpm
new file mode 100644 (file)
index 0000000..ed7f397
--- /dev/null
@@ -0,0 +1,867 @@
+/* XPM */
+static const char * create_database_xpm[] = {
+"48 48 816 2",
+"      c None",
+".     c #BAC3C7",
+"+     c #B4BDC2",
+"@     c #B1BABF",
+"#     c #B5BEC3",
+"$     c #BAC2C6",
+"%     c #BDC5C9",
+"&     c #BAC2C7",
+"*     c #B6BFC3",
+"=     c #B2BBC0",
+"-     c #ABB5BA",
+";     c #B8C1C7",
+">     c #AEB8BE",
+",     c #C8CFD3",
+"'     c #D9DDE0",
+")     c #E7EAEC",
+"!     c #E9ECED",
+"~     c #E6E9EB",
+"{     c #DDE1E4",
+"]     c #D1D7DA",
+"^     c #C8CFD2",
+"/     c #C4CBCF",
+"(     c #C0C8CC",
+"_     c #BEC6CB",
+":     c #C0C7CC",
+"<     c #C2CACE",
+"[     c #C5CCD0",
+"}     c #CCD2D6",
+"|     c #D7DDE0",
+"1     c #E3E7E9",
+"2     c #E8EBED",
+"3     c #DDE1E3",
+"4     c #C9D0D3",
+"5     c #ACB6BC",
+"6     c #B2BBC1",
+"7     c #EEF0F2",
+"8     c #D7DCDF",
+"9     c #B8C0C5",
+"0     c #A1ADB3",
+"a     c #A2AEB4",
+"b     c #A6B1B8",
+"c     c #C1C9CE",
+"d     c #C8D0D4",
+"e     c #C8D0D6",
+"f     c #C6CFD5",
+"g     c #C0CBD2",
+"h     c #BBC6CE",
+"i     c #B4C1C9",
+"j     c #ACBAC2",
+"k     c #A2B1BA",
+"l     c #99A9B2",
+"m     c #92A2AC",
+"n     c #94A3AC",
+"o     c #9BA8AF",
+"p     c #ADB8BE",
+"q     c #CFD5D9",
+"r     c #EAEDEF",
+"s     c #E0E4E6",
+"t     c #B9C2C7",
+"u     c #B8C1C6",
+"v     c #EEF0F1",
+"w     c #D6DBDF",
+"x     c #A8B3B9",
+"y     c #9AA8B0",
+"z     c #B4BEC6",
+"A     c #CED6DC",
+"B     c #E6EBEF",
+"C     c #ECF0F3",
+"D     c #F0F3F5",
+"E     c #F3F6F7",
+"F     c #F3F6F8",
+"G     c #F1F4F6",
+"H     c #EDF1F4",
+"I     c #E9EEF1",
+"J     c #E3E9EE",
+"K     c #DFE6EB",
+"L     c #D9E2E8",
+"M     c #D4DEE5",
+"N     c #D0DBE2",
+"O     c #CBD7DF",
+"P     c #C5D3DC",
+"Q     c #BFCFD9",
+"R     c #B9CAD5",
+"S     c #B4C7D2",
+"T     c #AEC1CF",
+"U     c #A3B7C4",
+"V     c #96A8B5",
+"W     c #899BA6",
+"X     c #C8CFD4",
+"Y     c #F0F2F3",
+"Z     c #BCC4C8",
+"`     c #CED4D8",
+" .    c #EBEEEF",
+"..    c #A6B2B8",
+"+.    c #ABB8C0",
+"@.    c #CCD6DD",
+"#.    c #D8E1E7",
+"$.    c #E0E6EB",
+"%.    c #E4EAEE",
+"&.    c #EAEFF2",
+"*.    c #EEF1F4",
+"=.    c #F8F9FA",
+"-.    c #F9FAFB",
+";.    c #F4F6F8",
+">.    c #EEF2F5",
+",.    c #EBEFF2",
+"'.    c #E4EAEF",
+").    c #E0E7EC",
+"!.    c #DAE3E8",
+"~.    c #C6D3DD",
+"{.    c #B5C7D3",
+"].    c #AFC2CF",
+"^.    c #ABBFCD",
+"/.    c #A8BCCB",
+"(.    c #A5B9C8",
+"_.    c #9FB4C1",
+":.    c #91A5B1",
+"<.    c #94A4AD",
+"[.    c #DDE2E5",
+"}.    c #D8DDDF",
+"|.    c #FCFCFC",
+"1.    c #B0BBC2",
+"2.    c #C2CED6",
+"3.    c #CFDAE2",
+"4.    c #EFF2F5",
+"5.    c #A2B7C5",
+"6.    c #9EB4C2",
+"7.    c #99AFBD",
+"8.    c #8FA2AD",
+"9.    c #FCFCFD",
+"0.    c #FDFDFD",
+"a.    c #D0DAE1",
+"b.    c #CAD7DF",
+"c.    c #EDF0F3",
+"d.    c #E0E6EC",
+"e.    c #A7BCCB",
+"f.    c #A4BAC8",
+"g.    c #A1B7C5",
+"h.    c #9DB4C2",
+"i.    c #9AB1C0",
+"j.    c #FAFBFB",
+"k.    c #D5DEE3",
+"l.    c #C1CED4",
+"m.    c #F5F8F9",
+"n.    c #D5DFE5",
+"o.    c #CED9E1",
+"p.    c #D3DDE4",
+"q.    c #D6E0E6",
+"r.    c #DCE4EA",
+"s.    c #E2E8ED",
+"t.    c #E5EBEF",
+"u.    c #EDF1F3",
+"v.    c #E6ECEF",
+"w.    c #DDE5EA",
+"x.    c #D7E1E7",
+"y.    c #D3DDE5",
+"z.    c #CAD6DE",
+"A.    c #C4D2DC",
+"B.    c #BECED8",
+"C.    c #B8C9D5",
+"D.    c #B4C6D2",
+"E.    c #A7BBCA",
+"F.    c #A4B9C8",
+"G.    c #A8BCC9",
+"H.    c #E3E9ED",
+"I.    c #E8EDF1",
+"J.    c #628293",
+"K.    c #ADBEC8",
+"L.    c #F4F6F7",
+"M.    c #ECF1F4",
+"N.    c #D5DFE6",
+"O.    c #D2DCE3",
+"P.    c #CCD8E0",
+"Q.    c #C9D5DE",
+"R.    c #C2D1DB",
+"S.    c #BCCCD7",
+"T.    c #B7C9D4",
+"U.    c #B2C4D1",
+"V.    c #ADC0CE",
+"W.    c #AABECC",
+"X.    c #A6BBCA",
+"Y.    c #B0C2CE",
+"Z.    c #F5F7F9",
+"`.    c #DDE5EB",
+" +    c #AABDCB",
+".+    c #5E7F91",
+"++    c #628394",
+"@+    c #728FA0",
+"#+    c #AABCC6",
+"$+    c #E1E7EB",
+"%+    c #F7F9FA",
+"&+    c #F0F3F6",
+"*+    c #E6EBF0",
+"=+    c #E5EAEF",
+"-+    c #DBE4E9",
+";+    c #C0D0D9",
+">+    c #BACBD6",
+",+    c #B6C8D3",
+"'+    c #B7C8D4",
+")+    c #C8D5DE",
+"!+    c #DAE3E9",
+"~+    c #E3EAEE",
+"{+    c #C3D2DB",
+"]+    c #ADC1CE",
+"^+    c #A4B9C7",
+"/+    c #668698",
+"(+    c #6A899B",
+"_+    c #7391A1",
+":+    c #87A1B0",
+"<+    c #ABBDC8",
+"[+    c #CFD9E0",
+"}+    c #E7ECEF",
+"|+    c #F2F5F7",
+"1+    c #F3F5F7",
+"2+    c #EFF3F5",
+"3+    c #EBF0F3",
+"4+    c #E9EEF2",
+"5+    c #F6F8FA",
+"6+    c #DFE7EC",
+"7+    c #658697",
+"8+    c #6E8D9E",
+"9+    c #7291A2",
+"0+    c #7794A6",
+"a+    c #7B98A9",
+"b+    c #829DAE",
+"c+    c #91AAB9",
+"d+    c #AFC2CD",
+"e+    c #BECDD6",
+"f+    c #E6ECF0",
+"g+    c #FBFCFC",
+"h+    c #D2DDE4",
+"i+    c #BACBD5",
+"j+    c #819DAE",
+"k+    c #88A3B3",
+"l+    c #8EA7B7",
+"m+    c #93ACBB",
+"n+    c #99B0BF",
+"o+    c #A0B6C4",
+"p+    c #A6BBC9",
+"q+    c #ACBFCE",
+"r+    c #C1D0DA",
+"s+    c #FAFBFC",
+"t+    c #D8E2E8",
+"u+    c #93ABBB",
+"v+    c #A6BAC9",
+"w+    c #D6DFE6",
+"x+    c #728D9D",
+"y+    c #7693A3",
+"z+    c #6E8D9F",
+"A+    c #B6C5CF",
+"B+    c #AAB5BB",
+"C+    c #CAD1D5",
+"D+    c #788D99",
+"E+    c #698594",
+"F+    c #7390A1",
+"G+    c #D9E0E6",
+"H+    c #B4C0C8",
+"I+    c #9EACB5",
+"J+    c #C2CACF",
+"K+    c #ECEFF0",
+"L+    c #EBEDEF",
+"M+    c #909EA5",
+"N+    c #607580",
+"O+    c #4B6370",
+"P+    c #47606D",
+"Q+    c #526C7A",
+"R+    c #5F7988",
+"S+    c #6C8695",
+"T+    c #7B94A3",
+"U+    c #859EAD",
+"V+    c #8FA6B5",
+"W+    c #9AB0BE",
+"X+    c #A3B8C7",
+"Y+    c #DCE4E9",
+"Z+    c #E0E6EA",
+"`+    c #DEE4E7",
+" @    c #DBE0E3",
+".@    c #CDD4D8",
+"+@    c #ADB9BF",
+"@@    c #8D9DA6",
+"#@    c #6E828D",
+"$@    c #4B6471",
+"%@    c #49626E",
+"&@    c #5C727D",
+"*@    c #819199",
+"=@    c #DDE2E4",
+"-@    c #D4D9DC",
+";@    c #8F9EA6",
+">@    c #5C7380",
+",@    c #576F7C",
+"'@    c #57707D",
+")@    c #58717E",
+"!@    c #5B7481",
+"~@    c #5E7784",
+"{@    c #607986",
+"]@    c #627A88",
+"^@    c #667E8B",
+"/@    c #6A818E",
+"(@    c #6A818D",
+"_@    c #687F8B",
+":@    c #677E8A",
+"<@    c #657C89",
+"[@    c #617985",
+"}@    c #5C7481",
+"|@    c #5A727E",
+"1@    c #768993",
+"2@    c #FEFEFE",
+"3@    c #889AA4",
+"4@    c #687F8C",
+"5@    c #728793",
+"6@    c #F9FAFA",
+"7@    c #D4DEDD",
+"8@    c #C6D1D8",
+"9@    c #E7EBED",
+"0@    c #94A5AF",
+"a@    c #7E929E",
+"b@    c #8295A1",
+"c@    c #ADB6BD",
+"d@    c #BEC5C9",
+"e@    c #C6CBCF",
+"f@    c #BDC4C8",
+"g@    c #CED2D5",
+"h@    c #E9EBEC",
+"i@    c #ABC1C0",
+"j@    c #648395",
+"k@    c #B4C3CC",
+"l@    c #EDF0F2",
+"m@    c #D2D9DE",
+"n@    c #A7B5BE",
+"o@    c #97A8B3",
+"p@    c #93A5B0",
+"q@    c #9AA9B3",
+"r@    c #BCC5CA",
+"s@    c #E3E4E6",
+"t@    c #F3F4F4",
+"u@    c #E5F1E8",
+"v@    c #D4EADB",
+"w@    c #B9DDC3",
+"x@    c #B7DCC1",
+"y@    c #D2E8D9",
+"z@    c #E2EFE5",
+"A@    c #EFF1F0",
+"B@    c #E2E3E3",
+"C@    c #C7D1CB",
+"D@    c #7B97A6",
+"E@    c #B2C2CB",
+"F@    c #E9EEF0",
+"G@    c #D7DEE3",
+"H@    c #C1CDD4",
+"I@    c #AFBEC8",
+"J@    c #A4B5C1",
+"K@    c #A3B4BF",
+"L@    c #A3B4C0",
+"M@    c #BBC5CC",
+"N@    c #E9EAEB",
+"O@    c #F5F9F5",
+"P@    c #A2D3B1",
+"Q@    c #48A86C",
+"R@    c #128F41",
+"S@    c #018636",
+"T@    c #008636",
+"U@    c #0F8D3F",
+"V@    c #43A567",
+"W@    c #98CEA9",
+"X@    c #EEF3EF",
+"Y@    c #E5E4E4",
+"Z@    c #6F8E9F",
+"`@    c #8AA4B2",
+" #    c #B0C1CC",
+".#    c #F2F4F6",
+"+#    c #E8EDF0",
+"@#    c #DBE2E8",
+"##    c #D6DEE4",
+"$#    c #D3DCE3",
+"%#    c #D2DBE2",
+"&#    c #D1DAE1",
+"*#    c #D5DEE4",
+"=#    c #D8E0E5",
+"-#    c #F7F8F7",
+";#    c #B0DABC",
+">#    c #21974D",
+",#    c #038A38",
+"'#    c #109142",
+")#    c #20994F",
+"!#    c #2A9F57",
+"~#    c #2FA15C",
+"{#    c #30A25C",
+"]#    c #2CA059",
+"^#    c #249B53",
+"/#    c #169447",
+"(#    c #078B3B",
+"_#    c #199346",
+":#    c #A4D4B2",
+"<#    c #EFF0EF",
+"[#    c #CCD3CE",
+"}#    c #7C98A9",
+"|#    c #86A1B1",
+"1#    c #94ABBA",
+"2#    c #A4B9C6",
+"3#    c #B4C5D0",
+"4#    c #C2D0D9",
+"5#    c #CFDAE1",
+"6#    c #D8E1E8",
+"7#    c #ECF1F3",
+"8#    c #F2F2F2",
+"9#    c #F5F9F6",
+"0#    c #75C08C",
+"a#    c #078E3B",
+"b#    c #129444",
+"c#    c #29A057",
+"d#    c #31A55D",
+"e#    c #32A65E",
+"f#    c #32A75E",
+"g#    c #31A65D",
+"h#    c #32A55E",
+"i#    c #31A45D",
+"j#    c #2EA25A",
+"k#    c #1C994C",
+"l#    c #098E3C",
+"m#    c #66B881",
+"n#    c #ECF1ED",
+"o#    c #CBD4CE",
+"p#    c #E5E9EB",
+"q#    c #FBFBFB",
+"r#    c #69BB82",
+"s#    c #048F38",
+"t#    c #1D9C4D",
+"u#    c #32A95D",
+"v#    c #33AA5D",
+"w#    c #36AB5D",
+"x#    c #A3D9B6",
+"y#    c #AFDEC1",
+"z#    c #AFDEC0",
+"A#    c #A0D7B5",
+"B#    c #2BA65A",
+"C#    c #32A85D",
+"D#    c #28A056",
+"E#    c #0A913D",
+"F#    c #57B375",
+"G#    c #F3F4F3",
+"H#    c #C7CFC9",
+"I#    c #DAE1E6",
+"J#    c #F8F8F8",
+"K#    c #90CEA2",
+"L#    c #029037",
+"M#    c #21A04F",
+"N#    c #34AA5D",
+"O#    c #3AAD5D",
+"P#    c #41AE5C",
+"Q#    c #47B05C",
+"R#    c #4DB15D",
+"S#    c #E9F5EB",
+"T#    c #E6F4EC",
+"U#    c #32A658",
+"V#    c #45AF5C",
+"W#    c #3FAE5C",
+"X#    c #38AC5D",
+"Y#    c #2CA459",
+"Z#    c #09923D",
+"`#    c #7AC391",
+" $    c #EBECEB",
+".$    c #EBEEF0",
+"+$    c #D6EDDB",
+"@$    c #119941",
+"#$    c #1BA04A",
+"$$    c #3CAD5C",
+"%$    c #50B25C",
+"&$    c #56B45C",
+"*$    c #5AB65B",
+"=$    c #5EB85C",
+"-$    c #EBF6EB",
+";$    c #FFFFFF",
+">$    c #3AA957",
+",$    c #59B55B",
+"'$    c #54B35C",
+")$    c #4DB15C",
+"!$    c #43AE5C",
+"~$    c #39AC5D",
+"{$    c #29A556",
+"]$    c #0D963E",
+"^$    c #C6E4CE",
+"/$    c #D9DBD9",
+"($    c #62BC7D",
+"_$    c #0E9B3C",
+":$    c #42AE5B",
+"<$    c #58B55B",
+"[$    c #5FB85B",
+"}$    c #65BB5B",
+"|$    c #69BC5B",
+"1$    c #6DBE5D",
+"2$    c #EDF7EB",
+"3$    c #41AC57",
+"4$    c #68BB5B",
+"5$    c #63BA5B",
+"6$    c #5DB75B",
+"7$    c #4CB15C",
+"8$    c #3FAE5D",
+"9$    c #1BA049",
+"0$    c #4DB36E",
+"a$    c #F2F1F1",
+"b$    c #6E8A99",
+"c$    c #718EA0",
+"d$    c #E2E7EA",
+"e$    c #E2F2E4",
+"f$    c #29A440",
+"g$    c #3BAA4D",
+"h$    c #56B45B",
+"i$    c #67BB5B",
+"j$    c #6DBE5C",
+"k$    c #72BF5F",
+"l$    c #76C061",
+"m$    c #79C264",
+"n$    c #EEF7EC",
+"o$    c #47AE5A",
+"p$    c #74C060",
+"q$    c #70BF5D",
+"r$    c #6BBD5B",
+"s$    c #64BA5B",
+"t$    c #5CB75B",
+"u$    c #52B35C",
+"v$    c #40AD59",
+"w$    c #20A23E",
+"x$    c #D1EAD7",
+"y$    c #CDD5CD",
+"z$    c #A6B2B9",
+"A$    c #E1E5E7",
+"B$    c #7B909D",
+"C$    c #6B8797",
+"D$    c #728E9F",
+"E$    c #7B98A8",
+"F$    c #C2D0DA",
+"G$    c #EFF1F3",
+"H$    c #ADDBB4",
+"I$    c #52B030",
+"J$    c #6BBC54",
+"K$    c #78C163",
+"L$    c #7CC367",
+"M$    c #80C56A",
+"N$    c #83C66C",
+"O$    c #EFF8ED",
+"P$    c #4BB05E",
+"Q$    c #7FC469",
+"R$    c #7BC265",
+"S$    c #76C161",
+"T$    c #60B85B",
+"U$    c #65BA59",
+"V$    c #56B33D",
+"W$    c #93D1A0",
+"X$    c #E2E1E1",
+"Y$    c #EFF1F2",
+"Z$    c #9AA7AD",
+"`$    c #627580",
+" %    c #4C6370",
+".%    c #435C69",
+"+%    c #6E8897",
+"@%    c #7D96A5",
+"#%    c #89A2B2",
+"$%    c #96ADBC",
+"%%    c #F8F8F9",
+"&%    c #82C786",
+"*%    c #73BC32",
+"=%    c #93CB50",
+"-%    c #78C365",
+";%    c #A7D89C",
+">%    c #ACD9A2",
+",%    c #B0DBA5",
+"'%    c #B2DCA7",
+")%    c #B1DBA5",
+"!%    c #AFDAA1",
+"~%    c #F5FAF3",
+"{%    c #F0F8F4",
+"]%    c #90CE9B",
+"^%    c #AFDAA2",
+"/%    c #AEDAA4",
+"(%    c #ABD8A0",
+"_%    c #A5D79C",
+":%    c #5EB862",
+"<%    c #8ECA51",
+"[%    c #79C044",
+"}%    c #70C07C",
+"|%    c #EDECEC",
+"1%    c #8E9DA5",
+"2%    c #58707D",
+"3%    c #536C79",
+"4%    c #627A87",
+"5%    c #677E8B",
+"6%    c #82959F",
+"7%    c #76C172",
+"8%    c #82C338",
+"9%    c #9BCE4E",
+"0%    c #A2D36E",
+"a%    c #F8FCF7",
+"b%    c #F9FCFB",
+"c%    c #5BB66A",
+"d%    c #86C64A",
+"e%    c #5AB557",
+"f%    c #FDFEFE",
+"g%    c #8497A1",
+"h%    c #647C89",
+"i%    c #647B88",
+"j%    c #80939D",
+"k%    c #72C063",
+"l%    c #86C43A",
+"m%    c #ABD669",
+"n%    c #FAFCF6",
+"o%    c #5CB76A",
+"p%    c #8BC84C",
+"q%    c #57B44C",
+"r%    c #F3F3F3",
+"s%    c #CFD8DE",
+"t%    c #E1E6E8",
+"u%    c #889AA5",
+"v%    c #778C99",
+"w%    c #8C9DA8",
+"x%    c #81C771",
+"y%    c #85C439",
+"z%    c #AAD568",
+"A%    c #FAFCF5",
+"B%    c #5BB76A",
+"C%    c #8AC74B",
+"D%    c #66BB55",
+"E%    c #638294",
+"F%    c #BBC9D1",
+"G%    c #CAD3D8",
+"H%    c #A1B0B9",
+"I%    c #90A2AD",
+"J%    c #8EA1AC",
+"K%    c #8FA1AC",
+"L%    c #99A9B3",
+"M%    c #F6F7F8",
+"N%    c #97D087",
+"O%    c #7FC136",
+"P%    c #96CB45",
+"Q%    c #B4DA84",
+"R%    c #B3DA89",
+"S%    c #B4DB8C",
+"T%    c #BADE9D",
+"U%    c #C1E1AC",
+"V%    c #F7FBF5",
+"W%    c #F1F9F5",
+"X%    c #A0D5A6",
+"Y%    c #BBDE9E",
+"Z%    c #B4DB8D",
+"`%    c #B0D987",
+" &    c #6EBB43",
+".&    c #99CD4B",
+"+&    c #82C447",
+"@&    c #8ACA7A",
+"#&    c #EFEFEF",
+"$&    c #638495",
+"%&    c #7F9AA9",
+"&&    c #B9C7D0",
+"*&    c #E8ECEF",
+"=&    c #E8ECEE",
+"-&    c #D1D9DE",
+";&    c #BBC7CF",
+">&    c #ABB9C4",
+",&    c #A5B5C0",
+"'&    c #A1B2BD",
+")&    c #A0B1BC",
+"!&    c #A3B3BE",
+"~&    c #BFE2B4",
+"{&    c #73BC36",
+"]&    c #95CB44",
+"^&    c #83C124",
+"/&    c #82C023",
+"(&    c #83C126",
+"_&    c #89C434",
+":&    c #F1F8E7",
+"<&    c #4EAF41",
+"[&    c #8CC637",
+"}&    c #76BF42",
+"|&    c #ACD99F",
+"1&    c #E7E6E6",
+"2&    c #7593A3",
+"3&    c #94ABB8",
+"4&    c #B7C7D0",
+"5&    c #DBE3E8",
+"6&    c #EBEFF1",
+"7&    c #E2E8EC",
+"8&    c #DBE2E7",
+"9&    c #D5DDE3",
+"0&    c #CFD9DF",
+"a&    c #CDD7DE",
+"b&    c #CBD5DD",
+"c&    c #C9D4DC",
+"d&    c #E9ECEF",
+"e&    c #E8F4E3",
+"f&    c #73BD49",
+"g&    c #85C22A",
+"h&    c #83C125",
+"i&    c #EFF7E4",
+"j&    c #4CAE3D",
+"k&    c #7FC028",
+"l&    c #6ABA43",
+"m&    c #DCEED6",
+"n&    c #D7DDD3",
+"o&    c #92AAB9",
+"p&    c #A9BCC9",
+"q&    c #B9C9D3",
+"r&    c #C7D4DC",
+"s&    c #E1E8ED",
+"t&    c #E7EDF0",
+"u&    c #9BD084",
+"v&    c #7CBE2E",
+"w&    c #74BC2D",
+"x&    c #8CCA75",
+"y&    c #F6F6F6",
+"z&    c #F0F2F4",
+"A&    c #E2F1DB",
+"B&    c #7EC150",
+"C&    c #81C025",
+"D&    c #82C124",
+"E&    c #7DBF25",
+"F&    c #74BD48",
+"G&    c #D7ECCF",
+"H&    c #E4E5E2",
+"I&    c #DDE4E9",
+"J&    c #BCDFA9",
+"K&    c #81C13F",
+"L&    c #82C024",
+"M&    c #80C024",
+"N&    c #78BE3B",
+"O&    c #AED89A",
+"P&    c #607F91",
+"Q&    c #EBEEF1",
+"R&    c #AFD993",
+"S&    c #86C441",
+"T&    c #CBE5A8",
+"U&    c #D0E9BB",
+"V&    c #C1E2AE",
+"W&    c #5DB435",
+"X&    c #7FBF24",
+"Y&    c #7DC03D",
+"Z&    c #A4D387",
+"`&    c #F8F9F7",
+" *    c #DADDD5",
+".*    c #6D8491",
+"+*    c #638394",
+"@*    c #F2F4F5",
+"#*    c #F9FBF7",
+"$*    c #BADE9E",
+"%*    c #90C950",
+"&*    c #82C128",
+"**    c #7EBF28",
+"=*    c #87C54B",
+"-*    c #B1DA94",
+";*    c #F4F8F1",
+">*    c #E1E4DC",
+",*    c #728792",
+"'*    c #F5F6F7",
+")*    c #FBFCFA",
+"!*    c #D7EBC4",
+"~*    c #9FD06C",
+"{*    c #8BC642",
+"]*    c #81C027",
+"^*    c #81C024",
+"/*    c #7EBF27",
+"(*    c #86C440",
+"_*    c #99CD66",
+":*    c #D1E9BD",
+"<*    c #E2E5DE",
+"[*    c #758893",
+"}*    c #738A97",
+"|*    c #738F9E",
+"1*    c #7793A4",
+"2*    c #FAFAFB",
+"3*    c #D2E9BB",
+"4*    c #B3DA8B",
+"5*    c #98CD5D",
+"6*    c #91C94D",
+"7*    c #8DC746",
+"8*    c #8CC746",
+"9*    c #8FC84D",
+"0*    c #95CB5B",
+"a*    c #B0D886",
+"b*    c #CEE7B6",
+"c*    c #F4F9F1",
+"d*    c #778B96",
+"e*    c #798E9A",
+"f*    c #7C929F",
+"g*    c #8399A7",
+"h*    c #89A1B0",
+"i*    c #90A8B7",
+"j*    c #97ADBC",
+"k*    c #DEE5EA",
+"l*    c #E5EAEE",
+"m*    c #EAEDF0",
+"n*    c #E3E6E8",
+"o*    c #D5DADC",
+"p*    c #F0F1F2",
+"q*    c #FAFBF9",
+"r*    c #F2F8ED",
+"s*    c #E6F3DA",
+"t*    c #D8ECC6",
+"u*    c #D7ECC5",
+"v*    c #E5F2D8",
+"w*    c #F2F8EC",
+"x*    c #F8FAF7",
+"y*    c #F4F4F3",
+"z*    c #E2E4DF",
+"A*    c #8496A2",
+"B*    c #82949E",
+"C*    c #81929C",
+"D*    c #83949E",
+"E*    c #8797A1",
+"F*    c #8B9BA4",
+"G*    c #8D9CA4",
+"H*    c #8D9BA4",
+"I*    c #8B99A1",
+"J*    c #A4AFB6",
+"K*    c #E7EDDF",
+"L*    c #EDEDEB",
+"M*    c #EFEEEE",
+"N*    c #EBEBEB",
+"O*    c #E4E9DD",
+"                            . + @ # $ % & * = - ;                                               ",
+"                > , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 ) 3 4 5                                   ",
+"          6 ' 7 8 9 0 a b > ; c d e e f g h i j k l m n o p q r s t                             ",
+"      u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W y X Y Z                         ",
+"    `  ...+.@.#.$.%.&.*.E =.-.;.>.,.'.).!.M N O ~.Q R {.].^./.(._.:.<.[.}.                      ",
+"    |.1.2.3.M L $.%.&.*.F -.-.;.4.,.'.).!.M N O ~.Q R {.].^./.(.5.6.7.8.9.                      ",
+"    0.a.b.3.M #.K J I c.G ;.;.G H I J d.L M N O P Q R S T ^.e.f.g.h.i.6.j.k.                    ",
+"    l.m.n.o.p.q.r.s.t.&.u.4.4.H ,.v.s.w.x.y.o.z.A.B.C.D.T ^.E.F.g.h.G.H.I.                      ",
+"    J.K.L.M.r.N.L K s.B I ,.,.I v.H.K !.n.O.P.Q.R.S.T.U.V.W.X.F.Y.p.Z.`. +                      ",
+"    .+++@+#+$+%+&+&.*+=+J '.'.J s.K -+q.p.3.O ~.;+>+,+'+S.)+!+&+=.~+{+]+^+                      ",
+"    .+++/+(+_+:+<+[+}+|+%+%+Z.1+2+H 3+4+I.B t.t.4+H F %+-.5+H 6+M )+>+]+^+                      ",
+"    .+++7+(+8+9+0+a+b+c+U d+e+O M L ).f+4+M.&+;.%+0.g+Z.H t.K #.h+)+i+V.^+                      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+)+>+]+^+                      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+)+>+]+^+                      ",
+"    .+++7+(+8+9+0+a+j+k+l+u+n+o+v+q+{.r+P.w+).I |+9.s+;.H t.K #.h+)+i+V.^+                      ",
+"      ++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+)+>+]+                        ",
+"        x+y+z+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+P.A+                          ",
+"      B+) C+D+E+F+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.G+H+I+J+K+.                         ",
+"    < L+M+N+O+P+P+Q+R+S+T+U+V+W+X+^.{.r+P.N.Y+Z+`+ @.@+@@@#@$@P+%@&@*@=@-@                      ",
+"    g+;@>@,@'@'@,@'@'@'@'@)@!@~@{@]@^@/@(@_@:@<@[@}@'@'@'@,@'@'@'@,@|@1@g+                      ",
+"    2@3@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@5@6@7@                    ",
+"    8@9@0@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@b@n c@d@e@e@f@g@h@i@                    ",
+"    j@k@l@m@n@o@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@q@r@s@t@u@v@w@x@y@z@A@B@C@                  ",
+"    .+++D@E@F@l@G@H@I@J@K@L@K@L@L@K@L@L@K@L@L@K@L@M@N@O@P@Q@R@S@T@T@T@U@V@W@X@Y@                ",
+"    .+++7+(+Z@`@ #k.F@Z..#+#$+@###$#%#a.&#$#*#=#{ -#;#>#,#'#)#!#~#{#]#^#/#(#_#:#<#[#            ",
+"    .+++/+(+8+9+0+}#|#1#2#3#4#5#6#`.%.4+7#>.G 8#9#0#a#b#c#d#e#e#f#g#e#h#i#j#k#l#m#n#o#          ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.p#q#r#s#t#g#u#v#w#x#y#z#A#B#u#C#e#D#E#F#G#H#        ",
+"    .+++7+(+8+9+0+a+j+k+l+u+n+o+v+q+{.r+P.I#J#K#L#M#N#O#P#Q#R#S#2@2@T#U#V#W#X#v#Y#Z#`# $        ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P..$+$@$#$$$Q#%$&$*$=$-$;$2@T#>$,$'$)$!$~${$]$^$/$      ",
+"      ++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+%#q#($_$:$%$<$[$}$|$1$2$;$2@T#3$4$5$6$&$7$8$9$0$a$      ",
+"        b$c$8+9+0+a+j+k+l+u+n+o+v+q+{.r+d$e$f$g$h$[$i$j$k$l$m$n$2@2@T#o$p$q$r$s$t$u$v$w$x$y$    ",
+"      z$A$X B$C$D$E$j+k+l+m+n+o+p+q+{.F$G$H$I$J$s$r$k$K$L$M$N$O$;$2@T#P$Q$R$S$q$|$T$U$V$W$X$    ",
+"    . Y$Z$`$ %.%P+Q+R++%@%#%$%o+p+q+{.P %%&%*%=%-%;%>%,%'%)%!%~%;$2@{%]%^%,%/%(%_%:%<%[%}%|%    ",
+"    g+1%2%3%3%3%3%3%3%3%3%3%3%)@~@4%5%6%q#7%8%9%0%a%2@2@2@2@2@2@2@2@2@2@2@2@2@2@b%c%9%d%e%a$    ",
+"    f%g%h%i%h%h%i%h%h%h%i%h%i%h%h%i%h%j%q#k%l%9%m%n%2@;$;$2@;$;$;$2@;$;$2@;$;$2@b%o%9%p%q%r%    ",
+"    s%t%u%v%v%v%v%v%v%v%v%v%v%v%v%v%v%w%q#x%y%9%z%A%2@2@2@2@2@2@2@2@2@2@2@2@2@2@b%B%9%C%D%8#    ",
+"    E%F%.#G%H%I%J%K%K%K%J%K%J%K%K%J%K%L%M%N%O%9%P%Q%R%R%S%T%U%V%;$2@W%X%Y%Z%R%R%`% &.&+&@&#&    ",
+"    .+$&%&&&*&=&-&;&>&,&'&)&)&)&)&)&)&!&.$~&{&]&^&^&/&^&^&(&_&:&;$2@T#<&(&^&^&/&^&^&[&}&|&1&    ",
+"    .+++/+(+2&3&4&5&G ;.6&7&8&9&0&a&b&c&d&e&f&g&^&^&/&^&^&/&h&i&;$2@T#j&/&^&^&/&^&^&k&l&m&n&    ",
+"    .+++7+(+8+9+0+a+j+o&p&q&r&M w.s&t&C l@0.u&v&/&/&/&/&/&/&h&i&2@2@T#j&/&/&/&/&/&/&w&x&y&      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.z&A&B&C&^&/&^&^&/&h&i&;$2@T#j&/&^&^&/&D&E&F&G&H&      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.I&q#J&K&L&/&^&^&/&h&i&;$2@T#j&/&^&^&/&M&N&O&G#        ",
+"    P&++7+(+8+9+0+a+j+k+l+u+n+o+v+q+{.r+P.w+Q&0.R&S&L&/&/&/&^&T&U&U&V&W&/&/&/&X&Y&Z&`& *        ",
+"    .*+*/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).@*#*$*%*&*L&/&^&^&^&/&^&^&/&L&**=*-*;*>*          ",
+"      ,*S+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I '*)*!*~*{*]*L&^&^&/&D&^*/*(*_*:*`&<*            ",
+"          [*}*|*1*a+j+k+l+u+n+o+v+q+{.r+P.w+).I |+J#2*V%3*4*5*6*7*8*9*0*a*b*c*r%                ",
+"                d*e*f*g*h*i*j*6.(.^.{.r+P.n.k*l*m*v n*o*p*q*r*s*t*u*v*w*x*y*z*                  ",
+"                            A*B*C*D*E*F*G*G*H*I*J*          K*L*#&M*N*O*                        "};
diff --git a/src/icons/database-add-48x48.png b/src/icons/database-add-48x48.png
new file mode 100644 (file)
index 0000000..289bc71
Binary files /dev/null and b/src/icons/database-add-48x48.png differ
diff --git a/src/icons/database-add.xpm b/src/icons/database-add.xpm
new file mode 100644 (file)
index 0000000..6653b21
--- /dev/null
@@ -0,0 +1,867 @@
+/* XPM */
+static const char * database_add_xpm[] = {
+"48 48 816 2",
+"      c None",
+".     c #BAC3C7",
+"+     c #B4BDC2",
+"@     c #B1BABF",
+"#     c #B5BEC3",
+"$     c #BAC2C6",
+"%     c #BDC5C9",
+"&     c #BAC2C7",
+"*     c #B6BFC3",
+"=     c #B2BBC0",
+"-     c #ABB5BA",
+";     c #B8C1C7",
+">     c #AEB8BE",
+",     c #C8CFD3",
+"'     c #D9DDE0",
+")     c #E7EAEC",
+"!     c #E9ECED",
+"~     c #E6E9EB",
+"{     c #DDE1E4",
+"]     c #D1D7DA",
+"^     c #C8CFD2",
+"/     c #C4CBCF",
+"(     c #C0C8CC",
+"_     c #BEC6CB",
+":     c #C0C7CC",
+"<     c #C2CACE",
+"[     c #C5CCD0",
+"}     c #CCD2D6",
+"|     c #D7DDE0",
+"1     c #E3E7E9",
+"2     c #E8EBED",
+"3     c #DDE1E3",
+"4     c #C9D0D3",
+"5     c #ACB6BC",
+"6     c #B2BBC1",
+"7     c #EEF0F2",
+"8     c #D7DCDF",
+"9     c #B8C0C5",
+"0     c #A1ADB3",
+"a     c #A2AEB4",
+"b     c #A6B1B8",
+"c     c #C1C9CE",
+"d     c #C8D0D4",
+"e     c #C8D0D6",
+"f     c #C6CFD5",
+"g     c #C0CBD2",
+"h     c #BBC6CE",
+"i     c #B4C1C9",
+"j     c #ACBAC2",
+"k     c #A2B1BA",
+"l     c #99A9B2",
+"m     c #92A2AC",
+"n     c #94A3AC",
+"o     c #9BA8AF",
+"p     c #ADB8BE",
+"q     c #CFD5D9",
+"r     c #EAEDEF",
+"s     c #E0E4E6",
+"t     c #B9C2C7",
+"u     c #B8C1C6",
+"v     c #EEF0F1",
+"w     c #D6DBDF",
+"x     c #A8B3B9",
+"y     c #9AA8B0",
+"z     c #B4BEC6",
+"A     c #CED6DC",
+"B     c #E6EBEF",
+"C     c #ECF0F3",
+"D     c #F0F3F5",
+"E     c #F3F6F7",
+"F     c #F3F6F8",
+"G     c #F1F4F6",
+"H     c #EDF1F4",
+"I     c #E9EEF1",
+"J     c #E3E9EE",
+"K     c #DFE6EB",
+"L     c #D9E2E8",
+"M     c #D4DEE5",
+"N     c #D0DBE2",
+"O     c #CBD7DF",
+"P     c #C5D3DC",
+"Q     c #BFCFD9",
+"R     c #B9CAD5",
+"S     c #B4C7D2",
+"T     c #AEC1CF",
+"U     c #A3B7C4",
+"V     c #96A8B5",
+"W     c #899BA6",
+"X     c #C8CFD4",
+"Y     c #F0F2F3",
+"Z     c #BCC4C8",
+"`     c #CED4D8",
+" .    c #EBEEEF",
+"..    c #A6B2B8",
+"+.    c #ABB8C0",
+"@.    c #CCD6DD",
+"#.    c #D8E1E7",
+"$.    c #E0E6EB",
+"%.    c #E4EAEE",
+"&.    c #EAEFF2",
+"*.    c #EEF1F4",
+"=.    c #F8F9FA",
+"-.    c #F9FAFB",
+";.    c #F4F6F8",
+">.    c #EEF2F5",
+",.    c #EBEFF2",
+"'.    c #E4EAEF",
+").    c #E0E7EC",
+"!.    c #DAE3E8",
+"~.    c #C6D3DD",
+"{.    c #B5C7D3",
+"].    c #AFC2CF",
+"^.    c #ABBFCD",
+"/.    c #A8BCCB",
+"(.    c #A5B9C8",
+"_.    c #9FB4C1",
+":.    c #91A5B1",
+"<.    c #94A4AD",
+"[.    c #DDE2E5",
+"}.    c #D8DDDF",
+"|.    c #FCFCFC",
+"1.    c #B0BBC2",
+"2.    c #C2CED6",
+"3.    c #CFDAE2",
+"4.    c #EFF2F5",
+"5.    c #A2B7C5",
+"6.    c #9EB4C2",
+"7.    c #99AFBD",
+"8.    c #8FA2AD",
+"9.    c #FCFCFD",
+"0.    c #FDFDFD",
+"a.    c #D0DAE1",
+"b.    c #CAD7DF",
+"c.    c #EDF0F3",
+"d.    c #E0E6EC",
+"e.    c #A7BCCB",
+"f.    c #A4BAC8",
+"g.    c #A1B7C5",
+"h.    c #9DB4C2",
+"i.    c #9AB1C0",
+"j.    c #FAFBFB",
+"k.    c #D5DEE3",
+"l.    c #C1CED4",
+"m.    c #F5F8F9",
+"n.    c #D5DFE5",
+"o.    c #CED9E1",
+"p.    c #D3DDE4",
+"q.    c #D6E0E6",
+"r.    c #DCE4EA",
+"s.    c #E2E8ED",
+"t.    c #E5EBEF",
+"u.    c #EDF1F3",
+"v.    c #E6ECEF",
+"w.    c #DDE5EA",
+"x.    c #D7E1E7",
+"y.    c #D3DDE5",
+"z.    c #CAD6DE",
+"A.    c #C4D2DC",
+"B.    c #BECED8",
+"C.    c #B8C9D5",
+"D.    c #B4C6D2",
+"E.    c #A7BBCA",
+"F.    c #A4B9C8",
+"G.    c #A8BCC9",
+"H.    c #E3E9ED",
+"I.    c #E8EDF1",
+"J.    c #628293",
+"K.    c #ADBEC8",
+"L.    c #F4F6F7",
+"M.    c #ECF1F4",
+"N.    c #D5DFE6",
+"O.    c #D2DCE3",
+"P.    c #CCD8E0",
+"Q.    c #C9D5DE",
+"R.    c #C2D1DB",
+"S.    c #BCCCD7",
+"T.    c #B7C9D4",
+"U.    c #B2C4D1",
+"V.    c #ADC0CE",
+"W.    c #AABECC",
+"X.    c #A6BBCA",
+"Y.    c #B0C2CE",
+"Z.    c #F5F7F9",
+"`.    c #DDE5EB",
+" +    c #AABDCB",
+".+    c #5E7F91",
+"++    c #628394",
+"@+    c #728FA0",
+"#+    c #AABCC6",
+"$+    c #E1E7EB",
+"%+    c #F7F9FA",
+"&+    c #F0F3F6",
+"*+    c #E6EBF0",
+"=+    c #E5EAEF",
+"-+    c #DBE4E9",
+";+    c #C0D0D9",
+">+    c #BACBD6",
+",+    c #B6C8D3",
+"'+    c #B7C8D4",
+")+    c #C8D5DE",
+"!+    c #DAE3E9",
+"~+    c #E3EAEE",
+"{+    c #C3D2DB",
+"]+    c #ADC1CE",
+"^+    c #A4B9C7",
+"/+    c #668698",
+"(+    c #6A899B",
+"_+    c #7391A1",
+":+    c #87A1B0",
+"<+    c #ABBDC8",
+"[+    c #CFD9E0",
+"}+    c #E7ECEF",
+"|+    c #F2F5F7",
+"1+    c #F3F5F7",
+"2+    c #EFF3F5",
+"3+    c #EBF0F3",
+"4+    c #E9EEF2",
+"5+    c #F6F8FA",
+"6+    c #DFE7EC",
+"7+    c #658697",
+"8+    c #6E8D9E",
+"9+    c #7291A2",
+"0+    c #7794A6",
+"a+    c #7B98A9",
+"b+    c #829DAE",
+"c+    c #91AAB9",
+"d+    c #AFC2CD",
+"e+    c #BECDD6",
+"f+    c #E6ECF0",
+"g+    c #FBFCFC",
+"h+    c #D2DDE4",
+"i+    c #BACBD5",
+"j+    c #819DAE",
+"k+    c #88A3B3",
+"l+    c #8EA7B7",
+"m+    c #93ACBB",
+"n+    c #99B0BF",
+"o+    c #A0B6C4",
+"p+    c #A6BBC9",
+"q+    c #ACBFCE",
+"r+    c #C1D0DA",
+"s+    c #FAFBFC",
+"t+    c #D8E2E8",
+"u+    c #93ABBB",
+"v+    c #A6BAC9",
+"w+    c #D6DFE6",
+"x+    c #728D9D",
+"y+    c #7693A3",
+"z+    c #6E8D9F",
+"A+    c #B6C5CF",
+"B+    c #AAB5BB",
+"C+    c #CAD1D5",
+"D+    c #788D99",
+"E+    c #698594",
+"F+    c #7390A1",
+"G+    c #D9E0E6",
+"H+    c #B4C0C8",
+"I+    c #9EACB5",
+"J+    c #C2CACF",
+"K+    c #ECEFF0",
+"L+    c #EBEDEF",
+"M+    c #909EA5",
+"N+    c #607580",
+"O+    c #4B6370",
+"P+    c #47606D",
+"Q+    c #526C7A",
+"R+    c #5F7988",
+"S+    c #6C8695",
+"T+    c #7B94A3",
+"U+    c #859EAD",
+"V+    c #8FA6B5",
+"W+    c #9AB0BE",
+"X+    c #A3B8C7",
+"Y+    c #DCE4E9",
+"Z+    c #E0E6EA",
+"`+    c #DEE4E7",
+" @    c #DBE0E3",
+".@    c #CDD4D8",
+"+@    c #ADB9BF",
+"@@    c #8D9DA6",
+"#@    c #6E828D",
+"$@    c #4B6471",
+"%@    c #49626E",
+"&@    c #5C727D",
+"*@    c #819199",
+"=@    c #DDE2E4",
+"-@    c #D4D9DC",
+";@    c #8F9EA6",
+">@    c #5C7380",
+",@    c #576F7C",
+"'@    c #57707D",
+")@    c #58717E",
+"!@    c #5B7481",
+"~@    c #5E7784",
+"{@    c #607986",
+"]@    c #627A88",
+"^@    c #667E8B",
+"/@    c #6A818E",
+"(@    c #6A818D",
+"_@    c #687F8B",
+":@    c #677E8A",
+"<@    c #657C89",
+"[@    c #617985",
+"}@    c #5C7481",
+"|@    c #5A727E",
+"1@    c #768993",
+"2@    c #FEFEFE",
+"3@    c #889AA4",
+"4@    c #687F8C",
+"5@    c #728793",
+"6@    c #F9FAFA",
+"7@    c #D4DEDD",
+"8@    c #C6D1D8",
+"9@    c #E7EBED",
+"0@    c #94A5AF",
+"a@    c #7E929E",
+"b@    c #8295A1",
+"c@    c #ADB6BD",
+"d@    c #BEC5C9",
+"e@    c #C6CBCF",
+"f@    c #BDC4C8",
+"g@    c #CED2D5",
+"h@    c #E9EBEC",
+"i@    c #ABC1C0",
+"j@    c #648395",
+"k@    c #B4C3CC",
+"l@    c #EDF0F2",
+"m@    c #D2D9DE",
+"n@    c #A7B5BE",
+"o@    c #97A8B3",
+"p@    c #93A5B0",
+"q@    c #9AA9B3",
+"r@    c #BCC5CA",
+"s@    c #E3E4E6",
+"t@    c #F3F4F4",
+"u@    c #E5F1E8",
+"v@    c #D4EADB",
+"w@    c #B9DDC3",
+"x@    c #B7DCC1",
+"y@    c #D2E8D9",
+"z@    c #E2EFE5",
+"A@    c #EFF1F0",
+"B@    c #E2E3E3",
+"C@    c #C7D1CB",
+"D@    c #7B97A6",
+"E@    c #B2C2CB",
+"F@    c #E9EEF0",
+"G@    c #D7DEE3",
+"H@    c #C1CDD4",
+"I@    c #AFBEC8",
+"J@    c #A4B5C1",
+"K@    c #A3B4BF",
+"L@    c #A3B4C0",
+"M@    c #BBC5CC",
+"N@    c #E9EAEB",
+"O@    c #F5F9F5",
+"P@    c #A2D3B1",
+"Q@    c #48A86C",
+"R@    c #128F41",
+"S@    c #018636",
+"T@    c #008636",
+"U@    c #0F8D3F",
+"V@    c #43A567",
+"W@    c #98CEA9",
+"X@    c #EEF3EF",
+"Y@    c #E5E4E4",
+"Z@    c #6F8E9F",
+"`@    c #8AA4B2",
+" #    c #B0C1CC",
+".#    c #F2F4F6",
+"+#    c #E8EDF0",
+"@#    c #DBE2E8",
+"##    c #D6DEE4",
+"$#    c #D3DCE3",
+"%#    c #D2DBE2",
+"&#    c #D1DAE1",
+"*#    c #D5DEE4",
+"=#    c #D8E0E5",
+"-#    c #F7F8F7",
+";#    c #B0DABC",
+">#    c #21974D",
+",#    c #038A38",
+"'#    c #109142",
+")#    c #20994F",
+"!#    c #2A9F57",
+"~#    c #2FA15C",
+"{#    c #30A25C",
+"]#    c #2CA059",
+"^#    c #249B53",
+"/#    c #169447",
+"(#    c #078B3B",
+"_#    c #199346",
+":#    c #A4D4B2",
+"<#    c #EFF0EF",
+"[#    c #CCD3CE",
+"}#    c #7C98A9",
+"|#    c #86A1B1",
+"1#    c #94ABBA",
+"2#    c #A4B9C6",
+"3#    c #B4C5D0",
+"4#    c #C2D0D9",
+"5#    c #CFDAE1",
+"6#    c #D8E1E8",
+"7#    c #ECF1F3",
+"8#    c #F2F2F2",
+"9#    c #F5F9F6",
+"0#    c #75C08C",
+"a#    c #078E3B",
+"b#    c #129444",
+"c#    c #29A057",
+"d#    c #31A55D",
+"e#    c #32A65E",
+"f#    c #32A75E",
+"g#    c #31A65D",
+"h#    c #32A55E",
+"i#    c #31A45D",
+"j#    c #2EA25A",
+"k#    c #1C994C",
+"l#    c #098E3C",
+"m#    c #66B881",
+"n#    c #ECF1ED",
+"o#    c #CBD4CE",
+"p#    c #E5E9EB",
+"q#    c #FBFBFB",
+"r#    c #69BB82",
+"s#    c #048F38",
+"t#    c #1D9C4D",
+"u#    c #32A95D",
+"v#    c #33AA5D",
+"w#    c #36AB5D",
+"x#    c #A3D9B6",
+"y#    c #AFDEC1",
+"z#    c #AFDEC0",
+"A#    c #A0D7B5",
+"B#    c #2BA65A",
+"C#    c #32A85D",
+"D#    c #28A056",
+"E#    c #0A913D",
+"F#    c #57B375",
+"G#    c #F3F4F3",
+"H#    c #C7CFC9",
+"I#    c #DAE1E6",
+"J#    c #F8F8F8",
+"K#    c #90CEA2",
+"L#    c #029037",
+"M#    c #21A04F",
+"N#    c #34AA5D",
+"O#    c #3AAD5D",
+"P#    c #41AE5C",
+"Q#    c #47B05C",
+"R#    c #4DB15D",
+"S#    c #E9F5EB",
+"T#    c #E6F4EC",
+"U#    c #32A658",
+"V#    c #45AF5C",
+"W#    c #3FAE5C",
+"X#    c #38AC5D",
+"Y#    c #2CA459",
+"Z#    c #09923D",
+"`#    c #7AC391",
+" $    c #EBECEB",
+".$    c #EBEEF0",
+"+$    c #D6EDDB",
+"@$    c #119941",
+"#$    c #1BA04A",
+"$$    c #3CAD5C",
+"%$    c #50B25C",
+"&$    c #56B45C",
+"*$    c #5AB65B",
+"=$    c #5EB85C",
+"-$    c #EBF6EB",
+";$    c #FFFFFF",
+">$    c #3AA957",
+",$    c #59B55B",
+"'$    c #54B35C",
+")$    c #4DB15C",
+"!$    c #43AE5C",
+"~$    c #39AC5D",
+"{$    c #29A556",
+"]$    c #0D963E",
+"^$    c #C6E4CE",
+"/$    c #D9DBD9",
+"($    c #62BC7D",
+"_$    c #0E9B3C",
+":$    c #42AE5B",
+"<$    c #58B55B",
+"[$    c #5FB85B",
+"}$    c #65BB5B",
+"|$    c #69BC5B",
+"1$    c #6DBE5D",
+"2$    c #EDF7EB",
+"3$    c #41AC57",
+"4$    c #68BB5B",
+"5$    c #63BA5B",
+"6$    c #5DB75B",
+"7$    c #4CB15C",
+"8$    c #3FAE5D",
+"9$    c #1BA049",
+"0$    c #4DB36E",
+"a$    c #F2F1F1",
+"b$    c #6E8A99",
+"c$    c #718EA0",
+"d$    c #E2E7EA",
+"e$    c #E2F2E4",
+"f$    c #29A440",
+"g$    c #3BAA4D",
+"h$    c #56B45B",
+"i$    c #67BB5B",
+"j$    c #6DBE5C",
+"k$    c #72BF5F",
+"l$    c #76C061",
+"m$    c #79C264",
+"n$    c #EEF7EC",
+"o$    c #47AE5A",
+"p$    c #74C060",
+"q$    c #70BF5D",
+"r$    c #6BBD5B",
+"s$    c #64BA5B",
+"t$    c #5CB75B",
+"u$    c #52B35C",
+"v$    c #40AD59",
+"w$    c #20A23E",
+"x$    c #D1EAD7",
+"y$    c #CDD5CD",
+"z$    c #A6B2B9",
+"A$    c #E1E5E7",
+"B$    c #7B909D",
+"C$    c #6B8797",
+"D$    c #728E9F",
+"E$    c #7B98A8",
+"F$    c #C2D0DA",
+"G$    c #EFF1F3",
+"H$    c #ADDBB4",
+"I$    c #52B030",
+"J$    c #6BBC54",
+"K$    c #78C163",
+"L$    c #7CC367",
+"M$    c #80C56A",
+"N$    c #83C66C",
+"O$    c #EFF8ED",
+"P$    c #4BB05E",
+"Q$    c #7FC469",
+"R$    c #7BC265",
+"S$    c #76C161",
+"T$    c #60B85B",
+"U$    c #65BA59",
+"V$    c #56B33D",
+"W$    c #93D1A0",
+"X$    c #E2E1E1",
+"Y$    c #EFF1F2",
+"Z$    c #9AA7AD",
+"`$    c #627580",
+" %    c #4C6370",
+".%    c #435C69",
+"+%    c #6E8897",
+"@%    c #7D96A5",
+"#%    c #89A2B2",
+"$%    c #96ADBC",
+"%%    c #F8F8F9",
+"&%    c #82C786",
+"*%    c #73BC32",
+"=%    c #93CB50",
+"-%    c #78C365",
+";%    c #A7D89C",
+">%    c #ACD9A2",
+",%    c #B0DBA5",
+"'%    c #B2DCA7",
+")%    c #B1DBA5",
+"!%    c #AFDAA1",
+"~%    c #F5FAF3",
+"{%    c #F0F8F4",
+"]%    c #90CE9B",
+"^%    c #AFDAA2",
+"/%    c #AEDAA4",
+"(%    c #ABD8A0",
+"_%    c #A5D79C",
+":%    c #5EB862",
+"<%    c #8ECA51",
+"[%    c #79C044",
+"}%    c #70C07C",
+"|%    c #EDECEC",
+"1%    c #8E9DA5",
+"2%    c #58707D",
+"3%    c #536C79",
+"4%    c #627A87",
+"5%    c #677E8B",
+"6%    c #82959F",
+"7%    c #76C172",
+"8%    c #82C338",
+"9%    c #9BCE4E",
+"0%    c #A2D36E",
+"a%    c #F8FCF7",
+"b%    c #F9FCFB",
+"c%    c #5BB66A",
+"d%    c #86C64A",
+"e%    c #5AB557",
+"f%    c #FDFEFE",
+"g%    c #8497A1",
+"h%    c #647C89",
+"i%    c #647B88",
+"j%    c #80939D",
+"k%    c #72C063",
+"l%    c #86C43A",
+"m%    c #ABD669",
+"n%    c #FAFCF6",
+"o%    c #5CB76A",
+"p%    c #8BC84C",
+"q%    c #57B44C",
+"r%    c #F3F3F3",
+"s%    c #CFD8DE",
+"t%    c #E1E6E8",
+"u%    c #889AA5",
+"v%    c #778C99",
+"w%    c #8C9DA8",
+"x%    c #81C771",
+"y%    c #85C439",
+"z%    c #AAD568",
+"A%    c #FAFCF5",
+"B%    c #5BB76A",
+"C%    c #8AC74B",
+"D%    c #66BB55",
+"E%    c #638294",
+"F%    c #BBC9D1",
+"G%    c #CAD3D8",
+"H%    c #A1B0B9",
+"I%    c #90A2AD",
+"J%    c #8EA1AC",
+"K%    c #8FA1AC",
+"L%    c #99A9B3",
+"M%    c #F6F7F8",
+"N%    c #97D087",
+"O%    c #7FC136",
+"P%    c #96CB45",
+"Q%    c #B4DA84",
+"R%    c #B3DA89",
+"S%    c #B4DB8C",
+"T%    c #BADE9D",
+"U%    c #C1E1AC",
+"V%    c #F7FBF5",
+"W%    c #F1F9F5",
+"X%    c #A0D5A6",
+"Y%    c #BBDE9E",
+"Z%    c #B4DB8D",
+"`%    c #B0D987",
+" &    c #6EBB43",
+".&    c #99CD4B",
+"+&    c #82C447",
+"@&    c #8ACA7A",
+"#&    c #EFEFEF",
+"$&    c #638495",
+"%&    c #7F9AA9",
+"&&    c #B9C7D0",
+"*&    c #E8ECEF",
+"=&    c #E8ECEE",
+"-&    c #D1D9DE",
+";&    c #BBC7CF",
+">&    c #ABB9C4",
+",&    c #A5B5C0",
+"'&    c #A1B2BD",
+")&    c #A0B1BC",
+"!&    c #A3B3BE",
+"~&    c #BFE2B4",
+"{&    c #73BC36",
+"]&    c #95CB44",
+"^&    c #83C124",
+"/&    c #82C023",
+"(&    c #83C126",
+"_&    c #89C434",
+":&    c #F1F8E7",
+"<&    c #4EAF41",
+"[&    c #8CC637",
+"}&    c #76BF42",
+"|&    c #ACD99F",
+"1&    c #E7E6E6",
+"2&    c #7593A3",
+"3&    c #94ABB8",
+"4&    c #B7C7D0",
+"5&    c #DBE3E8",
+"6&    c #EBEFF1",
+"7&    c #E2E8EC",
+"8&    c #DBE2E7",
+"9&    c #D5DDE3",
+"0&    c #CFD9DF",
+"a&    c #CDD7DE",
+"b&    c #CBD5DD",
+"c&    c #C9D4DC",
+"d&    c #E9ECEF",
+"e&    c #E8F4E3",
+"f&    c #73BD49",
+"g&    c #85C22A",
+"h&    c #83C125",
+"i&    c #EFF7E4",
+"j&    c #4CAE3D",
+"k&    c #7FC028",
+"l&    c #6ABA43",
+"m&    c #DCEED6",
+"n&    c #D7DDD3",
+"o&    c #92AAB9",
+"p&    c #A9BCC9",
+"q&    c #B9C9D3",
+"r&    c #C7D4DC",
+"s&    c #E1E8ED",
+"t&    c #E7EDF0",
+"u&    c #9BD084",
+"v&    c #7CBE2E",
+"w&    c #74BC2D",
+"x&    c #8CCA75",
+"y&    c #F6F6F6",
+"z&    c #F0F2F4",
+"A&    c #E2F1DB",
+"B&    c #7EC150",
+"C&    c #81C025",
+"D&    c #82C124",
+"E&    c #7DBF25",
+"F&    c #74BD48",
+"G&    c #D7ECCF",
+"H&    c #E4E5E2",
+"I&    c #DDE4E9",
+"J&    c #BCDFA9",
+"K&    c #81C13F",
+"L&    c #82C024",
+"M&    c #80C024",
+"N&    c #78BE3B",
+"O&    c #AED89A",
+"P&    c #607F91",
+"Q&    c #EBEEF1",
+"R&    c #AFD993",
+"S&    c #86C441",
+"T&    c #CBE5A8",
+"U&    c #D0E9BB",
+"V&    c #C1E2AE",
+"W&    c #5DB435",
+"X&    c #7FBF24",
+"Y&    c #7DC03D",
+"Z&    c #A4D387",
+"`&    c #F8F9F7",
+" *    c #DADDD5",
+".*    c #6D8491",
+"+*    c #638394",
+"@*    c #F2F4F5",
+"#*    c #F9FBF7",
+"$*    c #BADE9E",
+"%*    c #90C950",
+"&*    c #82C128",
+"**    c #7EBF28",
+"=*    c #87C54B",
+"-*    c #B1DA94",
+";*    c #F4F8F1",
+">*    c #E1E4DC",
+",*    c #728792",
+"'*    c #F5F6F7",
+")*    c #FBFCFA",
+"!*    c #D7EBC4",
+"~*    c #9FD06C",
+"{*    c #8BC642",
+"]*    c #81C027",
+"^*    c #81C024",
+"/*    c #7EBF27",
+"(*    c #86C440",
+"_*    c #99CD66",
+":*    c #D1E9BD",
+"<*    c #E2E5DE",
+"[*    c #758893",
+"}*    c #738A97",
+"|*    c #738F9E",
+"1*    c #7793A4",
+"2*    c #FAFAFB",
+"3*    c #D2E9BB",
+"4*    c #B3DA8B",
+"5*    c #98CD5D",
+"6*    c #91C94D",
+"7*    c #8DC746",
+"8*    c #8CC746",
+"9*    c #8FC84D",
+"0*    c #95CB5B",
+"a*    c #B0D886",
+"b*    c #CEE7B6",
+"c*    c #F4F9F1",
+"d*    c #778B96",
+"e*    c #798E9A",
+"f*    c #7C929F",
+"g*    c #8399A7",
+"h*    c #89A1B0",
+"i*    c #90A8B7",
+"j*    c #97ADBC",
+"k*    c #DEE5EA",
+"l*    c #E5EAEE",
+"m*    c #EAEDF0",
+"n*    c #E3E6E8",
+"o*    c #D5DADC",
+"p*    c #F0F1F2",
+"q*    c #FAFBF9",
+"r*    c #F2F8ED",
+"s*    c #E6F3DA",
+"t*    c #D8ECC6",
+"u*    c #D7ECC5",
+"v*    c #E5F2D8",
+"w*    c #F2F8EC",
+"x*    c #F8FAF7",
+"y*    c #F4F4F3",
+"z*    c #E2E4DF",
+"A*    c #8496A2",
+"B*    c #82949E",
+"C*    c #81929C",
+"D*    c #83949E",
+"E*    c #8797A1",
+"F*    c #8B9BA4",
+"G*    c #8D9CA4",
+"H*    c #8D9BA4",
+"I*    c #8B99A1",
+"J*    c #A4AFB6",
+"K*    c #E7EDDF",
+"L*    c #EDEDEB",
+"M*    c #EFEEEE",
+"N*    c #EBEBEB",
+"O*    c #E4E9DD",
+"                            . + @ # $ % & * = - ;                                               ",
+"                > , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 ) 3 4 5                                   ",
+"          6 ' 7 8 9 0 a b > ; c d e e f g h i j k l m n o p q r s t                             ",
+"      u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W y X Y Z                         ",
+"    `  ...+.@.#.$.%.&.*.E =.-.;.>.,.'.).!.M N O ~.Q R {.].^./.(._.:.<.[.}.                      ",
+"    |.1.2.3.M L $.%.&.*.F -.-.;.4.,.'.).!.M N O ~.Q R {.].^./.(.5.6.7.8.9.                      ",
+"    0.a.b.3.M #.K J I c.G ;.;.G H I J d.L M N O P Q R S T ^.e.f.g.h.i.6.j.k.                    ",
+"    l.m.n.o.p.q.r.s.t.&.u.4.4.H ,.v.s.w.x.y.o.z.A.B.C.D.T ^.E.F.g.h.G.H.I.                      ",
+"    J.K.L.M.r.N.L K s.B I ,.,.I v.H.K !.n.O.P.Q.R.S.T.U.V.W.X.F.Y.p.Z.`. +                      ",
+"    .+++@+#+$+%+&+&.*+=+J '.'.J s.K -+q.p.3.O ~.;+>+,+'+S.)+!+&+=.~+{+]+^+                      ",
+"    .+++/+(+_+:+<+[+}+|+%+%+Z.1+2+H 3+4+I.B t.t.4+H F %+-.5+H 6+M )+>+]+^+                      ",
+"    .+++7+(+8+9+0+a+b+c+U d+e+O M L ).f+4+M.&+;.%+0.g+Z.H t.K #.h+)+i+V.^+                      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+)+>+]+^+                      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+)+>+]+^+                      ",
+"    .+++7+(+8+9+0+a+j+k+l+u+n+o+v+q+{.r+P.w+).I |+9.s+;.H t.K #.h+)+i+V.^+                      ",
+"      ++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+)+>+]+                        ",
+"        x+y+z+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.K t+h+P.A+                          ",
+"      B+) C+D+E+F+a+j+k+l+m+n+o+p+q+{.r+P.q.).I 1+9.s+;.H t.G+H+I+J+K+.                         ",
+"    < L+M+N+O+P+P+Q+R+S+T+U+V+W+X+^.{.r+P.N.Y+Z+`+ @.@+@@@#@$@P+%@&@*@=@-@                      ",
+"    g+;@>@,@'@'@,@'@'@'@'@)@!@~@{@]@^@/@(@_@:@<@[@}@'@'@'@,@'@'@'@,@|@1@g+                      ",
+"    2@3@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@4@5@6@7@                    ",
+"    8@9@0@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@b@n c@d@e@e@f@g@h@i@                    ",
+"    j@k@l@m@n@o@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@p@q@r@s@t@u@v@w@x@y@z@A@B@C@                  ",
+"    .+++D@E@F@l@G@H@I@J@K@L@K@L@L@K@L@L@K@L@L@K@L@M@N@O@P@Q@R@S@T@T@T@U@V@W@X@Y@                ",
+"    .+++7+(+Z@`@ #k.F@Z..#+#$+@###$#%#a.&#$#*#=#{ -#;#>#,#'#)#!#~#{#]#^#/#(#_#:#<#[#            ",
+"    .+++/+(+8+9+0+}#|#1#2#3#4#5#6#`.%.4+7#>.G 8#9#0#a#b#c#d#e#e#f#g#e#h#i#j#k#l#m#n#o#          ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.p#q#r#s#t#g#u#v#w#x#y#z#A#B#u#C#e#D#E#F#G#H#        ",
+"    .+++7+(+8+9+0+a+j+k+l+u+n+o+v+q+{.r+P.I#J#K#L#M#N#O#P#Q#R#S#2@2@T#U#V#W#X#v#Y#Z#`# $        ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P..$+$@$#$$$Q#%$&$*$=$-$;$2@T#>$,$'$)$!$~${$]$^$/$      ",
+"      ++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+%#q#($_$:$%$<$[$}$|$1$2$;$2@T#3$4$5$6$&$7$8$9$0$a$      ",
+"        b$c$8+9+0+a+j+k+l+u+n+o+v+q+{.r+d$e$f$g$h$[$i$j$k$l$m$n$2@2@T#o$p$q$r$s$t$u$v$w$x$y$    ",
+"      z$A$X B$C$D$E$j+k+l+m+n+o+p+q+{.F$G$H$I$J$s$r$k$K$L$M$N$O$;$2@T#P$Q$R$S$q$|$T$U$V$W$X$    ",
+"    . Y$Z$`$ %.%P+Q+R++%@%#%$%o+p+q+{.P %%&%*%=%-%;%>%,%'%)%!%~%;$2@{%]%^%,%/%(%_%:%<%[%}%|%    ",
+"    g+1%2%3%3%3%3%3%3%3%3%3%3%)@~@4%5%6%q#7%8%9%0%a%2@2@2@2@2@2@2@2@2@2@2@2@2@2@b%c%9%d%e%a$    ",
+"    f%g%h%i%h%h%i%h%h%h%i%h%i%h%h%i%h%j%q#k%l%9%m%n%2@;$;$2@;$;$;$2@;$;$2@;$;$2@b%o%9%p%q%r%    ",
+"    s%t%u%v%v%v%v%v%v%v%v%v%v%v%v%v%v%w%q#x%y%9%z%A%2@2@2@2@2@2@2@2@2@2@2@2@2@2@b%B%9%C%D%8#    ",
+"    E%F%.#G%H%I%J%K%K%K%J%K%J%K%K%J%K%L%M%N%O%9%P%Q%R%R%S%T%U%V%;$2@W%X%Y%Z%R%R%`% &.&+&@&#&    ",
+"    .+$&%&&&*&=&-&;&>&,&'&)&)&)&)&)&)&!&.$~&{&]&^&^&/&^&^&(&_&:&;$2@T#<&(&^&^&/&^&^&[&}&|&1&    ",
+"    .+++/+(+2&3&4&5&G ;.6&7&8&9&0&a&b&c&d&e&f&g&^&^&/&^&^&/&h&i&;$2@T#j&/&^&^&/&^&^&k&l&m&n&    ",
+"    .+++7+(+8+9+0+a+j+o&p&q&r&M w.s&t&C l@0.u&v&/&/&/&/&/&/&h&i&2@2@T#j&/&/&/&/&/&/&w&x&y&      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.z&A&B&C&^&/&^&^&/&h&i&;$2@T#j&/&^&^&/&D&E&F&G&H&      ",
+"    .+++/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.I&q#J&K&L&/&^&^&/&h&i&;$2@T#j&/&^&^&/&M&N&O&G#        ",
+"    P&++7+(+8+9+0+a+j+k+l+u+n+o+v+q+{.r+P.w+Q&0.R&S&L&/&/&/&^&T&U&U&V&W&/&/&/&X&Y&Z&`& *        ",
+"    .*+*/+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).@*#*$*%*&*L&/&^&^&^&/&^&^&/&L&**=*-*;*>*          ",
+"      ,*S+(+8+9+0+a+j+k+l+m+n+o+p+q+{.r+P.q.).I '*)*!*~*{*]*L&^&^&/&D&^*/*(*_*:*`&<*            ",
+"          [*}*|*1*a+j+k+l+u+n+o+v+q+{.r+P.w+).I |+J#2*V%3*4*5*6*7*8*9*0*a*b*c*r%                ",
+"                d*e*f*g*h*i*j*6.(.^.{.r+P.n.k*l*m*v n*o*p*q*r*s*t*u*v*w*x*y*z*                  ",
+"                            A*B*C*D*E*F*G*G*H*I*J*          K*L*#&M*N*O*                        "};
diff --git a/src/icons/folder-down-48x48.png b/src/icons/folder-down-48x48.png
new file mode 100644 (file)
index 0000000..9928454
Binary files /dev/null and b/src/icons/folder-down-48x48.png differ
diff --git a/src/icons/folder-down.xpm b/src/icons/folder-down.xpm
new file mode 100644 (file)
index 0000000..4785078
--- /dev/null
@@ -0,0 +1,700 @@
+/* XPM */
+static const char * folder_down_xpm[] = {
+"48 48 649 2",
+"      c None",
+".     c #C2AA68",
+"+     c #BBA260",
+"@     c #B79E63",
+"#     c #E9DEA7",
+"$     c #BCA05D",
+"%     c #BB9F5C",
+"&     c #BFA35C",
+"*     c #C0A45B",
+"=     c #C2A65A",
+"-     c #C4A859",
+";     c #C4A958",
+">     c #C3A857",
+",     c #C3A958",
+"'     c #CDB977",
+")     c #F1E8B1",
+"!     c #FFFAC3",
+"~     c #CFB266",
+"{     c #D1B465",
+"]     c #CCAE63",
+"^     c #D0B263",
+"/     c #D1B462",
+"(     c #D1B460",
+"_     c #D0B35E",
+":     c #CFB25D",
+"<     c #CCB05C",
+"[     c #CBAF5B",
+"}     c #CAAE5A",
+"|     c #C8AC59",
+"1     c #C7AB58",
+"2     c #C4A959",
+"3     c #D0BB78",
+"4     c #EBE0A6",
+"5     c #FDF8C1",
+"6     c #FEF9C2",
+"7     c #D9BC72",
+"8     c #CFB36D",
+"9     c #D9BD6F",
+"0     c #E4C772",
+"a     c #EECF73",
+"b     c #F3D473",
+"c     c #F1D272",
+"d     c #EECF6F",
+"e     c #E9CB6C",
+"f     c #E5C66A",
+"g     c #E0C167",
+"h     c #DDBE65",
+"i     c #D9BB63",
+"j     c #D4B761",
+"k     c #CDB05C",
+"l     c #C8AD5F",
+"m     c #D6C280",
+"n     c #F1E8AF",
+"o     c #FFF9C0",
+"p     c #FFFAC0",
+"q     c #FEF9C0",
+"r     c #C6AB6C",
+"s     c #F2D781",
+"t     c #F9DD82",
+"u     c #FADD81",
+"v     c #FADC7E",
+"w     c #FADC7B",
+"x     c #F9DB79",
+"y     c #F9DA77",
+"z     c #F5D673",
+"A     c #E5C76A",
+"B     c #DDBF65",
+"C     c #CCAF5C",
+"D     c #CBB163",
+"E     c #DBC989",
+"F     c #F4EBB1",
+"G     c #FEF8BE",
+"H     c #FFF9BF",
+"I     c #FEF9BF",
+"J     c #E1C77B",
+"K     c #FAE086",
+"L     c #FADE83",
+"M     c #F9DB7B",
+"N     c #F6D674",
+"O     c #EDCE6F",
+"P     c #E1C267",
+"Q     c #CBAF5D",
+"R     c #D7C482",
+"S     c #F6EDB2",
+"T     c #FEF8BD",
+"U     c #E8CE7E",
+"V     c #FBE086",
+"W     c #F2D372",
+"X     c #EACB6C",
+"Y     c #D5B761",
+"Z     c #CAB273",
+"`     c #FDF5BA",
+" .    c #FEF8BC",
+"..    c #FFF8BC",
+"+.    c #EACF7F",
+"@.    c #D0BC80",
+"#.    c #FFF8BB",
+"$.    c #FEF7BA",
+"%.    c #D1BD82",
+"&.    c #FEF7B9",
+"*.    c #F9DA78",
+"=.    c #D5B861",
+"-.    c #D1BD81",
+";.    c #FEF5B6",
+">.    c #D1BD80",
+",.    c #FEF4B3",
+"'.    c #FDF4B3",
+").    c #D1BC7F",
+"!.    c #FDF3B1",
+"~.    c #EACF80",
+"{.    c #FBE087",
+"].    c #FADF84",
+"^.    c #FBDE82",
+"/.    c #FADD7F",
+"(.    c #FADC7C",
+"_.    c #F9DB7A",
+":.    c #FADB78",
+"<.    c #F7D775",
+"[.    c #F3D472",
+"}.    c #EFD070",
+"|.    c #EBCC6D",
+"1.    c #E6C86B",
+"2.    c #E2C368",
+"3.    c #DEC066",
+"4.    c #DABC64",
+"5.    c #D6B962",
+"6.    c #D1B45F",
+"7.    c #D1BC7E",
+"8.    c #FEF3AF",
+"9.    c #FDF2AF",
+"0.    c #D1BC7D",
+"a.    c #FEF2AC",
+"b.    c #FDF1AB",
+"c.    c #FAE087",
+"d.    c #FADD82",
+"e.    c #D1BB7C",
+"f.    c #FDF0A9",
+"g.    c #D0BB7B",
+"h.    c #FDEFA6",
+"i.    c #FCEFA6",
+"j.    c #E6C96B",
+"k.    c #E2C468",
+"l.    c #D2B55F",
+"m.    c #D0BA7A",
+"n.    c #FDEEA4",
+"o.    c #FCEEA4",
+"p.    c #F7D875",
+"q.    c #E7C96B",
+"r.    c #D7B962",
+"s.    c #D0BA79",
+"t.    c #FDEEA2",
+"u.    c #FCEDA2",
+"v.    c #ECCD6D",
+"w.    c #DBBC64",
+"x.    c #D0B978",
+"y.    c #FCEC9F",
+"z.    c #E3C468",
+"A.    c #D0B977",
+"B.    c #FDEB9D",
+"C.    c #FCEB9D",
+"D.    c #F8D876",
+"E.    c #D0B876",
+"F.    c #FCEA9A",
+"G.    c #D0B875",
+"H.    c #FBE998",
+"I.    c #FAE899",
+"J.    c #F0E2A5",
+"K.    c #E7DEB6",
+"L.    c #E3DEC7",
+"M.    c #E2DFD4",
+"N.    c #E0DED8",
+"O.    c #E1DED6",
+"P.    c #E1DDCE",
+"Q.    c #E3DCBF",
+"R.    c #E9DEAD",
+"S.    c #CFB776",
+"T.    c #EDE0AC",
+"U.    c #E4E0D0",
+"V.    c #EDEDEB",
+"W.    c #E2EDE5",
+"X.    c #C3E1CB",
+"Y.    c #97CCA7",
+"Z.    c #8BC79E",
+"`.    c #8EC8A0",
+" +    c #A7D4B4",
+".+    c #D4E8DA",
+"++    c #E8EDE9",
+"@+    c #E1E0E0",
+"#+    c #C9CEC8",
+"$+    c #FADF85",
+"%+    c #FBDE83",
+"&+    c #FADC7D",
+"*+    c #F8D976",
+"=+    c #F4D573",
+"-+    c #F0D170",
+";+    c #ECCD6E",
+">+    c #E7CA6B",
+",+    c #DFC066",
+"'+    c #DBBD64",
+")+    c #D2B86D",
+"!+    c #D6CFBF",
+"~+    c #F1F1F0",
+"{+    c #C8E3CF",
+"]+    c #57AF76",
+"^+    c #169045",
+"/+    c #05883A",
+"(+    c #0D8C41",
+"_+    c #118E44",
+":+    c #0B8B3F",
+"<+    c #07893B",
+"[+    c #2E9B57",
+"}+    c #85C59A",
+"|+    c #E6EFE8",
+"1+    c #E2E1E1",
+"2+    c #FAE088",
+"3+    c #FADD80",
+"4+    c #F0D171",
+"5+    c #EDCE6E",
+"6+    c #E8CA6C",
+"7+    c #E4C569",
+"8+    c #DFC067",
+"9+    c #DCBD65",
+"0+    c #D7C080",
+"a+    c #E4E1DA",
+"b+    c #E0EFE4",
+"c+    c #58B176",
+"d+    c #058A39",
+"e+    c #159347",
+"f+    c #289D56",
+"g+    c #31A25D",
+"h+    c #30A15D",
+"i+    c #249A53",
+"j+    c #108F42",
+"k+    c #179245",
+"l+    c #9ACFAB",
+"m+    c #EEEEEE",
+"n+    c #C6CFC9",
+"o+    c #FBE088",
+"p+    c #FADB79",
+"q+    c #DAC37F",
+"r+    c #E8E6DE",
+"s+    c #CEE7D4",
+"t+    c #22994D",
+"u+    c #0F9241",
+"v+    c #2AA058",
+"w+    c #31A45D",
+"x+    c #32A55E",
+"y+    c #32A65E",
+"z+    c #35A760",
+"A+    c #34A860",
+"B+    c #34A760",
+"C+    c #33A65F",
+"D+    c #31A55D",
+"E+    c #32A45E",
+"F+    c #31A35D",
+"G+    c #259C53",
+"H+    c #0B8F3E",
+"I+    c #6BBA86",
+"J+    c #E8EEE9",
+"K+    c #CECFCE",
+"L+    c #E9CF80",
+"M+    c #DEC16F",
+"N+    c #E6E2D7",
+"O+    c #D2E9D7",
+"P+    c #1C9848",
+"Q+    c #169748",
+"R+    c #30A55C",
+"S+    c #31A75D",
+"T+    c #32A95D",
+"U+    c #34AA5D",
+"V+    c #4DB570",
+"W+    c #D2ECDB",
+"X+    c #D1ECDB",
+"Y+    c #96D2AF",
+"Z+    c #24A354",
+"`+    c #31A85D",
+" @    c #2EA25A",
+".@    c #0D9240",
+"+@    c #67BA82",
+"@@    c #EFF0EF",
+"#@    c #BECAC2",
+"$@    c #EDD382",
+"%@    c #F8D977",
+"&@    c #E4C66A",
+"*@    c #E0D5B4",
+"=@    c #EAF4EC",
+"-@    c #2FA257",
+";@    c #149846",
+">@    c #32A85D",
+",@    c #35AB5D",
+"'@    c #3BAD5D",
+")@    c #42AF5C",
+"!@    c #48B05C",
+"~@    c #67BD74",
+"{@    c #FEFEFE",
+"]@    c #B4DEC6",
+"^@    c #2DA451",
+"/@    c #45AF5C",
+"(@    c #3EAD5C",
+"_@    c #37AC5D",
+":@    c #2EA55B",
+"<@    c #0D943F",
+"[@    c #8BCB9F",
+"}@    c #E8E7E7",
+"|@    c #D3B976",
+"1@    c #F9DF89",
+"2@    c #F9D977",
+"3@    c #E2CA82",
+"4@    c #F1F0EE",
+"5@    c #79C490",
+"6@    c #0B963E",
+"7@    c #31A95B",
+"8@    c #3EAD5D",
+"9@    c #50B25C",
+"0@    c #57B45C",
+"a@    c #5BB65B",
+"b@    c #76C273",
+"c@    c #FFFFFF",
+"d@    c #39A850",
+"e@    c #58B55B",
+"f@    c #53B35C",
+"g@    c #4CB15C",
+"h@    c #42AE5C",
+"i@    c #29A557",
+"j@    c #0F9640",
+"k@    c #DAECDE",
+"l@    c #D3D5D3",
+"m@    c #BDA36A",
+"n@    c #F1D889",
+"o@    c #FAE28D",
+"p@    c #FBE18A",
+"q@    c #F5D573",
+"r@    c #F1D271",
+"s@    c #E9CA6C",
+"t@    c #E4D9B8",
+"u@    c #E7F3E9",
+"v@    c #0C983C",
+"w@    c #2BA752",
+"x@    c #52B35C",
+"y@    c #59B55B",
+"z@    c #60B85B",
+"A@    c #66BB5B",
+"B@    c #69BC5B",
+"C@    c #82C774",
+"D@    c #42AC50",
+"E@    c #67BB5B",
+"F@    c #62B95B",
+"G@    c #5CB75B",
+"H@    c #55B45C",
+"I@    c #4AB15C",
+"J@    c #3DAD5C",
+"K@    c #1A9F49",
+"L@    c #69BE84",
+"M@    c #ECEBEB",
+"N@    c #D7BE7B",
+"O@    c #FAE38F",
+"P@    c #FAE18A",
+"Q@    c #E7CB75",
+"R@    c #EFECE4",
+"S@    c #8DCF9F",
+"T@    c #2AA43C",
+"U@    c #4BB05B",
+"V@    c #57B55B",
+"W@    c #61B85B",
+"X@    c #68BC5B",
+"Y@    c #6EBE5C",
+"Z@    c #72C05F",
+"`@    c #76C161",
+" #    c #8CCB7A",
+".#    c #4AAF54",
+"+#    c #74C060",
+"@#    c #70BE5D",
+"##    c #6ABD5B",
+"$#    c #64BA5B",
+"%#    c #51B25C",
+"&#    c #42AE59",
+"*#    c #27A442",
+"=#    c #E3EFE6",
+"-#    c #C6D2C5",
+";#    c #DFC680",
+">#    c #FBE38F",
+",#    c #E6D08B",
+"'#    c #F5F6F4",
+")#    c #52B567",
+"!#    c #79C040",
+"~#    c #61B85A",
+"{#    c #6CBE5C",
+"]#    c #75C061",
+"^#    c #7DC46D",
+"/#    c #78C166",
+"(#    c #80C56A",
+"_#    c #94CE80",
+":#    c #50B159",
+"<#    c #7EC469",
+"[#    c #7CC367",
+"}#    c #7AC36A",
+"|#    c #6ABD5C",
+"1#    c #68BB5B",
+"2#    c #5EB75B",
+"3#    c #71BF56",
+"4#    c #48AE3B",
+"5#    c #B1DDBA",
+"6#    c #DCDBDB",
+"7#    c #E0C881",
+"8#    c #E7D5A1",
+"9#    c #EBF4EB",
+"0#    c #45AC43",
+"a#    c #92CA46",
+"b#    c #87C753",
+"c#    c #6FBE5C",
+"d#    c #76C162",
+"e#    c #B5DDA9",
+"f#    c #E0F1E5",
+"g#    c #51B369",
+"h#    c #73BE5A",
+"i#    c #8AC870",
+"j#    c #48AD4D",
+"k#    c #77BF5B",
+"l#    c #BDE1B1",
+"m#    c #D8EEDE",
+"n#    c #4DB165",
+"o#    c #70BF5E",
+"p#    c #71BF59",
+"q#    c #96CC50",
+"r#    c #6ABA42",
+"s#    c #8DCE98",
+"t#    c #E0C781",
+"u#    c #E9DBB1",
+"v#    c #E4F2E4",
+"w#    c #48AC33",
+"x#    c #98CD4C",
+"y#    c #9BCE4F",
+"z#    c #87C75A",
+"A#    c #BADFAF",
+"B#    c #FCFEFC",
+"C#    c #E0F1E7",
+"D#    c #55B469",
+"E#    c #8DC973",
+"F#    c #50B052",
+"G#    c #B9DEA8",
+"H#    c #DEF1E6",
+"I#    c #4EB265",
+"J#    c #8DC951",
+"K#    c #9BCE4E",
+"L#    c #7BC147",
+"M#    c #77C377",
+"N#    c #EEEDED",
+"O#    c #DFC780",
+"P#    c #FAE085",
+"Q#    c #EADDB6",
+"R#    c #E5F2E4",
+"S#    c #50AF30",
+"T#    c #9ACE4E",
+"U#    c #9CCF4F",
+"V#    c #ADD76E",
+"W#    c #FAFDF8",
+"X#    c #DDF0E5",
+"Y#    c #72C185",
+"Z#    c #B8E0C9",
+"`#    c #9AD2A4",
+" $    c #AEDCC1",
+".$    c #65B94B",
+"+$    c #81C448",
+"@$    c #74C16D",
+"#$    c #EFEFEF",
+"$$    c #DEC680",
+"%$    c #FAE390",
+"&$    c #FAE28E",
+"*$    c #FAE18B",
+"=$    c #F9DB7C",
+"-$    c #EADCB1",
+";$    c #E7F3E5",
+">$    c #56B233",
+",$    c #98CD4D",
+"'$    c #94CA41",
+")$    c #BADD84",
+"!$    c #FCFDFA",
+"~$    c #EBF6F0",
+"{$    c #F1F9F4",
+"]$    c #FAFDFB",
+"^$    c #D9EFE3",
+"/$    c #52B14D",
+"($    c #92CA47",
+"_$    c #80C346",
+":$    c #86C97B",
+"<$    c #DEC580",
+"[$    c #FBE390",
+"}$    c #FBE18B",
+"|$    c #FBE189",
+"1$    c #FBDF84",
+"2$    c #FADD7E",
+"3$    c #FADB7A",
+"4$    c #E9D8A1",
+"5$    c #EFF6ED",
+"6$    c #66B948",
+"7$    c #93CB47",
+"8$    c #98CC48",
+"9$    c #84C227",
+"0$    c #83C124",
+"a$    c #B6DB7E",
+"b$    c #FBFDF9",
+"c$    c #D2ECDC",
+"d$    c #51B14B",
+"e$    c #81C024",
+"f$    c #88C42D",
+"g$    c #9ACE4D",
+"h$    c #78C043",
+"i$    c #A6D79A",
+"j$    c #EBEAEA",
+"k$    c #DDC47F",
+"l$    c #E9D28B",
+"m$    c #F8F8F6",
+"n$    c #84C770",
+"o$    c #88C640",
+"p$    c #8BC532",
+"q$    c #82C023",
+"r$    c #84C126",
+"s$    c #D2EBDC",
+"t$    c #56B34D",
+"u$    c #7EBF24",
+"v$    c #8FC83C",
+"w$    c #6CBB40",
+"x$    c #CBE7C3",
+"y$    c #DCC47F",
+"z$    c #E9CD74",
+"A$    c #F4F1E7",
+"B$    c #B9DEAC",
+"C$    c #73BD39",
+"D$    c #83C125",
+"E$    c #B9DC83",
+"F$    c #D9EFE2",
+"G$    c #7FC02A",
+"H$    c #71BD52",
+"I$    c #EEF5EC",
+"J$    c #D2DACD",
+"K$    c #DCC37E",
+"L$    c #EACC6D",
+"M$    c #EBDEB8",
+"N$    c #F4F9F2",
+"O$    c #73BD4F",
+"P$    c #7EBF26",
+"Q$    c #D3ECDD",
+"R$    c #50B04A",
+"S$    c #72BB33",
+"T$    c #A7D697",
+"U$    c #F2F1F1",
+"V$    c #DBC27E",
+"W$    c #E6CD80",
+"X$    c #F7F5F1",
+"Y$    c #BADEAA",
+"Z$    c #79BE3B",
+"`$    c #82C024",
+" %    c #BFDF8D",
+".%    c #FDFEFD",
+"+%    c #DCF0E4",
+"@%    c #56B354",
+"#%    c #7DBF24",
+"$%    c #7BBE29",
+"%%    c #7AC054",
+"&%    c #EEF6EA",
+"*%    c #DDE1D9",
+"=%    c #DAC27D",
+"-%    c #FBE391",
+";%    c #F6D774",
+">%    c #EADCB5",
+",%    c #F6FAF5",
+"'%    c #99CE7A",
+")%    c #7EBF32",
+"!%    c #C2E194",
+"~%    c #E4F3EA",
+"{%    c #52B253",
+"]%    c #7DBF25",
+"^%    c #7FBF25",
+"/%    c #7CC047",
+"(%    c #C8E5BA",
+"_%    c #F1F1F1",
+":%    c #D7BF7B",
+"<%    c #E6C76A",
+"[%    c #E1C36C",
+"}%    c #EFEEE2",
+"|%    c #EDF6E8",
+"1%    c #99CE74",
+"2%    c #81C132",
+"3%    c #B6DA7F",
+"4%    c #66B94F",
+"5%    c #81C249",
+"6%    c #BBDEA6",
+"7%    c #F9F9F9",
+"8%    c #CBB273",
+"9%    c #F3F3F2",
+"0%    c #A6D47E",
+"a%    c #88C540",
+"b%    c #81C026",
+"c%    c #82C124",
+"d%    c #80C02D",
+"e%    c #8FC857",
+"f%    c #C4E3AF",
+"g%    c #F7F9F6",
+"h%    c #DDE2D7",
+"i%    c #E3CA81",
+"j%    c #F8E08D",
+"k%    c #F6D87A",
+"l%    c #F8D979",
+"m%    c #F7FAF4",
+"n%    c #C5E3AA",
+"o%    c #96CC5E",
+"p%    c #86C439",
+"q%    c #80C025",
+"r%    c #80C024",
+"s%    c #80C02B",
+"t%    c #8BC749",
+"u%    c #A5D379",
+"v%    c #DDEED0",
+"w%    c #DEE2D8",
+"x%    c #D5BB76",
+"y%    c #F9DF88",
+"z%    c #F8DD85",
+"A%    c #F5DA81",
+"B%    c #E8EBE3",
+"C%    c #FAFAFA",
+"D%    c #EFF7E9",
+"E%    c #C8E4AC",
+"F%    c #ACD77F",
+"G%    c #96CB58",
+"H%    c #90C94C",
+"I%    c #8DC747",
+"J%    c #8EC848",
+"K%    c #92CA50",
+"L%    c #9CCF65",
+"M%    c #B6DC91",
+"N%    c #D9ECC7",
+"O%    c #FAFBF9",
+"P%    c #E4DCCD",
+"Q%    c #FAF8F2",
+"R%    c #F8FAF5",
+"S%    c #F2F8EC",
+"T%    c #E1F0D3",
+"U%    c #D8ECC5",
+"V%    c #DAEDC9",
+"W%    c #EBF5E1",
+"X%    c #F3F8EE",
+"Y%    c #FAFAF9",
+"Z%    c #F2F2F1",
+"`%    c #E0E6D9",
+" &    c #C5AC71",
+".&    c #F3D57F",
+"+&    c #E9EBE1",
+"@&    c #EAECE8",
+"#&    c #E3EADB",
+"                                                                . + @ #                         ",
+"                                                $ % & * = - ; > , ' ) !                         ",
+"                                  ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 6 6                         ",
+"                  7 8 9 0 a b c d e f g h i j _ : k [ } l m n o p q p p                         ",
+"            r s t u v w x y z c d e A g B i j _ : C D E F G H H H I H H                         ",
+"            J K L u v M x y N c O e A P B i j _ Q R S T T T T T T T T T                         ",
+"            U V L u v w x y N W d X A P B i Y _ Z `  ..... ....... .....                        ",
+"            +.V L u v w x y N W d X A P B i Y _ @.#.$.#.#.$.#.#.#.$.#.#.                        ",
+"            +.K L u v M x y N W d X A P B i Y _ %.&.&.&.&.&.&.&.&.&.&.&.                        ",
+"            +.V L u v w x *.N W d X A P B i =._ -.;.;.;.;.;.;.;.;.;.;.;.                        ",
+"            +.V L u v w x *.N W d X A P B i =._ >.,.'.,.,.'.,.,.,.'.,.,.                        ",
+"            +.K L u v M x y N W d X A P B i =._ ).!.!.!.!.!.!.!.!.!.!.!.                        ",
+"            ~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.8.8.9.8.8.8.9.8.8.                        ",
+"            ~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.0.a.b.a.a.b.a.a.a.b.a.a.                        ",
+"            +.c.].d./.(._.*.<.[.}.|.1.2.3.4.5.6.e.f.f.f.f.f.f.f.f.f.f.f.                        ",
+"            ~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.g.h.i.h.h.i.h.h.h.i.h.h.                        ",
+"            ~.{.].^./.(._.:.<.[.}.|.j.k.3.4.5.l.m.n.o.n.n.o.n.n.n.o.n.n.                        ",
+"            ~.{.].^./.(._.:.p.[.}.|.q.k.3.4.r.l.s.t.u.t.t.u.t.t.t.u.t.t.                        ",
+"            +.c.].d./.(._.*.p.[.}.v.q.2.3.w.r.l.x.y.y.y.y.y.y.y.y.y.y.y.                        ",
+"            ~.{.].^./.(._.:.p.[.}.v.q.z.3.w.r.l.A.B.C.B.B.C.B.B.B.C.B.B.                        ",
+"            ~.{.].^./.(._.:.D.[.}.v.q.z.3.w.r.l.E.F.F.F.F.F.F.F.F.F.F.F.                        ",
+"            +.c.].d./.(._.*.D.[.}.v.q.z.3.w.r.l.G.H.I.J.K.L.M.N.O.P.Q.R.                        ",
+"            ~.{.].^./.(._.:.D.[.}.v.q.z.3.w.r.l.S.T.U.V.W.X.Y.Z.`. +.+++@+#+                    ",
+"            ~.{.$+%+/.&+_.:.*+=+-+;+>+z.,+'+r.)+!+~+{+]+^+/+(+_+_+:+<+[+}+|+1+                  ",
+"            ~.2+$+L 3+&+M x *+=+4+5+6+7+8+9+0+a+b+c+d+e+f+g+g+g+g+g+h+i+j+k+l+m+n+              ",
+"            ~.o+$+%+3+&+M p+*+=+4+5+6+7+8+q+r+s+t+u+v+w+x+y+z+A+B+C+D+E+F+G+H+I+J+K+            ",
+"            L+o+$+%+3+&+M p+*+=+4+5+6+7+M+N+O+P+Q+R+S+T+U+V+W+X+X+Y+Z+T+`+y+ @.@+@@@#@          ",
+"            $@2+$+L 3+&+M x %@=+4+5+6+&@*@=@-@;@>@,@'@)@!@~@{@{@{@]@^@/@(@_@T+:@<@[@}@          ",
+"          |@1@o+$+%+3+&+M p+2@=+4+5+6+3@4@5@6@7@8@!@9@0@a@b@c@c@c@]@d@e@f@g@h@_@i@j@k@l@        ",
+"      m@n@o@p@o+$+%+3+&+M p+y q@r@5+s@t@u@v@w@/@x@y@z@A@B@C@c@c@c@]@D@E@F@G@H@I@J@K@L@M@        ",
+"      N@O@o@P@2+$+L 3+&+M x y q@r@5+Q@R@S@T@U@V@W@X@Y@Z@`@ #{@{@{@]@.#+#@###$#a@%#&#*#=#-#      ",
+"      ;#>#o@p@o+$+%+u &+M p+y q@r@5+,#'#)#!#~#$#{#]#^#/#(#_#c@c@c@]@:#<#[#}#|#1#2#3#4#5#6#      ",
+"      7#>#o@p@o+$+%+u &+M p+y q@r@5+8#9#0#a#b#c#d#e#f#g#h#i#c@c@c@]@j#k#l#m#n#o#p#q#r#s#}@      ",
+"      t#O@o@P@2+$+L 3+&+M x y q@r@5+u#v#w#x#y#z#A#B#{@C#D#E#{@{@{@]@F#G#{@{@H#I#J#K#L#M#N#      ",
+"      O#>#o@p@o+P#%+u v M p+y q@r@5+Q#R#S#T#U#V#W#c@{@c@X#Y#c@c@c@Z#`#B#{@c@c@ $.$U#+$@$#$      ",
+"      $$%$&$*$2+K ].u v =$x *.N W d -$;$>$,$K#'$)$!${@{@{@~${@{@{@{$]${@{@{@^$/$($K#_$:$m+      ",
+"      <$[$&$}$|$K 1$u 2$=$3$*.N W d 4$5$6$7$8$9$0$a$b$c@c@{@c@c@c@{@c@c@{@c$d$e$f$g$h$i$j$      ",
+"      k$[$&$}$|$K 1$u 2$=$3$*.N W d l$m$n$o$p$q$0$r$a$!$c@{@c@c@c@{@c@c@s$t$u$q$0$v$w$x$@+      ",
+"      y$[$&$}$|$K 1$u 2$=$3$*.N W d z$A$B$C$D$q$0$0$0$E$!${@c@c@c@{@c@F$d$u$0$q$0$G$H$I$J$      ",
+"      K$%$&$*$2+K ].u v =$x *.N W d L$M$N$O$P$q$q$q$q$0$a$!${@{@{@{@Q$R$e$q$q$q$e$S$T$U$        ",
+"      V$[$&$}$|$K 1$d.2$=$3$*.N W d L$W$X$Y$Z$`$0$0$q$0$r$ %.%c@c@+%@%#%q$0$0$q$$%%%&%*%        ",
+"      =%-%&$}$|$K 1$d.2$=$3$*.;%W d L$1.>%,%'%)%0$0$q$0$0$q$!%.%~%{%]%0$q$0$0$^%/%(%_%          ",
+"      :%%$&$*$2+K ].d.v =$x *.;%W d L$<%[%}%|%1%2%`$q$q$q$q$q$3%4%e$q$q$q$q$^%5%6%7%            ",
+"      8%%$&$}$|$K 1$d.2$=$3$*.N c d         9%|%0%a%b%c%0$q$0$0$0$q$0$0$e$d%e%f%g%h%            ",
+"        i%j%}$|$K 1$d.2$k%l%                  U$m%n%o%p%q%`$0$0$0$q$r%s%t%u%v%7%w%              ",
+"            x%y%z%A%                            B%C%D%E%F%G%H%I%J%K%L%M%N%O%_%                  ",
+"                                                    P%Q%R%S%T%U%V%W%X%Y%Z%`%                    ",
+"                                                     &.&  +&N##$m+@&#&                          "};
diff --git a/src/icons/help-48x48.png b/src/icons/help-48x48.png
new file mode 100644 (file)
index 0000000..5a848a8
Binary files /dev/null and b/src/icons/help-48x48.png differ
diff --git a/src/icons/help.xpm b/src/icons/help.xpm
new file mode 100644 (file)
index 0000000..d73f820
--- /dev/null
@@ -0,0 +1,716 @@
+/* XPM */
+static const char * help_xpm[] = {
+"48 48 665 2",
+"      c None",
+".     c #D9D9DB",
+"+     c #D5D4D5",
+"@     c #D4D3D3",
+"#     c #D6D5D5",
+"$     c #D5D4D4",
+"%     c #D3D2D2",
+"&     c #D3D2D3",
+"*     c #D6D7D9",
+"=     c #D5D5D6",
+"-     c #DBDBDB",
+";     c #E5E4E4",
+">     c #ECECEC",
+",     c #F2F2F2",
+"'     c #F5F5F5",
+")     c #F7F7F7",
+"!     c #F8F7F7",
+"~     c #F6F6F6",
+"{     c #F5F4F4",
+"]     c #F0F0F0",
+"^     c #EAE9E9",
+"/     c #E1E1E1",
+"(     c #D7D7D7",
+"_     c #D0D0D1",
+":     c #D9D9D9",
+"<     c #E7E7E7",
+"[     c #F3F3F3",
+"}     c #FAFAFA",
+"|     c #FDFDFD",
+"1     c #F2F5F8",
+"2     c #DDE4EF",
+"3     c #FCFCFC",
+"4     c #F8F8F8",
+"5     c #EFEFEF",
+"6     c #E2E1E1",
+"7     c #DADADA",
+"8     c #F9F9F9",
+"9     c #FEFEFE",
+"0     c #FCFDFD",
+"a     c #D7DDE9",
+"b     c #9FA9C9",
+"c     c #6B76AA",
+"d     c #3A4B8F",
+"e     c #222F7E",
+"f     c #202A7A",
+"g     c #3A4A8F",
+"h     c #D7DDEA",
+"i     c #E6E5E5",
+"j     c #D6D6D7",
+"k     c #E8E7E7",
+"l     c #F2F4F8",
+"m     c #ABB4D0",
+"n     c #52619C",
+"o     c #283581",
+"p     c #1F2C7B",
+"q     c #202C7B",
+"r     c #202E7C",
+"s     c #22307D",
+"t     c #23317E",
+"u     c #24327E",
+"v     c #24327F",
+"w     c #202D7C",
+"x     c #E0DFDF",
+"y     c #CECDCF",
+"z     c #DCDCDD",
+"A     c #F2F1F1",
+"B     c #ADB7D2",
+"C     c #425293",
+"D     c #1F2D7B",
+"E     c #1E2E7C",
+"F     c #1F2F7D",
+"G     c #2B3B85",
+"H     c #37468B",
+"I     c #3F4F91",
+"J     c #445494",
+"K     c #475696",
+"L     c #485897",
+"M     c #3F4E91",
+"N     c #2B3B84",
+"O     c #202F7D",
+"P     c #1F2E7C",
+"Q     c #D3D3D3",
+"R     c #E1E0E0",
+"S     c #DFE4EE",
+"T     c #52649F",
+"U     c #1E2F7D",
+"V     c #1D2F7D",
+"W     c #243682",
+"X     c #35488D",
+"Y     c #445696",
+"Z     c #485A99",
+"`     c #475B99",
+" .    c #475A99",
+"..    c #485A98",
+"+.    c #455696",
+"@.    c #36478D",
+"#.    c #53659F",
+"$.    c #F1F1F1",
+"%.    c #D7D6D6",
+"&.    c #E4E3E3",
+"*.    c #B5C0D8",
+"=.    c #32468C",
+"-.    c #1C307E",
+";.    c #203581",
+">.    c #33488D",
+",.    c #445897",
+"'.    c #465B99",
+").    c #465C9A",
+"!.    c #455D9A",
+"~.    c #455C9A",
+"{.    c #465C99",
+"].    c #34488D",
+"^.    c #213581",
+"/.    c #32458B",
+"(.    c #B5BFD7",
+"_.    c #F3F2F2",
+":.    c #D9D8D9",
+"<.    c #E2E2E2",
+"[.    c #A4B1CF",
+"}.    c #233984",
+"|.    c #1B317F",
+"1.    c #273D86",
+"2.    c #405595",
+"3.    c #445E9B",
+"4.    c #435F9C",
+"5.    c #425F9C",
+"6.    c #41609C",
+"7.    c #435E9B",
+"8.    c #405495",
+"9.    c #1C317E",
+"0.    c #233883",
+"a.    c #DFDFDF",
+"b.    c #A3B1CF",
+"c.    c #1B3280",
+"d.    c #1B3480",
+"e.    c #2C468C",
+"f.    c #445C99",
+"g.    c #435F9B",
+"h.    c #415F9C",
+"i.    c #40609C",
+"j.    c #3F619D",
+"k.    c #4D6DA4",
+"l.    c #708AB6",
+"m.    c #92A5C7",
+"n.    c #A4B2CF",
+"o.    c #B0BDD6",
+"p.    c #B8C5DA",
+"q.    c #AEB9D4",
+"r.    c #9EA9CA",
+"s.    c #7B87B5",
+"t.    c #586CA4",
+"u.    c #3D5897",
+"v.    c #40609D",
+"w.    c #445D9A",
+"x.    c #445B99",
+"y.    c #2D458B",
+"z.    c #1B3380",
+"A.    c #1B327F",
+"B.    c #D3D3D4",
+"C.    c #DADADB",
+"D.    c #F4F4F4",
+"E.    c #B4C1D8",
+"F.    c #213B85",
+"G.    c #193581",
+"H.    c #2E498D",
+"I.    c #425D9A",
+"J.    c #3E629D",
+"K.    c #3D639E",
+"L.    c #5778AB",
+"M.    c #B1C0D8",
+"N.    c #EBEFF5",
+"O.    c #FFFFFF",
+"P.    c #FEFEFF",
+"Q.    c #F4F3F8",
+"R.    c #CDCCDF",
+"S.    c #6D70A6",
+"T.    c #3D5394",
+"U.    c #3E609C",
+"V.    c #3F609D",
+"W.    c #1A3481",
+"X.    c #213A85",
+"Y.    c #B5C1D8",
+"Z.    c #ECEBEB",
+"`.    c #DFE5EF",
+" +    c #2E4A8F",
+".+    c #173581",
+"++    c #2A488D",
+"@+    c #405E9B",
+"#+    c #3E619D",
+"$+    c #3D629E",
+"%+    c #3B639E",
+"&+    c #39639F",
+"*+    c #7F9BC1",
+"=+    c #EFF2F7",
+"-+    c #FCFCFD",
+";+    c #B7B1CF",
+">+    c #3E438B",
+",+    c #3B609C",
+"'+    c #3D629D",
+")+    c #415E9B",
+"!+    c #183481",
+"~+    c #2F498E",
+"{+    c #DFE5EE",
+"]+    c #FBFBFB",
+"^+    c #4E6AA3",
+"/+    c #163682",
+"(+    c #20438A",
+"_+    c #3E5F9C",
+":+    c #3C639E",
+"<+    c #3A639F",
+"[+    c #3764A0",
+"}+    c #3565A0",
+"|+    c #7B9BC1",
+"1+    c #F9FBFC",
+"2+    c #D6D2E3",
+"3+    c #3A3A85",
+"4+    c #375F9C",
+"5+    c #3B639F",
+"6+    c #3F5F9C",
+"7+    c #214289",
+"8+    c #173681",
+"9+    c #4E69A2",
+"0+    c #A9BAD4",
+"a+    c #143883",
+"b+    c #173D87",
+"c+    c #375B99",
+"d+    c #3366A1",
+"e+    c #507CAE",
+"f+    c #F4F7FA",
+"g+    c #B1AACB",
+"h+    c #303B86",
+"i+    c #38649F",
+"j+    c #385A99",
+"k+    c #183D86",
+"l+    c #163782",
+"m+    c #AAB9D4",
+"n+    c #F1F4F8",
+"o+    c #385B99",
+"p+    c #123984",
+"q+    c #285093",
+"r+    c #37649F",
+"s+    c #3366A0",
+"t+    c #3267A1",
+"u+    c #3469A3",
+"v+    c #B7CADF",
+"w+    c #FAFAFC",
+"x+    c #584D91",
+"y+    c #305898",
+"z+    c #3466A0",
+"A+    c #3665A0",
+"B+    c #3C629E",
+"C+    c #295092",
+"D+    c #A5B8D3",
+"E+    c #113A85",
+"F+    c #15428A",
+"G+    c #36619E",
+"H+    c #3466A1",
+"I+    c #3268A2",
+"J+    c #3168A3",
+"K+    c #507FB1",
+"L+    c #F7F9FB",
+"M+    c #E5E3EE",
+"N+    c #A6A9CA",
+"O+    c #9CAFCE",
+"P+    c #C2D2E4",
+"Q+    c #FAFBFD",
+"R+    c #A29BC1",
+"S+    c #2C3F89",
+"T+    c #3267A2",
+"U+    c #3266A1",
+"V+    c #3465A0",
+"W+    c #37609D",
+"X+    c #174289",
+"Y+    c #113984",
+"Z+    c #A6B8D3",
+"`+    c #466BA3",
+" @    c #0C3E88",
+".@    c #235395",
+"+@    c #3268A3",
+"@@    c #3269A4",
+"#@    c #316BA4",
+"$@    c #8CADCD",
+"%@    c #D4D0E2",
+"&@    c #42478D",
+"*@    c #3068A3",
+"=@    c #3270A8",
+"-@    c #3472AA",
+";@    c #9FBCD7",
+">@    c #CDC9DD",
+",@    c #2A2F7F",
+"'@    c #3169A3",
+")@    c #245395",
+"!@    c #0D3D87",
+"~@    c #466AA3",
+"{@    c #E6E5E6",
+"]@    c #D4DFEB",
+"^@    c #15458C",
+"/@    c #05569D",
+"(@    c #2F639F",
+"_@    c #3269A3",
+":@    c #326AA4",
+"<@    c #326BA5",
+"[@    c #316CA5",
+"}@    c #B8CCE0",
+"|@    c #645898",
+"1@    c #2F5D9D",
+"2@    c #3171AA",
+"3@    c #3271AA",
+"4@    c #6292BE",
+"5@    c #DCD9E7",
+"6@    c #292A7B",
+"7@    c #30629F",
+"8@    c #06569C",
+"9@    c #17458C",
+"0@    c #D5DFEB",
+"a@    c #EFEEEE",
+"b@    c #96AFCE",
+"c@    c #06428B",
+"d@    c #0F6CAD",
+"e@    c #3274AD",
+"f@    c #3169A4",
+"g@    c #316BA5",
+"h@    c #316CA6",
+"i@    c #316DA7",
+"j@    c #ABC4DB",
+"k@    c #D8E4EE",
+"l@    c #E9EEF4",
+"m@    c #F3F2F7",
+"n@    c #2B287A",
+"o@    c #2E6DA8",
+"p@    c #2E71AA",
+"q@    c #2F71AA",
+"r@    c #83ABCD",
+"s@    c #CCC7DC",
+"t@    c #2A3180",
+"u@    c #316AA4",
+"v@    c #3273AD",
+"w@    c #08428B",
+"x@    c #97AFCE",
+"y@    c #F6F5F5",
+"z@    c #5A82B2",
+"A@    c #024A92",
+"B@    c #1B76B4",
+"C@    c #3282B9",
+"D@    c #326DA6",
+"E@    c #326CA5",
+"F@    c #326EA7",
+"G@    c #316FA8",
+"H@    c #3270A9",
+"I@    c #3875AC",
+"J@    c #417BB0",
+"K@    c #4A83B5",
+"L@    c #5C90BD",
+"M@    c #6F9AC3",
+"N@    c #80A8CB",
+"O@    c #7EA1C7",
+"P@    c #133A87",
+"Q@    c #09599D",
+"R@    c #08599C",
+"S@    c #3F7EB2",
+"T@    c #E8EFF6",
+"U@    c #968EB9",
+"V@    c #2D488F",
+"W@    c #316EA7",
+"X@    c #326CA6",
+"Y@    c #3281B9",
+"Z@    c #1B76B3",
+"`@    c #034A92",
+" #    c #5C82B2",
+".#    c #225B9B",
+"+#    c #01539A",
+"@#    c #267DB7",
+"##    c #3285BC",
+"$#    c #327BB4",
+"%#    c #326DA7",
+"&#    c #326FA8",
+"*#    c #3170A9",
+"=#    c #3172AB",
+"-#    c #1E67A4",
+";#    c #0C5C9E",
+">#    c #03559B",
+",#    c #00549A",
+"'#    c #00559A",
+")#    c #4483B6",
+"!#    c #E6EEF5",
+"~#    c #F2F1F6",
+"{#    c #484089",
+"]#    c #3067A3",
+"^#    c #327BB3",
+"/#    c #267CB7",
+"(#    c #235B9A",
+"_#    c #E3E3E3",
+":#    c #03458D",
+"<#    c #035BA0",
+"[#    c #2B80B9",
+"}#    c #3185BC",
+"|#    c #3186BD",
+"1#    c #3177B0",
+"2#    c #3171A9",
+"3#    c #3172AA",
+"4#    c #2F72AA",
+"5#    c #06589C",
+"6#    c #00559B",
+"7#    c #00569B",
+"8#    c #00579C",
+"9#    c #02599D",
+"0#    c #6398C2",
+"a#    c #F9FBFD",
+"b#    c #8077AB",
+"c#    c #2C5195",
+"d#    c #3170A8",
+"e#    c #3177AF",
+"f#    c #035AA0",
+"g#    c #05448D",
+"h#    c #D2D3D4",
+"i#    c #F1F6F9",
+"j#    c #00428B",
+"k#    c #0460A5",
+"l#    c #2F83BB",
+"m#    c #3286BD",
+"n#    c #3276AE",
+"o#    c #286DA8",
+"p#    c #0D5C9E",
+"q#    c #01549A",
+"r#    c #00569C",
+"s#    c #00579D",
+"t#    c #00589D",
+"u#    c #00589E",
+"v#    c #045BA0",
+"w#    c #7DAACE",
+"x#    c #FBFBFC",
+"y#    c #9A94BD",
+"z#    c #143987",
+"A#    c #0E5B9D",
+"B#    c #3275AE",
+"C#    c #3186BC",
+"D#    c #2F82BB",
+"E#    c #0460A4",
+"F#    c #E4E4E4",
+"G#    c #DBE7F0",
+"H#    c #00448D",
+"I#    c #0562A7",
+"J#    c #3084BB",
+"K#    c #3187BE",
+"L#    c #236AA6",
+"M#    c #05579B",
+"N#    c #00599F",
+"O#    c #005A9F",
+"P#    c #005AA0",
+"Q#    c #7CABCE",
+"R#    c #FBFCFD",
+"S#    c #8E88B6",
+"T#    c #143E8A",
+"U#    c #05569B",
+"V#    c #2369A6",
+"W#    c #3285BD",
+"X#    c #3187BD",
+"Y#    c #3083BB",
+"Z#    c #0562A6",
+"`#    c #00438C",
+" $    c #DBE6F0",
+".$    c #00458D",
+"+$    c #0563A7",
+"@$    c #3184BB",
+"#$    c #3187BF",
+"$$    c #1E7CB9",
+"%$    c #025DA2",
+"&$    c #005BA0",
+"*$    c #005BA1",
+"=$    c #4287BA",
+"-$    c #FDFDFE",
+";$    c #6866A1",
+">$    c #0B4791",
+",$    c #1E7CB8",
+"'$    c #3183BB",
+")$    c #E3E2E2",
+"!$    c #00468E",
+"~$    c #0461A6",
+"{$    c #217EBA",
+"]$    c #036EB1",
+"^$    c #006CB1",
+"/$    c #0062A8",
+"($    c #00599E",
+"_$    c #005CA1",
+":$    c #005DA2",
+"<$    c #0561A5",
+"[$    c #BCD5E7",
+"}$    c #E6E4EE",
+"|$    c #565898",
+"1$    c #064F98",
+"2$    c #0062A7",
+"3$    c #006CB0",
+"4$    c #036DB1",
+"5$    c #217EB9",
+"6$    c #0461A5",
+"7$    c #034B92",
+"8$    c #035EA3",
+"9$    c #2B81B9",
+"0$    c #2881BB",
+"a$    c #046DB0",
+"b$    c #006BB0",
+"c$    c #006DB2",
+"d$    c #006AAF",
+"e$    c #0060A6",
+"f$    c #005EA3",
+"g$    c #005FA4",
+"h$    c #1C71AF",
+"i$    c #F3F8FB",
+"j$    c #EFEEF4",
+"k$    c #4F4D91",
+"l$    c #05539B",
+"m$    c #005CA2",
+"n$    c #0060A5",
+"o$    c #046CB0",
+"p$    c #035DA2",
+"q$    c #034B91",
+"r$    c #D4D4D5",
+"s$    c #E9E9E9",
+"t$    c #FBFAFA",
+"u$    c #2062A1",
+"v$    c #267DB8",
+"w$    c #2E84BC",
+"x$    c #0B6FB1",
+"y$    c #006EB3",
+"z$    c #006FB4",
+"A$    c #0064AA",
+"B$    c #0061A6",
+"C$    c #3E88BC",
+"D$    c #968DB8",
+"E$    c #10408E",
+"F$    c #0061A5",
+"G$    c #0064A9",
+"H$    c #006BAF",
+"I$    c #006AAE",
+"J$    c #2E83BC",
+"K$    c #2062A0",
+"L$    c #D8DADB",
+"M$    c #578AB8",
+"N$    c #1C77B4",
+"O$    c #1A78B5",
+"P$    c #0069AE",
+"Q$    c #0070B5",
+"R$    c #0070B6",
+"S$    c #4D97C7",
+"T$    c #5C4F92",
+"U$    c #065BA4",
+"V$    c #006DB1",
+"W$    c #0069AD",
+"X$    c #1A77B5",
+"Y$    c #1C76B4",
+"Z$    c #005399",
+"`$    c #5789B8",
+" %    c #93B4D2",
+".%    c #005096",
+"+%    c #0F6EAF",
+"@%    c #2C81BA",
+"#%    c #056BAE",
+"$%    c #0068AD",
+"%%    c #0071B6",
+"&%    c #0072B7",
+"*%    c #328EC6",
+"=%    c #9BC7E3",
+"-%    c #9BC7E2",
+";%    c #2C529A",
+">%    c #026CB3",
+",%    c #0071B7",
+"'%    c #056BAD",
+")%    c #0F6DAE",
+"!%    c #004F95",
+"~%    c #D3E1EC",
+"{%    c #0A5699",
+"]%    c #0260A5",
+"^%    c #1573B2",
+"/%    c #0067AB",
+"(%    c #0070B4",
+"_%    c #0073B8",
+":%    c #0073B9",
+"<%    c #0072B8",
+"[%    c #0068AC",
+"}%    c #025FA4",
+"|%    c #0A5598",
+"1%    c #E4E3E4",
+"2%    c #3A79AF",
+"3%    c #0066AB",
+"4%    c #3C93C7",
+"5%    c #69A6D1",
+"6%    c #6AA5CF",
+"7%    c #6AA4CF",
+"8%    c #3470AF",
+"9%    c #0564AC",
+"0%    c #0067AC",
+"a%    c #3A78AE",
+"b%    c #A0BFD9",
+"c%    c #005298",
+"d%    c #0063A9",
+"e%    c #96C4E1",
+"f%    c #7F75A9",
+"g%    c #0C529E",
+"h%    c #0063A8",
+"i%    c #005197",
+"j%    c #F1F5F9",
+"k%    c #286FAA",
+"l%    c #0066AA",
+"m%    c #96C4E0",
+"n%    c #7F74A9",
+"o%    c #0C519D",
+"p%    c #0065AA",
+"q%    c #286FA9",
+"r%    c #F7F6F6",
+"s%    c #A3C2DB",
+"t%    c #96C3E0",
+"u%    c #0C519C",
+"v%    c #3E80B4",
+"w%    c #96C3DF",
+"x%    c #0C509B",
+"y%    c #3E7FB4",
+"z%    c #DCE8F1",
+"A%    c #1969A7",
+"B%    c #0C4F9B",
+"C%    c #1968A7",
+"D%    c #AECAE0",
+"E%    c #0860A3",
+"F%    c #96C2DE",
+"G%    c #0C4F9A",
+"H%    c #085FA2",
+"I%    c #D6D7D8",
+"J%    c #E8E8E9",
+"K%    c #9ABED9",
+"L%    c #61A3CD",
+"M%    c #A5C9E1",
+"N%    c #A5C8E1",
+"O%    c #5270AB",
+"P%    c #0758A0",
+"Q%    c #9ABFDA",
+"R%    c #0864A6",
+"S%    c #0061A7",
+"T%    c #0963A5",
+"U%    c #EEEDED",
+"V%    c #ADCCE2",
+"W%    c #196FAE",
+"X%    c #196EAD",
+"Y%    c #ADCCE1",
+"Z%    c #DCE9F2",
+"`%    c #3D88BC",
+" &    c #0063A7",
+".&    c #3D87BB",
+"+&    c #A3C7DF",
+"@&    c #297DB7",
+"#&    c #0065AB",
+"$&    c #297DB6",
+"%&    c #DFDFE0",
+"&&    c #E3E3E4",
+"*&    c #A0C6DF",
+"=&    c #3B8ABF",
+"-&    c #0A6EB0",
+";&    c #3B8ABE",
+">&    c #D3E4F0",
+",&    c #93BFDC",
+"'&    c #579DCA",
+")&    c #207DB9",
+"!&    c #579CC9",
+"~&    c #F1F6FA",
+"{&    c #DAE9F3",
+"]&    c #DBE9F3",
+"^&    c #E6E6E6",
+"                                        . + @ # $ % & *                                         ",
+"                                = - ; > , ' ) ! ! ~ { ] ^ / ( _                                 ",
+"                            : < [ } | | | | 1 2 2 1 | | | 3 4 5 6 &                             ",
+"                        7 > 8 9 0 a b c d e f f f f e g c b h 0 | ' i %                         ",
+"                    j k 4 | l m n o p q r s t u v t s w q p o n m l 3 [ x y                     ",
+"                  z A 3 | B C D E F G H I J K L L K J M H N O P D C B | } ^ Q                   ",
+"                R 4 9 S T U V W X Y Z Z ` ` ` ` ` ` `  .Z ..+.@.W U E #.S | $.%.                ",
+"              &.8 | *.=.-.;.>.,.` '.).).!.!.!.!.!.!.!.~.).{.` ` ,.].^.V /.(.0 _.:.              ",
+"            <.8 | [.}.|.1.2.{.!.3.3.4.5.5.6.6.6.6.6.6.5.5.7.3.!.).{.8.1.9.0.[.| _.%.            ",
+"          a.8 | b.c.d.e.f.3.g.h.6.i.j.k.l.m.n.o.p.q.r.s.t.u.v.6.5.7.w.x.y.z.A.b.0 $.B.          ",
+"        C.D.9 E.F.G.H.I.5.i.j.J.K.L.M.N.0 O.O.9 O.O.9 P.Q.R.S.T.U.V.6.5.I.H.W.X.Y.| ^ y         ",
+"        Z.| `. +.+++@+i.#+$+%+&+*+=+9 9 9 9 9 9 9 9 9 9 9 9 -+;+>+,+'+j.i.)+++!+~+{+} x         ",
+"      x ]+| ^+/+(+_+J.:+<+[+}+|+1+9 O.O.9 O.O.9 O.O.9 O.O.9 O.O.2+3+4+5+'+j.6+7+8+9+| [ %       ",
+"      , | 0+a+b+c+$+<+[+}+d+e+f+O.9 O.O.9 O.O.9 O.O.9 O.O.9 O.O.O.g+h+}+i+5+'+j+k+l+m+3 i       ",
+"    / 3 n+o+p+q+%+r+}+s+t+u+v+9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 w+x+y+z+A+&+B+C+p+j+n+' Q     ",
+"    5 9 D+E+F+G+A+H+t+I+J+K+L+O.O.9 O.O.9 O.M+N+O+P+Q+O.O.9 O.O.O.9 R+S+T+U+V+[+W+X+Y+Z+| 6     ",
+"  a.8 0 `+ @.@}+d+T++@@@#@$@9 O.O.9 O.O.9 %@&@*@=@-@;@O.O.9 O.O.O.9 >@,@'@I+t+s+A+)@!@~@0 5 _   ",
+"  {@| ]@^@/@(@U+I+_@:@<@[@}@9 O.O.9 O.O.9 |@1@2@3@3@4@O.O.9 O.O.O.9 5@6@#@:@+@T+d+7@8@9@0@4 (   ",
+"  a@| b@c@d@e@J+f@#@g@h@i@j@k@l@w+9 9 9 m@n@o@p@p@q@r@9 9 9 9 9 9 9 s@t@[@g@u@'@I+v@d@w@x@3 /   ",
+"  y@| z@A@B@C@D@#@E@D@F@G@H@I@J@K@L@M@N@O@P@Q@R@R@S@T@O.O.9 O.O.O.9 U@V@W@X@E@#@X@Y@Z@`@ #| ^   ",
+"< 8 | .#+#@###$#h@%#&#=@*#3@=#p@-#;#>#,#,#'#'#'#)#!#9 O.O.9 O.O.O.~#{#]#G@F@D@[@^###/#+#(#| ] * ",
+"_#3 | :#<#[#}#|#1#G@*#2#3#4#-#5#,#,#6#7#7#8#9#0#a#9 9 9 9 9 9 9 9 b#c#3#*#d#G@e#}#}#[#f#g#| { h#",
+"6 3 i#j#k#l#m#m#|#n#3@=#o#p#q#'#7#r#s#t#u#v#w#1+O.O.9 O.O.9 O.x#y#z#A#o#3#3@B#C#m###D#E#j#i#~ % ",
+"F#| G#H#I#J#m#m#K#m#1#L#M#,#6#r#s#u#N#O#P#Q#R#9 O.O.9 O.O.9 x#S#T#'#,#U#V#e#W#X#m###Y#Z#`#G#! $ ",
+"; 3  $.$+$@$}#|#K##$$$%$,#7#s#u#N#P#&$*$=$-$9 9 9 9 9 9 9 ~#;$>$u#r#6#,#%$,$#$X#|#}#'$Z#.$ $! # ",
+")$3 i#!$~$l#m#m#K#{$]$^$/$N#($O#&$_$:$<$[$O.O.9 O.O.9 O.}$|$1$&$O#u#u#2$3$4$5$X#m###D#6$!$i#) @ ",
+"; 3 | 7$8$9$m#|#0$a$b$^$c$d$e$_$:$f$g$h$i$O.O.9 O.O.9 j$k$l$f$m$*$n$d$c$^$b$o$0$|###[#p$q$| ' r$",
+"s$t$| u$u#v$}#w$x$d$b$^$c$y$z$^$A$B$B$C$9 9 9 9 9 9 9 D$E$F$n$G$b$z$y$c$3$H$I$x$J$}#/#t#K$| , L$",
+"  ) | M$,#N$}#O$P$I$H$3$c$y$z$Q$R$Q$^$S$9 O.O.9 O.O.9 T$U$^$z$Q$Q$z$c$V$b$d$P$W$X$}#Y$Z$`$| >   ",
+"  , |  %.%+%@%#%$%I$H$b$^$c$y$Q$Q$%%&%*%=%-%-%-%-%-%-%;%>%,%%%Q$z$y$c$^$b$d$P$$%'%@%)%!% %| ;   ",
+"  ^ | ~%{%]%^%/%$%P$d$H$3$c$y$z$(%Q$%%,%&%_%:%:%:%_%<%&%%%%%Q$z$y$c$V$3$d$I$W$[%/%^%}%|%~%} -   ",
+"  1%]+0 2%t#3%/%[%P$I$d$b$^$c$y$z$(%Q$4%5%6%6%6%6%6%7%8%9%Q$z$z$y$c$^$b$d$P$$%0%/%3%s#a%0 [ =   ",
+"    D.9 b%c%d%3%/%$%P$d$H$3$^$c$y$z$Q$e%9 O.O.9 O.O.9 f%g%z$z$y$c$^$b$H$P$P$$%/%3%h%i%b%9 <     ",
+"    < | j%k%*$l%/%[%$%P$d$H$3$^$c$y$y$m%9 9 9 9 9 9 9 n%o%y$c$c$^$b$H$I$W$$%0%3%p%P#q%j%8 :     ",
+"      r%9 s%6#2$l%/%$%P$P$d$H$3$^$c$c$t%9 O.O.9 O.O.9 f%u%c$V$^$b$H$d$P$$%[%/%l%B$6#s%| >       ",
+"      < | | v%O#p%3%0%$%W$P$d$H$b$3$^$w%9 9 9 9 9 9 9 n%x%^$3$b$H$I$P$$%[%/%l%G$N#y%| 4 7       ",
+"        _.| z%A%f$p%/%0%$%P$P$d$d$H$b$w%9 O.O.9 O.O.9 f%B%b$H$d$I$W$$%[%/%3%p%:$C%z%3 k         ",
+"        _#8 9 D%E%e$l%/%0%$%$%P$I$d$H$F%9 O.O.9 O.O.9 f%G%d$I$P$P$$%[%/%3%p%n$H%D%9 A I%        ",
+"          J%3 | K%_$B$l%3%/%[%$%P$P$I$L%M%M%M%N%M%M%N%O%P%P$P$$%$%0%/%3%p%B$*$K%| 4 z           ",
+"            > 3 | Q%R%S%p%l%/%/%[%$%$%W$W$P$P$P$P$P$P$W$W$$%$%[%/%/%l%p%B$T%Q%| 8 R             ",
+"              U%3 | V%W%2$p%l%3%/%/%[%$%$%$%$%$%$%$%$%$%[%0%/%/%3%p%G$B$X%Y%| 8 &.              ",
+"                > 3 9 Z%`%h%p%p%3%l%/%/%/%[%[%0%[%[%/%/%/%/%3%l%p%G$ &.&Z%9 8 <.                ",
+"                  J%8 | | +&@&3%3%3%#&l%l%l%l%l%l%l%l%l%l%p%3%3%l%$&+&| | D.%&                  ",
+"                    &&_.| 9 i#*&=&-&P$P$$%0%0%3%3%0%0%$%$%W$-&;&*&i#| ]+Z.C.                    ",
+"                        < r%| 9 0 >&,&'&)&4$^$^$^$3$4$)&!&,&>&0 9 3 , x                         ",
+"                            < D.]+| | | | | ~&{&]&~&| | | | | 8 5 /                             ",
+"                                F#^ , ) t$3 3 3 | 3 3 8 y@a@^&a.                                ",
+"                                        s$; )$; F#6 _#<                                         "};
diff --git a/src/icons/page-down-48x48.png b/src/icons/page-down-48x48.png
new file mode 100644 (file)
index 0000000..5418a40
Binary files /dev/null and b/src/icons/page-down-48x48.png differ
diff --git a/src/icons/page-down.xpm b/src/icons/page-down.xpm
new file mode 100644 (file)
index 0000000..32dbc6c
--- /dev/null
@@ -0,0 +1,597 @@
+/* XPM */
+static const char * page_down_xpm[] = {
+"48 48 546 2",
+"      c None",
+".     c #C6CCD0",
+"+     c #CBD0D4",
+"@     c #CBD1D4",
+"#     c #CCD1D5",
+"$     c #CCD2D5",
+"%     c #CDD2D5",
+"&     c #CAD0D4",
+"*     c #CACFD3",
+"=     c #C9CFD3",
+"-     c #C9CED3",
+";     c #C8CED2",
+">     c #C3C9CE",
+",     c #ECEEF0",
+"'     c #F8F9F9",
+")     c #F9FAFA",
+"!     c #FBFBFB",
+"~     c #FCFCFC",
+"{     c #FDFDFD",
+"]     c #FAFBFB",
+"^     c #F7F8F9",
+"/     c #F6F7F8",
+"(     c #F5F6F6",
+"_     c #F3F4F5",
+":     c #F1F3F5",
+"<     c #EEF0F1",
+"[     c #C5CBD0",
+"}     c #EDEFF1",
+"|     c #FBFCFC",
+"1     c #F0F2F4",
+"2     c #DDE1E4",
+"3     c #DCE0E2",
+"4     c #EFF1F2",
+"5     c #FAFAFB",
+"6     c #F4F5F6",
+"7     c #EAEDEF",
+"8     c #D8DCDF",
+"9     c #F1F2F3",
+"0     c #F1F3F4",
+"a     c #D2D7DB",
+"b     c #FEFEFE",
+"c     c #F8F9FA",
+"d     c #E8EAEC",
+"e     c #FFFFFF",
+"f     c #EDEFF0",
+"g     c #D5D9DD",
+"h     c #E4E7E9",
+"i     c #F5F6F7",
+"j     c #DCDFE2",
+"k     c #D0D5D9",
+"l     c #DEE2E4",
+"m     c #DFE2E5",
+"n     c #E0E3E6",
+"o     c #E3E6E8",
+"p     c #EAECEE",
+"q     c #F2F3F4",
+"r     c #D4D8DC",
+"s     c #F0F2F3",
+"t     c #EBEEF0",
+"u     c #E9EBED",
+"v     c #E5E9EA",
+"w     c #E0E4E6",
+"x     c #D9DDE0",
+"y     c #D1D6DA",
+"z     c #F2F3F5",
+"A     c #E8EBED",
+"B     c #E5E9EB",
+"C     c #E1E5E8",
+"D     c #C7CDD1",
+"E     c #EFF1F3",
+"F     c #E3E7EA",
+"G     c #D8DEE1",
+"H     c #E5E8EB",
+"I     c #D8DDE1",
+"J     c #ECEFF0",
+"K     c #EAEDEE",
+"L     c #E7EBED",
+"M     c #F6F7F7",
+"N     c #F3F4F6",
+"O     c #E9ECEE",
+"P     c #E7EAEC",
+"Q     c #E4E8EB",
+"R     c #E2E6E9",
+"S     c #D7DDE1",
+"T     c #EBEEEF",
+"U     c #E6EAEC",
+"V     c #E1E6E8",
+"W     c #D7DCE1",
+"X     c #E0E5E8",
+"Y     c #D7DCE0",
+"Z     c #E0E4E7",
+"`     c #EDF0F1",
+" .    c #E4E8EA",
+"..    c #DFE4E7",
+"+.    c #D6DBDF",
+"@.    c #F2F4F5",
+"#.    c #E9EBEC",
+"$.    c #E1E2E3",
+"%.    c #DEDFDF",
+"&.    c #DFDFE0",
+"*.    c #E0E0E0",
+"=.    c #E0DFE0",
+"-.    c #DFDFDF",
+";.    c #DCDDDE",
+">.    c #D9DBDE",
+",.    c #D3D8DB",
+"'.    c #EAEAEB",
+").    c #E8E8E8",
+"!.    c #E6EDE7",
+"~.    c #D1E7D8",
+"{.    c #A3D2B0",
+"].    c #90C9A2",
+"^.    c #91CAA2",
+"/.    c #A6D3B3",
+"(.    c #D3E8DA",
+"_.    c #E9EFEA",
+":.    c #E9E8E9",
+"<.    c #D1D5D3",
+"[.    c #FCFDFD",
+"}.    c #F3F4F4",
+"|.    c #E9E9E9",
+"1.    c #DAEBDE",
+"2.    c #6FBB8A",
+"3.    c #249750",
+"4.    c #058839",
+"5.    c #0B8B40",
+"6.    c #108E44",
+"7.    c #118E44",
+"8.    c #0C8C40",
+"9.    c #07893B",
+"0.    c #279852",
+"a.    c #77BE8F",
+"b.    c #DFEEE3",
+"c.    c #ECEBEB",
+"d.    c #C5D0C8",
+"e.    c #EBEDEF",
+"f.    c #EFF0F1",
+"g.    c #EAF0EB",
+"h.    c #7CC193",
+"i.    c #098B3C",
+"j.    c #109043",
+"k.    c #249A53",
+"l.    c #30A15C",
+"m.    c #31A25D",
+"n.    c #31A15D",
+"o.    c #269C55",
+"p.    c #129144",
+"q.    c #0E8E3F",
+"r.    c #83C599",
+"s.    c #F0F4F1",
+"t.    c #D9DBD9",
+"u.    c #F0F0F1",
+"v.    c #E1E1E1",
+"w.    c #E2EEE5",
+"x.    c #3FA664",
+"y.    c #098F3D",
+"z.    c #239C52",
+"A.    c #31A35D",
+"B.    c #32A55E",
+"C.    c #31A55D",
+"D.    c #33A65F",
+"E.    c #33A75F",
+"F.    c #33A65E",
+"G.    c #31A45D",
+"H.    c #269E55",
+"I.    c #0C903F",
+"J.    c #4DAD6E",
+"K.    c #E5F0E8",
+"L.    c #DCDEDC",
+"M.    c #E6F0E8",
+"N.    c #39A55F",
+"O.    c #0B923F",
+"P.    c #2BA258",
+"Q.    c #31A65D",
+"R.    c #32A85D",
+"S.    c #33AA5D",
+"T.    c #35AB5D",
+"U.    c #C9E8D4",
+"V.    c #CEEBD9",
+"W.    c #B1DDC2",
+"X.    c #27A356",
+"Y.    c #31A85D",
+"Z.    c #32A75E",
+"`.    c #2EA45B",
+" +    c #0E9341",
+".+    c #43AA66",
+"++    c #EDF4EE",
+"@+    c #D0D8D2",
+"#+    c #E6E9EB",
+"$+    c #E3E3E4",
+"%+    c #EEF0EE",
+"&+    c #54B374",
+"*+    c #08923C",
+"=+    c #2DA55A",
+"-+    c #38AC5D",
+";+    c #40AE5C",
+">+    c #46B05C",
+",+    c #4BB05C",
+"'+    c #F7FBF8",
+")+    c #D8EEE1",
+"!+    c #2CA454",
+"~+    c #47B05C",
+"{+    c #39AC5D",
+"]+    c #34AA5D",
+"^+    c #2FA65B",
+"/+    c #0D9540",
+"(+    c #61B97D",
+"_+    c #F5F5F5",
+":+    c #EEF1F2",
+"<+    c #F3F5F6",
+"[+    c #ECEEEF",
+"}+    c #E5E4E4",
+"|+    c #A7D8B6",
+"1+    c #07933A",
+"2+    c #26A453",
+"3+    c #3AAD5D",
+"4+    c #44AF5C",
+"5+    c #4EB15C",
+"6+    c #54B45C",
+"7+    c #59B55B",
+"8+    c #5DB75B",
+"9+    c #F8FCF8",
+"0+    c #34A754",
+"a+    c #5AB65B",
+"b+    c #55B45C",
+"c+    c #4FB25C",
+"d+    c #46AF5C",
+"e+    c #3BAD5D",
+"f+    c #2BA657",
+"g+    c #07943A",
+"h+    c #B9E0C3",
+"i+    c #E6E6E6",
+"j+    c #E2E6E8",
+"k+    c #EEF0F2",
+"l+    c #F1F2F4",
+"m+    c #E3E4E4",
+"n+    c #F5F4F4",
+"o+    c #2BA453",
+"p+    c #169E44",
+"q+    c #4EB25C",
+"r+    c #57B45C",
+"s+    c #64BA5B",
+"t+    c #68BC5B",
+"u+    c #6BBD5B",
+"v+    c #F9FCF8",
+"w+    c #3BA954",
+"x+    c #69BC5B",
+"y+    c #65BA5B",
+"z+    c #5EB85B",
+"A+    c #58B55C",
+"B+    c #42AE5C",
+"C+    c #1EA149",
+"D+    c #3FAD63",
+"E+    c #F2F5F2",
+"F+    c #E2E2E3",
+"G+    c #BDE2C5",
+"H+    c #189E34",
+"I+    c #3FAC55",
+"J+    c #53B35C",
+"K+    c #65BB5B",
+"L+    c #6CBD5B",
+"M+    c #71BF5E",
+"N+    c #75C060",
+"O+    c #78C163",
+"P+    c #40AB57",
+"Q+    c #75C061",
+"R+    c #6CBD5C",
+"S+    c #66BB5B",
+"T+    c #5EB75B",
+"U+    c #45AF59",
+"V+    c #1FA035",
+"W+    c #CAE8D1",
+"X+    c #DEE3E5",
+"Y+    c #E6E8EA",
+"Z+    c #EBEAEA",
+"`+    c #77C589",
+" @    c #5EB534",
+".@    c #64B958",
+"+@    c #61B85B",
+"@@    c #6ABD5B",
+"#@    c #80C56D",
+"$@    c #73BF63",
+"%@    c #7FC469",
+"&@    c #81C56A",
+"*@    c #FAFCF9",
+"=@    c #44AD5B",
+"-@    c #80C46A",
+";@    c #7CC367",
+">@    c #7FC56D",
+",@    c #6BBD5C",
+"'@    c #62B95B",
+")@    c #69BB58",
+"!@    c #5FB638",
+"~@    c #8ACD98",
+"{@    c #EFEFEF",
+"]@    c #DCE1E4",
+"^@    c #E2E5E6",
+"/@    c #F2F2F2",
+"(@    c #58B667",
+"_@    c #7EC139",
+":@    c #8EC952",
+"<@    c #6DBE5B",
+"[@    c #74C060",
+"}@    c #9ED38F",
+"|@    c #ECF7EC",
+"1@    c #5EB97A",
+"2@    c #6EBC5A",
+"3@    c #75BE57",
+"4@    c #3FAA52",
+"5@    c #78BF5B",
+"6@    c #A8D797",
+"7@    c #E6F4E7",
+"8@    c #59B774",
+"9@    c #6DBD5E",
+"0@    c #6FBF5B",
+"a@    c #90CB51",
+"b@    c #7DC13E",
+"c@    c #62BA67",
+"d@    c #F8F8F8",
+"e@    c #DADFE3",
+"f@    c #E4E7EA",
+"g@    c #DFE2E3",
+"h@    c #EBF1EB",
+"i@    c #52B24F",
+"j@    c #87C53E",
+"k@    c #9BCE4E",
+"l@    c #8BC856",
+"m@    c #A3D593",
+"n@    c #F8FCF7",
+"o@    c #F0F9F4",
+"p@    c #62BA7B",
+"q@    c #71BC58",
+"r@    c #44AB54",
+"s@    c #A5D48D",
+"t@    c #FBFDFA",
+"u@    c #F1F9F4",
+"v@    c #59B674",
+"w@    c #81C453",
+"x@    c #8AC743",
+"y@    c #57B350",
+"z@    c #FAFAFA",
+"A@    c #E2E7E9",
+"B@    c #DEE0E2",
+"C@    c #E9F1E8",
+"D@    c #55B348",
+"E@    c #8AC640",
+"F@    c #9CCF4F",
+"G@    c #A1D158",
+"H@    c #F3F9ED",
+"I@    c #EDF7F1",
+"J@    c #66BB7D",
+"K@    c #D8EEE2",
+"L@    c #7AC48E",
+"M@    c #F8FCF6",
+"N@    c #D3ECDD",
+"O@    c #53B250",
+"P@    c #8EC845",
+"Q@    c #5BB54D",
+"R@    c #DEE2E6",
+"S@    c #DFE3E7",
+"T@    c #E0E5E7",
+"U@    c #DDDFE1",
+"V@    c #EDF2EC",
+"W@    c #63B950",
+"X@    c #88C53E",
+"Y@    c #98CD4A",
+"Z@    c #AAD56A",
+"`@    c #F8FBF3",
+" #    c #FAFDFB",
+".#    c #F3FAF6",
+"+#    c #F5FAF7",
+"@#    c #5CB766",
+"##    c #89C745",
+"$#    c #8CC744",
+"%#    c #66BA50",
+"&#    c #D5DBDE",
+"*#    c #DDE1E5",
+"=#    c #DEE2E5",
+"-#    c #DEE3E6",
+";#    c #F4F4F4",
+">#    c #79C368",
+",#    c #81C23A",
+"'#    c #9ACE4D",
+")#    c #8AC531",
+"!#    c #83C124",
+"~#    c #A5D260",
+"{#    c #F6FBF0",
+"]#    c #E8F5EE",
+"^#    c #5BB665",
+"/#    c #7BBE25",
+"(#    c #88C42D",
+"_#    c #9ACD4C",
+":#    c #84C440",
+"<#    c #81C66C",
+"[#    c #F9F9F9",
+"}#    c #D3D9DD",
+"|#    c #DAE0E3",
+"1#    c #DBE0E3",
+"2#    c #DDE2E5",
+"3#    c #DADFE2",
+"4#    c #EEEEEE",
+"5#    c #A0D491",
+"6#    c #73BD37",
+"7#    c #92C940",
+"8#    c #A5D25F",
+"9#    c #61B967",
+"0#    c #77BD26",
+"a#    c #82C023",
+"b#    c #90C83B",
+"c#    c #77BF3C",
+"d#    c #ADD99F",
+"e#    c #F3F3F3",
+"f#    c #D1D8DC",
+"g#    c #D8DEE2",
+"h#    c #D9DFE2",
+"i#    c #D9DFE3",
+"j#    c #DBE1E4",
+"k#    c #E4E5E6",
+"l#    c #D6ECCF",
+"m#    c #67B83A",
+"n#    c #82C12A",
+"o#    c #A7D363",
+"p#    c #F0F8F3",
+"q#    c #84C228",
+"r#    c #6BBA3E",
+"s#    c #DFF0D9",
+"t#    c #E7E7E7",
+"u#    c #D0D6DA",
+"v#    c #D6DCE0",
+"w#    c #DADDE0",
+"x#    c #F9F8F8",
+"y#    c #82C567",
+"z#    c #77BD2B",
+"A#    c #A4D25F",
+"B#    c #F7FBF1",
+"C#    c #EAF6EF",
+"D#    c #5AB664",
+"E#    c #7ABE2B",
+"F#    c #8FCB79",
+"G#    c #F8F9F7",
+"H#    c #CED4D9",
+"I#    c #D4DADE",
+"J#    c #D4DADF",
+"K#    c #D5DBDF",
+"L#    c #D5DADE",
+"M#    c #D0E8C6",
+"N#    c #76BD45",
+"O#    c #7FBF25",
+"P#    c #ABD56B",
+"Q#    c #FAFDF7",
+"R#    c #F0F8F4",
+"S#    c #66BC72",
+"T#    c #74BB26",
+"U#    c #80C025",
+"V#    c #78BE47",
+"W#    c #DBEDD3",
+"X#    c #EEEFEC",
+"Y#    c #CBD3D8",
+"Z#    c #D1D8DD",
+"`#    c #D2D8DD",
+" $    c #D2D9DE",
+".$    c #D3D9DE",
+"+$    c #D7DBDE",
+"@$    c #F8F8F7",
+"#$    c #A9D692",
+"$$    c #7ABE3A",
+"%$    c #81C024",
+"&$    c #AED76F",
+"*$    c #F8FCFA",
+"=$    c #62BA70",
+"-$    c #73BB26",
+";$    c #82C024",
+">$    c #7DC03D",
+",$    c #B2DA9D",
+"'$    c #C9D1D6",
+")$    c #CFD6DB",
+"!$    c #D0D7DC",
+"~$    c #E0E2E4",
+"{$    c #F5F9F4",
+"]$    c #A3D385",
+"^$    c #7FC13B",
+"/$    c #80C024",
+"($    c #A8D466",
+"_$    c #7BC36A",
+":$    c #77BC26",
+"<$    c #83C23F",
+"[$    c #ABD78F",
+"}$    c #F8FAF6",
+"|$    c #E3E9DD",
+"1$    c #C7CFD5",
+"2$    c #CCD4D9",
+"3$    c #CDD4D9",
+"4$    c #CED5DA",
+"5$    c #E6E7E8",
+"6$    c #F5F9F3",
+"7$    c #AED88E",
+"8$    c #89C64A",
+"9$    c #7FC028",
+"0$    c #81C029",
+"a$    c #8CC74B",
+"b$    c #B7DC9B",
+"c$    c #F5F9F2",
+"d$    c #ECECEA",
+"e$    c #BAC2C8",
+"f$    c #BCC5CA",
+"g$    c #BDC5CA",
+"h$    c #BDC5CB",
+"i$    c #BEC6CB",
+"j$    c #BEC5CB",
+"k$    c #DFE1E3",
+"l$    c #F8FAF7",
+"m$    c #D0E8BA",
+"n$    c #9CCE68",
+"o$    c #87C43F",
+"p$    c #7FC027",
+"q$    c #80C027",
+"r$    c #8AC642",
+"s$    c #9ED06B",
+"t$    c #D3E9BF",
+"u$    c #FCFCFB",
+"v$    c #EBEBE9",
+"w$    c #DDE3D8",
+"x$    c #CDE7B6",
+"y$    c #B1D988",
+"z$    c #97CC5C",
+"A$    c #90C94D",
+"B$    c #8EC747",
+"C$    c #91C94E",
+"D$    c #98CD5E",
+"E$    c #B2DA89",
+"F$    c #D1E9BB",
+"G$    c #F7FAF4",
+"H$    c #E5E9E0",
+"I$    c #F6F5F5",
+"J$    c #F9FAF7",
+"K$    c #F2F8EC",
+"L$    c #E5F2D9",
+"M$    c #D9ECC7",
+"N$    c #E7F3DB",
+"O$    c #F2F8ED",
+"P$    c #FAFBF9",
+"Q$    c #F6F7F5",
+"R$    c #E8EBE4",
+"S$    c #E5ECDD",
+"T$    c #ECECEC",
+"U$    c #E6EDDF",
+"      . + + @ # $ % % % % % % % % $ # @ + & * = - ; >                                           ",
+"      , ' ) ! ~ ~ { { { ~ { ~ { { ~ ~ ] ) ^ / ( _ : < [                                         ",
+"      } ) | ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ) ' / ( _ 1 2 3                                       ",
+"      4 ~ ~ { { ~ { { { ~ { ~ { { ~ { { ~ ~ 5 ' / 6 _ 7 8 _                                     ",
+"      9 { ~ { { ~ { { { ~ { ~ { { ~ { { ~ { ~ ) ^ / 6 0 a b ,                                   ",
+"      9 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ! c / ( _ a b b d                                 ",
+"      9 { ~ { { ~ { { { { { { { { ~ { { ~ { { ~ ] ^ / 6 a b e b f                               ",
+"      9 { ~ { { { { b b { b { b { { { { ~ { { ~ | ) ^ ( g b e e b h                             ",
+"      9 ~ ~ ~ { { { { { { { { { { { ~ ~ ~ ~ ~ ~ ~ ) ^ i g b b b b { j                           ",
+"      9 { ~ { { { b b b { b { b b { { { ~ { { ~ { ] ^ / k l m n o p q r                         ",
+"      9 { ~ { { { b b b { b { b b { { { ~ { { ~ { | c / s t u v w x y &                         ",
+"      9 ~ ~ { { { { { { { { { { { { { { ~ ~ ~ ~ ~ | c / 6 z 4 } 7 A B C D                       ",
+"      9 { ~ { b { b b b b b { b b { b { ~ { { ~ { | c / 6 z E } 7 A B F G                       ",
+"      9 { ~ { b { b b b { b { b b { b { ~ { { ~ { | c / 6 z E } 7 A B F G                       ",
+"      9 ~ ~ { { { { { { { { { { { { { { ~ ~ ~ ~ ~ ! c / 6 z 4 f 7 A H F I                       ",
+"      9 { ~ { { { b b b { b { b b { { { ~ { { ~ { ] ^ / 6 0 4 J K L H F I                       ",
+"      9 { ~ { { { b b b { b { b b { { { ~ { { ~ ~ ) ^ M N 1 4 J O P Q R S                       ",
+"      9 { ~ { { { { b b { b { b { { { { ~ { { ~ | ) ^ ( _ s < T O U Q V W                       ",
+"      9 ~ ~ ~ ~ ~ ~ { { { { { { ~ ~ ~ ~ ~ ~ ~ ~ ] ^ / 6 0 4 } 7 O B F X Y                       ",
+"      9 { ~ { { ~ { { { ~ { ~ { { ~ { { ~ { { | ) ^ i _ 1 4 J K A H F Z Y                       ",
+"      9 { ~ { { ~ { { { ~ { ~ { { ~ { { ~ { ~ ) ^ / 6 z s ` T O P  .R ..+.                      ",
+"      4 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ] ' / 6 @.#.$.%.&.*.=.-.;.>.,.                      ",
+"      } ] ~ { { ~ { { { ~ { ~ { { ~ { { ~ ] c / 6 '.-.).!.~.{.].^./.(._.:.<.                    ",
+"      , ' ) ! [.~ { { { ~ { ~ { { ~ ~ ! ) ' / }.*.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.                ",
+"      e./ ^ c ) ! ~ ~ ~ ~ ~ ~ ~ ~ ! ) c ^ / f.-.g.h.i.j.k.l.m.m.m.m.n.o.p.q.r.s.t.              ",
+"      u ( M ^ ^ ' ) ) ] ] ] ] ) ) ' ^ / M u.v.w.x.y.z.A.B.C.D.E.E.F.C.B.G.H.I.J.K.L.            ",
+"      P _ 6 i / / ^ ^ ^ ^ ^ ^ ^ ^ / M 6 _ =.M.N.O.P.Q.R.S.T.U.V.V.W.X.S.Y.Z.`. +.+++@+          ",
+"      #+s 0 _ 6 6 ( i M / / M i ( 6 _ _ $+%+&+*+=+S.-+;+>+,+'+b b )+!+~+;+{+]+^+/+(+_+          ",
+"      h :+4 1 0 z _ _ <+_ 6 _ _ _ z 0 [+}+|+1+2+3+4+5+6+7+8+9+e e )+0+a+b+c+d+e+f+g+h+i+        ",
+"      j+J } k+4 E s 1 1 l+l+1 1 s E 4 m+n+o+p+;+q+r+8+s+t+u+v+e e )+w+x+y+z+A+c+B+C+D+E+        ",
+"      Z O 7 t J } < k+4 4 4 4 k+< } , F+G+H+I+J+8+K+L+M+N+O+v+b b )+P+Q+M+R+S+T+b+U+V+W+v.      ",
+"      X+A O O 7 7 T , , , J t t T 7 Y+Z+`+ @.@+@@@M+#@$@%@&@*@e e )+=@-@;@>@,@@@'@)@!@~@{@      ",
+"      ]@B U L A O O O O O O O O O O ^@/@(@_@:@<@[@}@|@1@2@3@v+e e )+4@5@6@7@8@9@0@a@b@c@d@      ",
+"      e@F f@Q B B U P P L L P P U B g@h@i@j@k@l@m@n@b o@p@q@v+b b )+r@s@t@b u@v@w@k@x@y@z@      ",
+"      I X V A@F F Q Q Q Q Q Q Q  .F B@C@D@E@F@G@H@e b e I@J@v+e e K@L@M@b e e N@O@F@P@Q@!       ",
+"      Y R@S@..T@X V R R R R R R C X U@V@W@X@k@Y@Z@`@b b b u@ #b b .#+#b b b o@@###k@$#%#z@      ",
+"      &#]@*#=#R@R@-#S@S@....S@S@-#R@j ;#>#,#'#)#!#~#{#e e b e e e b e e b ]#^#/#(#_#:#<#[#      ",
+"      }#|#1#]@]@]@*#2#2#2#2#2#2#*#]@3#4#5#6#7#!#!#!#8#`@e b e e e b e e ]#9#0#a#!#b#c#d#e#      ",
+"      f#S g#h#i#|#1#j#j#j#j#j#j#1#|#i#k#l#m#n#a#!#!#a#o#`@b e e e b e p#^#0#!#a#!#q#r#s#t#      ",
+"      u#v#v#S S S S g#g#g#g#g#g#S S S w#x#y#z#a#a#a#a#a#A#B#b b b b C#D#/#a#a#a#a#E#F#G#        ",
+"      H#I#J#K#K#K#v#v#v#v#v#v#v#v#K#K#L#'.M#N#O#!#!#a#!#!#P#Q#e e R#S#T#a#!#!#a#U#V#W#X#        ",
+"      Y#Z#`# $.$.$J#J#J#J#J#J#J#I#.$.$ $+$@$#$$$%$!#a#!#!#a#&$Q#*$=$-$!#a#!#!#;$>$,$z@          ",
+"      '$)$)$!$!$Z#Z#Z#Z#`#`#Z#Z#Z#Z#!$!$)$~${$]$^$/$a#a#a#a#a#($_$:$a#a#a#a#%$<$[$}$|$          ",
+"      1$2$3$4$4$4$)$)$)$)$)$)$)$)$4$4$4$3$3$5$6$7$8$9$;$!#a#!#!#!#a#!#!#;$0$a$b$c$d$            ",
+"      e$f$f$g$h$h$h$h$i$i$i$j$h$h$h$h$g$f$f$j$k$l$m$n$o$p$%$!#!#!#a#%$q$r$s$t$u$v$              ",
+"                                                w$_+c$x$y$z$A$B$B$C$D$E$F$G$d@                  ",
+"                                                    H$I$J$K$L$M$M$N$O$P$Q$R$                    ",
+"                                                          S$T${@{@T$U$                          "};
diff --git a/src/icons/remove-48x48.png b/src/icons/remove-48x48.png
new file mode 100644 (file)
index 0000000..535e301
Binary files /dev/null and b/src/icons/remove-48x48.png differ
diff --git a/src/icons/remove.xpm b/src/icons/remove.xpm
new file mode 100644 (file)
index 0000000..fd35815
--- /dev/null
@@ -0,0 +1,756 @@
+/* XPM */
+static const char * remove_xpm[] = {
+"48 48 705 2",
+"      c None",
+".     c #DDD8D8",
+"+     c #D6D4D4",
+"@     c #D4D3D3",
+"#     c #D6D5D5",
+"$     c #D5D4D4",
+"%     c #D3D2D2",
+"&     c #D5D2D2",
+"*     c #DBD6D6",
+"=     c #D7D4D4",
+"-     c #DCDBDB",
+";     c #E5E4E4",
+">     c #ECECEC",
+",     c #F2F2F2",
+"'     c #F5F5F5",
+")     c #F7F7F7",
+"!     c #F8F7F7",
+"~     c #F6F6F6",
+"{     c #F5F4F4",
+"]     c #F0F0F0",
+"^     c #EAE9E9",
+"/     c #E1E1E1",
+"(     c #D8D7D7",
+"_     c #D2CFCF",
+":     c #DAD9D8",
+"<     c #E7E7E7",
+"[     c #F3F3F3",
+"}     c #FAFAFA",
+"|     c #FDFDFD",
+"1     c #FBF3F3",
+"2     c #F5E0DE",
+"3     c #F5E0DF",
+"4     c #FCFCFC",
+"5     c #F8F8F8",
+"6     c #EFEFEF",
+"7     c #E2E1E1",
+"8     c #D4D2D2",
+"9     c #DADADA",
+"0     c #F9F9F9",
+"a     c #FEFEFE",
+"b     c #FDFCFC",
+"c     c #F2D9D8",
+"d     c #DEA39F",
+"e     c #CA6F69",
+"f     c #BA4038",
+"g     c #AE271E",
+"h     c #AA241B",
+"i     c #AD271E",
+"j     c #DEA29F",
+"k     c #E6E5E5",
+"l     c #D9D6D6",
+"m     c #E8E7E7",
+"n     c #FAF3F2",
+"o     c #E3AEAB",
+"p     c #C25750",
+"q     c #B02D24",
+"r     c #AC241B",
+"s     c #AD241B",
+"t     c #AE261D",
+"u     c #AF281F",
+"v     c #AF2820",
+"w     c #AF2920",
+"x     c #AC231A",
+"y     c #E2AEAB",
+"z     c #E0DFDF",
+"A     c #D0CDCD",
+"B     c #DEDCDC",
+"C     c #F2F1F1",
+"D     c #E4B0AD",
+"E     c #BD4840",
+"F     c #AD231A",
+"G     c #AE241B",
+"H     c #AF251C",
+"I     c #B43129",
+"J     c #B83C34",
+"K     c #BC443D",
+"L     c #BE4943",
+"M     c #BF4C46",
+"N     c #BF4E47",
+"O     c #BB443D",
+"P     c #B33129",
+"Q     c #AE251C",
+"R     c #AD231B",
+"S     c #E4B1AD",
+"T     c #E1E0E0",
+"U     c #F5E1E0",
+"V     c #C55952",
+"W     c #AF241B",
+"X     c #B22B23",
+"Y     c #BA3C35",
+"Z     c #BF4B44",
+"`     c #C14F49",
+" .    c #C24E48",
+"..    c #C24F49",
+"+.    c #C14E48",
+"@.    c #B93C35",
+"#.    c #C45952",
+"$.    c #F1F1F1",
+"%.    c #D7D6D6",
+"&.    c #E4E3E3",
+"*.    c #E7B9B6",
+"=.    c #B93932",
+"-.    c #B0241B",
+";.    c #B32820",
+">.    c #BB3B34",
+",.    c #C14C46",
+"'.    c #C34E48",
+").    c #C44F49",
+"!.    c #C54E48",
+"~.    c #C54F49",
+"{.    c #C64F49",
+"].    c #C44E48",
+"^.    c #C34F49",
+"/.    c #BA3B34",
+"(.    c #B22820",
+"_.    c #B83931",
+":.    c #F3F2F2",
+"<.    c #D9D8D8",
+"[.    c #E2E2E2",
+"}.    c #E2A9A6",
+"|.    c #B42B23",
+"1.    c #B2241C",
+"2.    c #B73028",
+"3.    c #C14841",
+"4.    c #C64E48",
+"5.    c #C74E48",
+"6.    c #C84E48",
+"7.    c #C84F48",
+"8.    c #C94F48",
+"9.    c #C04841",
+"0.    c #B1241C",
+"a.    c #E0DEDE",
+"b.    c #E3A9A5",
+"c.    c #B3241C",
+"d.    c #B4251D",
+"e.    c #BB372F",
+"f.    c #C44D47",
+"g.    c #C84F49",
+"h.    c #C94F49",
+"i.    c #CA5049",
+"j.    c #CA4F48",
+"k.    c #BB362F",
+"l.    c #DCDADA",
+"m.    c #F4F4F4",
+"n.    c #E9B9B7",
+"o.    c #B72B23",
+"p.    c #B5251D",
+"q.    c #BE3932",
+"r.    c #C64D47",
+"s.    c #CB5049",
+"t.    c #CB4F48",
+"u.    c #CC5049",
+"v.    c #CD5049",
+"w.    c #CD4F48",
+"x.    c #CE5049",
+"y.    c #CE4F48",
+"z.    c #CC4F48",
+"A.    c #C74F49",
+"B.    c #BD3932",
+"C.    c #E9BAB7",
+"D.    c #D1CDCD",
+"E.    c #ECEBEB",
+"F.    c #B6241C",
+"G.    c #BE362F",
+"H.    c #C84D47",
+"I.    c #D97B76",
+"J.    c #DF908B",
+"K.    c #CF4F48",
+"L.    c #D04F48",
+"M.    c #D97A75",
+"N.    c #C74D47",
+"O.    c #B5241C",
+"P.    c #FBFBFB",
+"Q.    c #CA5953",
+"R.    c #B7241C",
+"S.    c #BD3028",
+"T.    c #C94E47",
+"U.    c #DB7B76",
+"V.    c #FCF6F5",
+"W.    c #FDFAFA",
+"X.    c #E09692",
+"Y.    c #D15049",
+"Z.    c #D25049",
+"`.    c #D24F48",
+" +    c #D34F48",
+".+    c #D35049",
+"++    c #D14F48",
+"@+    c #E49A96",
+"#+    c #FEFBFB",
+"$+    c #FBF4F4",
+"%+    c #D87873",
+"&+    c #CA4F49",
+"*+    c #C84E47",
+"=+    c #BC3028",
+"-+    c #E7B0AD",
+";+    c #B9241C",
+">+    c #BC2920",
+",+    c #C74841",
+"'+    c #CF5049",
+")+    c #DC7E78",
+"!+    c #FBF0F0",
+"~+    c #FFFFFF",
+"{+    c #E1928E",
+"]+    c #D4514A",
+"^+    c #D44F48",
+"/+    c #D55049",
+"(+    c #D54F48",
+"_+    c #D45049",
+":+    c #E59691",
+"<+    c #F9EFEE",
+"[+    c #BB2820",
+"}+    c #B8241C",
+"|+    c #E2E0E0",
+"1+    c #FBF3F2",
+"2+    c #C64740",
+"3+    c #BA241C",
+"4+    c #C43C34",
+"5+    c #DC7B76",
+"6+    c #FCF9F8",
+"7+    c #E2928E",
+"8+    c #D74F48",
+"9+    c #D84F48",
+"0+    c #E79691",
+"a+    c #FDF9F9",
+"b+    c #D97873",
+"c+    c #C33C34",
+"d+    c #E7AEAA",
+"e+    c #BB241C",
+"f+    c #BF2C23",
+"g+    c #CC4D46",
+"h+    c #D05049",
+"i+    c #DE7B76",
+"j+    c #E59592",
+"k+    c #DB4F49",
+"l+    c #DB4E48",
+"m+    c #EA9996",
+"n+    c #DA7873",
+"o+    c #CB4D46",
+"p+    c #E7AEAB",
+"q+    c #CE5750",
+"r+    c #BF251B",
+"s+    c #C73D35",
+"t+    c #E48F8B",
+"u+    c #E5928E",
+"v+    c #DD504A",
+"w+    c #DD4E48",
+"x+    c #DD4F49",
+"y+    c #EA9591",
+"z+    c #FCFAF9",
+"A+    c #C37671",
+"B+    c #C84740",
+"C+    c #BE251C",
+"D+    c #CD5750",
+"E+    c #F4D9D8",
+"F+    c #C12D25",
+"G+    c #D0281C",
+"H+    c #CE4C44",
+"I+    c #D75049",
+"J+    c #E39592",
+"K+    c #FDF9F8",
+"L+    c #E7928E",
+"M+    c #E04E48",
+"N+    c #E04F49",
+"O+    c #EC9592",
+"P+    c #FEF9F9",
+"Q+    c #C57F7B",
+"R+    c #AB2E27",
+"S+    c #D14C45",
+"T+    c #D0271D",
+"U+    c #C02D25",
+"V+    c #EFEEEE",
+"W+    c #E5A39F",
+"X+    c #C3251B",
+"Y+    c #DC3528",
+"Z+    c #D95348",
+"`+    c #D64F48",
+" @    c #D94F48",
+".@    c #E4918D",
+"+@    c #FCF8F8",
+"@@    c #E89691",
+"#@    c #EE9A95",
+"$@    c #FEFBFA",
+"%@    c #FBF8F8",
+"&@    c #C27A75",
+"*@    c #AC2E27",
+"=@    c #D74D47",
+"-@    c #D85248",
+";@    c #DB3428",
+">@    c #C2251B",
+",@    c #F6F5F5",
+"'@    c #D76F69",
+")@    c #CA251B",
+"!@    c #DF4234",
+"~@    c #E15847",
+"{@    c #D65148",
+"]@    c #D84F49",
+"^@    c #DA4F49",
+"/@    c #DE504A",
+"(@    c #E7918D",
+"_@    c #AF312A",
+":@    c #D84C45",
+"<@    c #E15647",
+"[@    c #DF4034",
+"}@    c #C9251B",
+"|@    c #D7706A",
+"1@    c #CC4139",
+"2@    c #D0271C",
+"3@    c #E04B3D",
+"4@    c #E35A47",
+"5@    c #DF5847",
+"6@    c #DC4F49",
+"7@    c #DE4F49",
+"8@    c #DF4E48",
+"9@    c #E14F49",
+"0@    c #E25048",
+"a@    c #E8968F",
+"b@    c #AE2F27",
+"c@    c #DC4C45",
+"d@    c #DF4F49",
+"e@    c #DE5747",
+"f@    c #E35847",
+"g@    c #E0493D",
+"h@    c #CF261C",
+"i@    c #DCD6D6",
+"j@    c #E3E3E2",
+"k@    c #C7281F",
+"l@    c #D4291E",
+"m@    c #E15142",
+"n@    c #E25B46",
+"o@    c #E35F46",
+"p@    c #DE5647",
+"q@    c #DC4E48",
+"r@    c #DE4E48",
+"s@    c #E14F48",
+"t@    c #E25045",
+"u@    c #DF4435",
+"v@    c #DC3320",
+"w@    c #E48275",
+"x@    c #AC251B",
+"y@    c #DD4134",
+"z@    c #E14E46",
+"A@    c #E35D46",
+"B@    c #E25947",
+"C@    c #E14F42",
+"D@    c #C5281F",
+"E@    c #FCF3F3",
+"F@    c #C7251C",
+"G@    c #D72B1F",
+"H@    c #E25445",
+"I@    c #E35C47",
+"J@    c #E35F47",
+"K@    c #E46247",
+"L@    c #E05448",
+"M@    c #E14B3F",
+"N@    c #DD3827",
+"O@    c #DC311B",
+"P@    c #DC321A",
+"Q@    c #DC361B",
+"R@    c #E58575",
+"S@    c #AE291C",
+"T@    c #D7301A",
+"U@    c #DC301B",
+"V@    c #DD3727",
+"W@    c #E14A3F",
+"X@    c #DF5448",
+"Y@    c #E36147",
+"Z@    c #E35E47",
+"`@    c #E25245",
+" #    c #D72A1F",
+".#    c #C6251C",
+"+#    c #FCF4F3",
+"@#    c #E4E4E4",
+"##    c #F8E1DF",
+"$#    c #C9251C",
+"%#    c #D92D20",
+"&#    c #E25646",
+"*#    c #E36047",
+"=#    c #E46446",
+"-#    c #E46546",
+";#    c #E35647",
+">#    c #E0483A",
+",#    c #DC331F",
+"'#    c #DC311A",
+")#    c #DB3419",
+"!#    c #DC3719",
+"~#    c #DC3919",
+"{#    c #DC3B19",
+"]#    c #E68D7A",
+"^#    c #FCFAFA",
+"/#    c #AD291A",
+"(#    c #D83719",
+"_#    c #DC361A",
+":#    c #DB3319",
+"<#    c #DC301A",
+"[#    c #DC311F",
+"}#    c #E0463A",
+"|#    c #E35547",
+"1#    c #E46447",
+"2#    c #E36246",
+"3#    c #E25447",
+"4#    c #D82B20",
+"5#    c #C8251C",
+"6#    c #F8E0DF",
+"7#    c #CB241B",
+"8#    c #E25C46",
+"9#    c #E36046",
+"0#    c #E46746",
+"a#    c #E35B34",
+"b#    c #DD3A1B",
+"c#    c #DB3219",
+"d#    c #DC3519",
+"e#    c #DC3819",
+"f#    c #DD3D18",
+"g#    c #DD3F18",
+"h#    c #EC917A",
+"i#    c #FEFAF9",
+"j#    c #CE837A",
+"k#    c #DB3D18",
+"l#    c #DD3C18",
+"m#    c #DC3A19",
+"n#    c #DC3419",
+"o#    c #DB311A",
+"p#    c #DD381C",
+"q#    c #E25A34",
+"r#    c #E46646",
+"s#    c #E35E46",
+"t#    c #E25A46",
+"u#    c #E25547",
+"v#    c #D92C20",
+"w#    c #CA251C",
+"x#    c #E3E2E2",
+"y#    c #CD241C",
+"z#    c #D92B1F",
+"A#    c #E46346",
+"B#    c #E25B37",
+"C#    c #DF481A",
+"D#    c #DF4817",
+"E#    c #DE4218",
+"F#    c #DD3B19",
+"G#    c #DD3C19",
+"H#    c #DE421A",
+"I#    c #EB8D74",
+"J#    c #FDFAF9",
+"K#    c #E68A74",
+"L#    c #DD3E19",
+"M#    c #DE4018",
+"N#    c #DE4717",
+"O#    c #DF471A",
+"P#    c #E25937",
+"Q#    c #E25345",
+"R#    c #D82A1F",
+"S#    c #CB251C",
+"T#    c #D0271F",
+"U#    c #D8291E",
+"V#    c #E35B47",
+"W#    c #E35C3E",
+"X#    c #DE441C",
+"Y#    c #DE4518",
+"Z#    c #DF4917",
+"`#    c #DF4D16",
+" $    c #DE4517",
+".$    c #EB8F74",
+"+$    c #FEF9F8",
+"@$    c #FDF8F8",
+"#$    c #E68B74",
+"$$    c #DE4118",
+"%$    c #DE4417",
+"&$    c #DF4B16",
+"*$    c #DE4418",
+"=$    c #DE431C",
+"-$    c #E25A3E",
+";$    c #E35947",
+">$    c #E15042",
+",$    c #D8281E",
+"'$    c #CF271F",
+")$    c #E9E8E8",
+"!$    c #FBFAFA",
+"~$    c #D84039",
+"{$    c #D7261C",
+"]$    c #E14C3D",
+"^$    c #E35C43",
+"/$    c #DE4422",
+"($    c #DD4018",
+"_$    c #DE4817",
+":$    c #DF4C16",
+"<$    c #E05015",
+"[$    c #E05314",
+"}$    c #ED9A78",
+"|$    c #E79678",
+"1$    c #E05214",
+"2$    c #DF4E16",
+"3$    c #DF4A17",
+"4$    c #DE4318",
+"5$    c #DE4223",
+"6$    c #E25A44",
+"7$    c #E25847",
+"8$    c #E14A3D",
+"9$    c #D6261C",
+"0$    c #D74039",
+"a$    c #E26F69",
+"b$    c #D6251B",
+"c$    c #DF4334",
+"d$    c #E04B31",
+"e$    c #DD4019",
+"f$    c #DF4718",
+"g$    c #E05018",
+"h$    c #EC9772",
+"i$    c #FEFBF9",
+"j$    c #E79273",
+"k$    c #DF4E18",
+"l$    c #DE4617",
+"m$    c #E04931",
+"n$    c #E35747",
+"o$    c #DF4134",
+"p$    c #D5241B",
+"q$    c #E16F69",
+"r$    c #EDA29F",
+"s$    c #D7241B",
+"t$    c #DD3629",
+"u$    c #E25342",
+"v$    c #DD381E",
+"w$    c #DE4618",
+"x$    c #DE4917",
+"y$    c #EC9373",
+"z$    c #CF887A",
+"A$    c #E68F73",
+"B$    c #DD371E",
+"C$    c #E25142",
+"D$    c #DD3529",
+"E$    c #D5241C",
+"F$    c #ECA39F",
+"G$    c #F7D9D7",
+"H$    c #D92C25",
+"I$    c #DB291C",
+"J$    c #DE3F2E",
+"K$    c #EC9579",
+"L$    c #C27A76",
+"M$    c #AE3317",
+"N$    c #E05D12",
+"O$    c #E89A71",
+"P$    c #E79179",
+"Q$    c #DD4218",
+"R$    c #DB301A",
+"S$    c #DE3D2E",
+"T$    c #DA271D",
+"U$    c #D82C25",
+"V$    c #E25750",
+"W$    c #DA271B",
+"X$    c #DB2B1B",
+"Y$    c #DD3A19",
+"Z$    c #DD3F19",
+"`$    c #EA876D",
+" %    c #C37A76",
+".%    c #B0351A",
+"+%    c #DD5913",
+"@%    c #E25D12",
+"#%    c #E25D14",
+"$%    c #E89872",
+"%%    c #E3836D",
+"&%    c #DC3D19",
+"*%    c #DB2E1A",
+"=%    c #DB2A1B",
+"-%    c #DA251B",
+";%    c #E15650",
+">%    c #F1AEAA",
+",%    c #DA291A",
+"'%    c #DB2D1A",
+")%    c #E66F51",
+"!%    c #FBF4F3",
+"~%    c #AE3118",
+"{%    c #DD5513",
+"]%    c #E15913",
+"^%    c #E25913",
+"/%    c #E25813",
+"(%    c #E15713",
+"_%    c #E89978",
+":%    c #FAF3F3",
+"<%    c #B55953",
+"[%    c #CD3419",
+"}%    c #DC3619",
+"|%    c #DB2B1A",
+"1%    c #DB281B",
+"2%    c #F1AEAB",
+"3%    c #FCF3F2",
+"4%    c #E14D3F",
+"5%    c #E26D51",
+"6%    c #FAEEEC",
+"7%    c #AE2F18",
+"8%    c #DE5314",
+"9%    c #E05513",
+"0%    c #E05613",
+"a%    c #E05514",
+"b%    c #E05414",
+"c%    c #E79373",
+"d%    c #F6EDEC",
+"e%    c #B35853",
+"f%    c #B92D19",
+"g%    c #DB3719",
+"h%    c #DB291A",
+"i%    c #E04C3F",
+"j%    c #F7F6F6",
+"k%    c #F2B3AD",
+"l%    c #DB2C1A",
+"m%    c #E37055",
+"n%    c #AF311B",
+"o%    c #DB4D15",
+"p%    c #E05115",
+"q%    c #E05215",
+"r%    c #DF4F18",
+"s%    c #E69074",
+"t%    c #B55C56",
+"u%    c #B82D19",
+"v%    c #DB3819",
+"w%    c #DC341A",
+"x%    c #DB2A1A",
+"y%    c #F1B3AD",
+"z%    c #E46452",
+"A%    c #DA2A1A",
+"B%    c #AD2C19",
+"C%    c #DA4817",
+"D%    c #E6917A",
+"E%    c #DB3919",
+"F%    c #DB3519",
+"G%    c #E46352",
+"H%    c #F9E3E0",
+"I%    c #E04C30",
+"J%    c #DC331A",
+"K%    c #C4756E",
+"L%    c #AD2B19",
+"M%    c #DC4518",
+"N%    c #DE4A17",
+"O%    c #DF4717",
+"P%    c #DC351A",
+"Q%    c #DC3319",
+"R%    c #E04A30",
+"S%    c #E5E3E2",
+"T%    c #F3BFB6",
+"U%    c #DE4421",
+"V%    c #D03819",
+"W%    c #D93E19",
+"X%    c #DD4118",
+"Y%    c #DE4221",
+"Z%    c #EAE8E8",
+"`%    c #F1B2A4",
+" &    c #DE4019",
+".&    c #DD3919",
+"+&    c #F1B1A4",
+"@&    c #F1B3A4",
+"#&    c #E04B20",
+"$&    c #DD3B18",
+"%&    c #DC3C18",
+"&&    c #DD3E18",
+"*&    c #DC3B18",
+"=&    c #DD3A18",
+"-&    c #DF4A20",
+";&    c #EEEDED",
+">&    c #FEFDFD",
+",&    c #F4C2B5",
+"'&    c #E25A2E",
+")&    c #DC3119",
+"!&    c #DB2F1A",
+"~&    c #DC3019",
+"{&    c #DE4317",
+"]&    c #E2582E",
+"^&    c #FAE5DF",
+"/&    c #E7754F",
+"(&    c #DE4017",
+"_&    c #DE3F17",
+":&    c #E6744F",
+"<&    c #F3BDAC",
+"[&    c #E56C3B",
+"}&    c #DF4516",
+"|&    c #DC3518",
+"1&    c #DA2B1A",
+"2&    c #DE4516",
+"3&    c #E46A3C",
+"4&    c #E1DFDE",
+"5&    c #FCF4F2",
+"6&    c #F3BDA9",
+"7&    c #E77B4B",
+"8&    c #E35E1C",
+"9&    c #E15513",
+"0&    c #E04B15",
+"a&    c #DE4116",
+"b&    c #DD3918",
+"c&    c #DC3418",
+"d&    c #DC3219",
+"e&    c #DF4116",
+"f&    c #E15413",
+"g&    c #E25D1D",
+"h&    c #DDDADA",
+"i&    c #F9E0D7",
+"j&    c #F2B69C",
+"k&    c #EB9164",
+"l&    c #E56D31",
+"m&    c #E35E15",
+"n&    c #E35F12",
+"o&    c #E26011",
+"p&    c #E25E15",
+"q&    c #FCF5F2",
+"r&    c #FAE4DE",
+"s&    c #E2E1E0",
+"t&    c #E5E3E3",
+"u&    c #E0DFDE",
+"v&    c #E9E9E8",
+"                                        . + @ # $ % & *                                         ",
+"                                = - ; > , ' ) ! ! ~ { ] ^ / ( _                                 ",
+"                            : < [ } | | | | 1 2 3 1 | | | 4 5 6 7 8                             ",
+"                        9 > 0 a b c d e f g h h h h i f e j c b | ' k %                         ",
+"                    l m 5 | n o p q r r s t u v w u t s r x q p y n 4 [ z A                     ",
+"                  B C 4 | D E F G H I J K L M N N M L O J P Q G R E S | } ^ &                   ",
+"                T 5 a U V W W X Y Z ` `  ..... ..... ...` +.Z @.X G G #.U | $.%.                ",
+"              &.0 | *.=.-.;.>.,.'.'.).).!.~.~.!.{.~.!.).).].^.'.,./.(.W _.*.| :.<.              ",
+"            [.0 | }.|.1.2.3.].!.4.4.5.6.7.7.7.8.8.7.7.7.5.5.4.!.].].9.2.0.|.}.| :.%.            ",
+"          a.0 | b.c.d.e.f.{.5.g.h.8.i.i.j.i.i.j.i.i.j.i.i.8.h.g.g.5.{.f.k.d.1.b.b $.&           ",
+"        l.m.a n.o.p.q.r.7.h.8.i.s.t.u.v.w.v.x.y.x.v.w.v.u.z.s.i.i.8.h.A.r.B.p.o.C.| ^ D.        ",
+"        E.| U q.F.G.H.8.j.t.t.I.J.y.K.K.K.L.L.L.L.L.L.K.K.y.y.J.M.t.j.j.8.N.G.O.B.U } z         ",
+"      z P.| Q.R.S.T.i.s.z.x.U.V.W.X.Y.Z.`.Z.Z. +.+Z.`.Z.Z.++@+#+$+%+v.u.j.&+*+=+R.Q.| [ %       ",
+"      , | -+;+>+,+s.u.x.'+)+!+~+~+W.{+]+^+/+/+(+/+/+(+_+]+:+#+~+~+<+I.'+w.u.i.,+[+}+-+4 k       ",
+"    |+4 1+2+3+4+z.y.K.L.5+!+a a a a 6+7+8+9+9+9+9+9+9+8+0+a+a a a a <+b+K.y.w.t.c+3+2+1+' 8     ",
+"    6 a d+e+f+g+y.h+Y.i+V.~+a ~+~+a ~+W.j+k+k+l+k+k+l+m+#+a ~+~+~+a ~+$+n+h+'+y.o+f+3+p+| 7     ",
+"  a.0 b q+r+s+K.L.Z..+t+W.~+a ~+~+a ~+~+W.u+v+w+x+v+y+#+~+a ~+~+~+a ~+z+A+B+Y.K.y.s+C+D+b 6 _   ",
+"  k | E+F+G+H+Y.`._+/+I+J+W.a ~+~+a ~+~+a K+L+M+N+O+P+~+~+a ~+~+~+a z+Q+R+S+.+`.h+H+T+U+E+5 (   ",
+"  V+| W+X+Y+Z+ +^+`+9+ @l+.@+@a a a a a a a W.@@#@$@a a a a a a a %@&@*@=@8+(+^+`.-@;@>@W+4 /   ",
+"  ,@| '@)@!@~@{@`+]@^@k+w+/@(@W.~+a ~+~+a ~+~+W.$@~+a ~+~+a ~+~+z+&@_@:@l+^@]@`+{@<@[@}@|@| ^   ",
+"< 0 | 1@2@3@4@5@ @k+6@7@8@9@0@a@W.a ~+~+a ~+~+a ~+~+a ~+~+a ~+z+Q+b@c@d@w+k+^@9+e@f@g@h@1@| ] i@",
+"j@4 | k@l@m@n@o@p@q@r@M+s@t@u@v@w@+@a a a a a a a a a a a a +@&@x@y@z@s@8@r@q@p@A@B@C@l@D@| { & ",
+"7 4 E@F@G@H@I@J@K@L@s@0@M@N@O@P@Q@R@W.~+a ~+~+a ~+~+a ~+~+z+&@S@T@U@V@W@s@N+X@Y@Z@4@`@ #.#+#~ % ",
+"@#| ##$#%#&#I@*#=#-#;#>#,#'#)#!#~#{#]#W.a ~+~+a ~+~+a ~+^#Q+/#(#_#:#<#[#}#|#1#2#Z@4@3#4#5###! $ ",
+"; 4 6#7#%#&#8#9#=#0#a#b#c#d#e#{#f#g#h#i#a a a a a a a a z+j#k#l#m#!#n#o#p#q#r#2#s#t#u#v#w#6#! # ",
+"x#4 E@y#z#H@I@*#A#B#C#D#E#F#G#g#H#I#i#~+a ~+~+a ~+~+a ~+~+J#K#H#L#{#~#M#N#O#P#2#Z@4@Q#R#S#E@) @ ",
+"; 4 | T#U#m@V#o@W#X#Y#Z#`#`# $E#.$+$~+~+a ~+~+a ~+~+a ~+~+a @$#$$$%$&$&$N#*$=$-$s#;$>$,$'$| ' = ",
+")$!$| ~${$]$t#^$/$($*$_$:$<$[$}$i#a a a a a a a a a a a a a a J#|$1$2$3$N#4$g#5$6$7$8$9$0$| , . ",
+"  ) | a$b$c$;$d$F#e$4$f$3$g$h$i$~+a ~+~+a ~+~+z+^#~+a ~+~+a ~+~+J#j$k$Z#l$$$L#~#m$n$o$p$q$| >   ",
+"  , | r$s$t$u$v$~#L#E#w$x$y$+$~+~+a ~+~+a ~+^#Q+z$J#a ~+~+a ~+~+~+K+A$D#*$M#G#!#B$C$D$E$F$| ;   ",
+"  ^ | G$H$I$J$c#!#l#($*$K$i#a a a a a a a +@L$M$N$O$6+a a a a a a a J#P$Q$g#m#d#R$S$T$U$G$} -   ",
+"  &.P.b V$W$X$R$d#Y$Z$`$i#~+a ~+~+a ~+~+z+ %.%+%@%#%$%J#~+a ~+~+~+a ~+J#%%&%e#:#*%=%-%;%b [ =   ",
+"    m.a >%,%=%'%:#e#G#)%!%~+a ~+~+a ~+^#Q+~%{%]%^%/%(%_%J#a ~+~+~+a ~+:%<%[%}%o#|%1%W$2%a <     ",
+"    m | 3%4%'%|%R$d#~#f#5%6%a a a a +@L$7%8%9%0%9%a%b%[$c%6+a a a a d%e%f%g%:#*%h%|%i%3%0 :     ",
+"      j%a k%P@|%l%P@}%Y$L#m%6%~+~+z+ %n%o%p%q%1$q%q%p%<$r%s%W.~+~+d%t%u%v%w%R$|%x%<#y%| >       ",
+"      < | | z%w%A%*%:#!#m#L#5%!%z+Q+B%C%:$`#2$2$2$`#:$&$3$_$D%J#:%e%u%E%F%o#l%,%P@G%| 5 9       ",
+"        :.| H%I%n#x%*%J%!#Y$f#5%K%L%M%f$_$Z#Z#N%3$Z#_$O%f$Y#4$%%<%f%v%P%o#'%h%Q%R%H%4 m         ",
+"        S%0 a T%U%n#|%*%:#}%~#G#V%W%E#4$*$Y#w$l$w$w$Y#*$E#X%e$&%[%g%d#'#'%x%P@Y%T%a C l         ",
+"          Z%4 | `%X%}%x%*%P@d#e#Y$l#L#e$($$$E#Q$E#$$X% &Z$f#F#.&}%)#R$l%h%n#e$+&| 5 B           ",
+"            > 4 | @&#&$&|%l%R$:#d#!#~#m#%&f#f#&&&&f#%&*&m#~#!#n#c#*%|%x%=&-&@&| 0 T             ",
+"              ;&4 >&,&'&%$)&|%'%R$c#w%}%!#e#e#~#~#e#e#!#d#n#P@!&l%x%~&{&]&,&>&0 &.              ",
+"                > 4 a ^&/&2$(&*%|%'%!&'#c#J%J%)#w%J%:#'#R$*%l%=%'%_&:$:&^&a 0 [.                ",
+"                  Z%0 | | <&[&b%}&|&|%1&1&l%'%'%'%'%l%1&A%|%|&2&[$3&<&| | m.4&                  ",
+"                    S%:.| a 5&6&7&8&9&0&a&b&c&d&)&c&b&e&0&f&g&7&6&5&| P.E.h&                    ",
+"                        < j%| a b i&j&k&l&m&n&o&n&n&p&l&k&j&i&b a 4 , z                         ",
+"                            m m.P.| | | | | q&r&r&5&| | | | | 0 6 s&                            ",
+"                                t&^ , ) !$4 4 4 | 4 4 0 ,@V+k u&                                ",
+"                                        v&; x#; @#7 j@<                                         "};
diff --git a/src/icons/save.xcf b/src/icons/save.xcf
new file mode 100644 (file)
index 0000000..ab34040
Binary files /dev/null and b/src/icons/save.xcf differ
diff --git a/src/icons/save.xpm b/src/icons/save.xpm
new file mode 100644 (file)
index 0000000..6079335
--- /dev/null
@@ -0,0 +1,130 @@
+/* XPM */
+static const char * save_xpm[] = {
+"20 20 107 2",
+"      c #FFFFFF",
+".     c #E4E4FB",
+"+     c #C2C2F5",
+"@     c #ACABEF",
+"#     c #A2A1EA",
+"$     c #9B9AE7",
+"%     c #9493E4",
+"&     c #8F8EE0",
+"*     c #8D8CDE",
+"=     c #A1A0E3",
+"-     c #D1D1F1",
+";     c #DBDBFF",
+">     c #9392F8",
+",     c #F6F8FB",
+"'     c #4B58BE",
+")     c #A4A3D4",
+"!     c #E2E2FA",
+"~     c #BEBDFF",
+"{     c #8A89EF",
+"]     c #EAEEF6",
+"^     c #3F52B8",
+"/     c #333367",
+"(     c #C4C4E1",
+"_     c #BDBCF2",
+":     c #8180E6",
+"<     c #DEE5F0",
+"[     c #344DB3",
+"}     c #7A79DF",
+"|     c #7E7DBB",
+"1     c #A3A2EA",
+"2     c #7776DC",
+"3     c #D2DBEA",
+"4     c #2847AD",
+"5     c #7271D7",
+"6     c #5857A3",
+"7     c #9897E5",
+"8     c #6E6DD3",
+"9     c #C6D1E5",
+"0     c #1C41A7",
+"a     c #6767CC",
+"b     c #4D4D9A",
+"c     c #9291E2",
+"d     c #6766CC",
+"e     c #BDCAE1",
+"f     c #113BA1",
+"g     c #5C5DC2",
+"h     c #4A4A94",
+"i     c #8B8ADF",
+"j     c #BCBBFF",
+"k     c #B7B6FF",
+"l     c #6063C9",
+"m     c #565EC4",
+"n     c #5C5DC1",
+"o     c #5456BA",
+"p     c #47478F",
+"q     c #8483DB",
+"r     c #B4B3FF",
+"s     c #AEADFF",
+"t     c #A4A3FC",
+"u     c #8F8EF4",
+"v     c #8786EC",
+"w     c #6C6BD1",
+"x     c #4C50B2",
+"y     c #444489",
+"z     c #8281D9",
+"A     c #AAA9FF",
+"B     c #A09FFB",
+"C     c #9493F5",
+"D     c #4B5B71",
+"E     c #526276",
+"F     c #5B6A7D",
+"G     c #4C4FB2",
+"H     c #4449AA",
+"I     c #494988",
+"J     c #9898DF",
+"K     c #A09FFF",
+"L     c #9190F5",
+"M     c #000000",
+"N     c #343C47",
+"O     c #CED9E9",
+"P     c #D4DDEC",
+"Q     c #677485",
+"R     c #434BAE",
+"S     c #3C42A3",
+"T     c #6E6E9E",
+"U     c #CDCDEF",
+"V     c #9A99FF",
+"W     c #68788D",
+"X     c #D8E0ED",
+"Y     c #E0E7F1",
+"Z     c #737F8F",
+"`     c #3541A3",
+" .    c #3C42A2",
+"..    c #353D9C",
+"+.    c #BBBBD0",
+"@.    c #C2C1F8",
+"#.    c #2444AA",
+"$.    c #213247",
+"%.    c #ABB4C3",
+"&.    c #B3BBC6",
+"*.    c #BCC1CA",
+"=.    c #C4C8CE",
+"-.    c #484D56",
+";.    c #333E9E",
+">.    c #363D9C",
+",.    c #8E92C6",
+"'.    c #6D6C9A",
+"                                        ",
+"                                        ",
+"                                        ",
+"          . + @ # $ % & * = -           ",
+"        ; >               , ' )         ",
+"      ! ~ {             , ] ^ / (       ",
+"      _ ~ :           , ] < [ } |       ",
+"      1 ~ 2         , ] < 3 4 5 6       ",
+"      7 ~ 8       , ] < 3 9 0 a b       ",
+"      c ~ d     , ] < 3 9 e f g h       ",
+"      i j k l m ' ^ [ 4 0 f n o p       ",
+"      q r s t u v : } 5 w n o x y       ",
+"      z A B C D D D D E F o G H I       ",
+"      J K L v D M N O P Q R H S T       ",
+"      U V v : D N W X Y Z `  ...+.      ",
+"        @.: #.$.%.&.*.=.-.;.>.,.        ",
+"          ( | 6 b h p y I '.+.          ",
+"                                        ",
+"                                        ",
+"                                        "};
diff --git a/src/icons/settings-40x40.png b/src/icons/settings-40x40.png
new file mode 100644 (file)
index 0000000..d15e144
Binary files /dev/null and b/src/icons/settings-40x40.png differ
diff --git a/src/icons/settings.xpm b/src/icons/settings.xpm
new file mode 100644 (file)
index 0000000..f98fffd
--- /dev/null
@@ -0,0 +1,115 @@
+/* XPM */
+static const char *settings_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"40 40 69 1",
+"  c #474A4A",
+". c #494D4D",
+"X c #575B5B",
+"o c #5B5F5F",
+"O c #5D6262",
+"+ c #626565",
+"@ c #656969",
+"# c #696D6D",
+"$ c #6D7171",
+"% c #727777",
+"& c #757A7A",
+"* c #7A7E7E",
+"= c #7C8282",
+"- c #828787",
+"; c #858A8A",
+": c #898E8E",
+"> c #818E92",
+", c #859295",
+"< c #8C9292",
+"1 c #899699",
+"2 c #8D999C",
+"3 c #919696",
+"4 c #949A9B",
+"5 c #9A9E9E",
+"6 c #949FA1",
+"7 c #999FA0",
+"8 c #95A2A4",
+"9 c #9CA3A3",
+"0 c #99A6A9",
+"q c #9DAAAD",
+"w c #A1A6A6",
+"e c #A4AAAB",
+"r c #A9ADAD",
+"t c #A2AEB1",
+"y c #A5B2B4",
+"u c #ABB2B3",
+"i c #ACB7B9",
+"p c #AEBABC",
+"a c #B1B6B6",
+"s c #B4BBBC",
+"d c #BABEBE",
+"f c #B4BEC0",
+"g c #B8BFC0",
+"h c #B6C1C3",
+"j c #BBC3C4",
+"k c #BBC6C8",
+"l c #BEC9CB",
+"z c #C2C5C5",
+"x c #C5CBCB",
+"c c #CACDCD",
+"v c #C3CED0",
+"b c #C6D1D3",
+"n c #CCD3D4",
+"m c #CCD7D9",
+"M c #CED9DB",
+"N c #D2D5D5",
+"B c #D5DADB",
+"V c #DBDDDD",
+"C c #D5DFE0",
+"Z c #D7E1E3",
+"A c #DDE1E1",
+"S c #E2E5E5",
+"D c #E5E8E8",
+"F c #EAEDED",
+"G c #EEF1F1",
+"H c #F3F5F5",
+"J c #F6F9F9",
+"K c #FAFBFB",
+"L c None",
+/* pixels */
+"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLLLihlbmxLLLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLLLhbmVANLLLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLLLlmCSSVdLLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLLjmAAASAzLLLLLLLLLLLLLLLL",
+"LLLLLLLL80eLLLLkbVSSSSSVcLLLLxVVLLLLLLLL",
+"LLLLLL8880yiihMCAAAVBASSSSccBDDDScLLLLLL",
+"LLLLLL68qyphlnZANhewwrdNSSSSDDDDDSzLLLLL",
+"LLLLL40qypklmndw<;------5dVDDDDDDDaLLLLL",
+"LLLLL<tyfhlbzw<<3:;;;;;;;:rNDDDDDV-LLLLL",
+"LLLLLL4pkxmh<::3raaw53<;<<3wNDDDSrLLLLLL",
+"LLLLLL=uvmj6<:<9VDVVNNcu37wwaNDDn-LLLLLL",
+"LLLLLLLkmn53<<rNDDNzaarjzrrrrdSDBrLLLLLL",
+"LLLLLLsmMs444wcVKJxw55-*5arraaNSSxLLLLLL",
+"LLLLLLbCxw55wsrxjLLLLLL@#&aaaszVDVLLLLLL",
+"LLLLsjVAdw99r54;LLLLLLLLO+<addzNDSNnLLLL",
+"LrhbNVSVrwee5&LLLLLLLLLLLL%wdzzcDDDDAAhL",
+"LibmAAANurra*+LLLLLLLLLLLL@3zzccDDDDDZkL",
+"LsBZASSNauas+LLLLLLLLLLLLLL*ccccAFDAZMpL",
+"LsAAAAAcaaaa+LLLLLLLLLLLLLL&ccNcADAZMbyL",
+"LdAASVSNaddd+LLLLLLLLLLLLLL*NNNcSAZMlkeL",
+"LwNVASAVazdd&LLLLLLLLLLLLLL3NVNcZZmlkf4L",
+"L#*:rdAAazzze$LLLLLLLLLLLL&aVVNcMbdy9=@L",
+"LLLL$-VAzzccz;LLLLLLLLLLLL5NVAccbl<*LLLL",
+"LLLLLLdANacNVc:LLLLLLLLLL5VSSVdzksLLLLLL",
+"LLLLLL4VSazVVScrLLLLLLLLsNSDSchjp5LLLLLL",
+"LLLLLL:cVSaNSSSSnzLLLLxNDDDDnfgpy=LLLLLL",
+"LLLLLLdBSSNaVSDDDSASFGFFDDDNsgiyq4LLLLLL",
+"LLLLLLVSSVVSdcSDDFFFHJHGDAxffiq068LLLLLL",
+"LLLLLcSVVSSVVczNDFDHHJHGBlffyt06216LLLLL",
+"LLLLLzVVSVVSSVVNzcBSGHGClhfy0861,>,LLLLL",
+"LLLL+-BSVVSVNVVSVVNVSFZmffyy061,>1%LLLLL",
+"LLLLL.-zVVx4o:xNVAAAZZBliy:O;21>2= LLLLL",
+"LLLLLL+5Bz:oL+:<cVCBmMmk;=XLO:q04#LLLLLL",
+"LLLLLLL:a:LLLLLLeVMbllbqLLLLLLea%LLLLLLL",
+"LLLLLLLLLLLLLLLL4bxkhpk4LLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLL;ghpyqs9LLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLLLeshshxLLLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLLL#4ryzNLLLLLLLLLLLLLLLLL",
+"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL"
+};
diff --git a/src/icons/synchronize-48x48.png b/src/icons/synchronize-48x48.png
new file mode 100644 (file)
index 0000000..b9dce6f
Binary files /dev/null and b/src/icons/synchronize-48x48.png differ
diff --git a/src/icons/synchronize.xpm b/src/icons/synchronize.xpm
new file mode 100644 (file)
index 0000000..c112456
--- /dev/null
@@ -0,0 +1,211 @@
+/* XPM */
+static const char *synchronize_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"48 50 155 2",
+"   c #2FBF25",
+".  c #32BF28",
+"X  c #37BF2D",
+"o  c #38BF2E",
+"O  c #39A631",
+"+  c #3ABF31",
+"@  c #3BBE32",
+"#  c #41B339",
+"$  c #47B13F",
+"%  c #42BF39",
+"&  c #2BC81F",
+"*  c #2AE01D",
+"=  c #29E31C",
+"-  c #2AE31C",
+";  c #2AE21D",
+":  c #2CE21F",
+">  c #2BE41D",
+",  c #2AE61C",
+"<  c #2BE41E",
+"1  c #27E819",
+"2  c #26ED18",
+"3  c #28EB19",
+"4  c #28EC1A",
+"5  c #29ED1B",
+"6  c #2AED1B",
+"7  c #2AE81D",
+"8  c #2BEB1D",
+"9  c #2DE91F",
+"0  c #2CEA1E",
+"q  c #2DEA1F",
+"w  c #2AEF1C",
+"e  c #2BEF1D",
+"r  c #2CEF1D",
+"t  c #2CED1E",
+"y  c #2CEE1E",
+"u  c #2DEE1F",
+"i  c #25F116",
+"p  c #25F616",
+"a  c #25F716",
+"s  c #26F616",
+"d  c #25F815",
+"f  c #25F915",
+"g  c #25FA15",
+"h  c #24FB15",
+"j  c #25FB15",
+"k  c #25F816",
+"l  c #26F816",
+"z  c #26F916",
+"x  c #27F917",
+"c  c #25FB16",
+"v  c #26FA16",
+"b  c #26FB16",
+"n  c #26FA17",
+"m  c #27FA17",
+"M  c #26FB17",
+"N  c #24FD14",
+"B  c #24FC15",
+"V  c #25FC15",
+"C  c #24FD15",
+"Z  c #25FD15",
+"A  c #24FE14",
+"S  c #24FF14",
+"D  c #24FE15",
+"F  c #25FD16",
+"G  c #26FC16",
+"H  c #27F318",
+"J  c #27F419",
+"K  c #28F019",
+"L  c #28F119",
+"P  c #29F01A",
+"I  c #28F519",
+"U  c #28F619",
+"Y  c #28F719",
+"T  c #29F51A",
+"R  c #29F71A",
+"E  c #2AF61B",
+"W  c #2BF11D",
+"Q  c #2DF01E",
+"!  c #2BF41D",
+"~  c #2BF61D",
+"^  c #27FA18",
+"/  c #28F818",
+"(  c #28F919",
+")  c #28FA19",
+"_  c #2CC321",
+"`  c #2DC122",
+"'  c #2DC222",
+"]  c #2FC424",
+"[  c #34C22A",
+"{  c #35C32A",
+"}  c #37C12C",
+"|  c #34CD29",
+" . c #35CD29",
+".. c #34CE29",
+"X. c #37C82C",
+"o. c #39CD2F",
+"O. c #2ED622",
+"+. c #2FD623",
+"@. c #2EDC21",
+"#. c #2EDE21",
+"$. c #31D625",
+"%. c #33D427",
+"&. c #30DB23",
+"*. c #31D824",
+"=. c #31DB24",
+"-. c #31DC24",
+";. c #31DF24",
+":. c #33DD26",
+">. c #33DD27",
+",. c #34DF27",
+"<. c #33D028",
+"1. c #34D028",
+"2. c #35D32A",
+"3. c #3AD02F",
+"4. c #39D22E",
+"5. c #38D52C",
+"6. c #36DF2A",
+"7. c #37DF2B",
+"8. c #3BDB2F",
+"9. c #3BCB30",
+"0. c #3CC932",
+"q. c #3BCE30",
+"w. c #3CCF32",
+"e. c #3FD434",
+"r. c #2EE021",
+"t. c #2FE222",
+"y. c #2DE420",
+"u. c #2DE620",
+"i. c #2DE720",
+"p. c #2EE721",
+"a. c #2FE522",
+"s. c #2DEA20",
+"d. c #30E023",
+"f. c #30E123",
+"g. c #31E024",
+"h. c #33E326",
+"j. c #31E823",
+"k. c #37E32A",
+"l. c #41C137",
+"z. c #41CB37",
+"x. c #41C038",
+"c. c #45C63C",
+"v. c #41D236",
+"b. c #42D637",
+"n. c #4BAD44",
+"m. c #50AD49",
+"M. c #4EB346",
+"N. c #49BB40",
+"B. c #4ABC41",
+"V. c #54B34D",
+"C. c #55B34E",
+"Z. c #52B94B",
+"A. c #5AB354",
+"S. c #699C65",
+"D. c None",
+/* pixels */
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.O D.D.S.A.A.A.A.V.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.e.e N S S S S O.. 4 S N N N S y v.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.8 N N S S S b ..D.D.D.o.N N N S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.@ h S S S S S Q D.D.D.D.D.D.D.S S S S S S b X D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.% S S S S S S S D.D.D.D.D.D.D.D.D.b S S S S S S { D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.b S S S S S S D.D.D.D.D.D.D.D.D.D.X.S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.b S S S S S S *.D.D.D.D.D.D.D.D.D.D.D.f.S S S S S S Y D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.#.S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.D.( S S S S S S $.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.S S S S S S S z.D.D.D.D.D.D.D.D.D.D.D.D.D.b.S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.- S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.( S S S S S S 6.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.b S S S S S S 6.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.f.S S S S S S ^ D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.<.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S w.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.a.S S S S S S 0 D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.e S S S S S S a.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.S S S S S S S $.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.- S S S S S S Y D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D...s s b S S S S S S S b s s _ D.D.D.D.D.D.",
+"D.D.D.D.6.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.x.Y N N S S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.8 S S S S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.2 N S S S S S S b Z.D.D.D.D.D.D.D.D.",
+"D.D.D.D.;.S S S S S S 0 D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.f.S S S S N b D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.i S S S S S S -.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D...b S S b D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D., S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.y b D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.M.B.B.B.B.B.B.$ D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.V.s.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.b f s b b s d m.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.( S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.` S S S S S 5.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.$ S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.] b S S S S S S t.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.* S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.c.S S S S S S S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.6.S S S S S S b D.D.D.D.D.D.D.D.",
+"D.D.D.- b S S S S S S S S S S S 0.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.j.S S S S S S 4 D.D.D.D.D.D.D.D.",
+"D.D.D.` _ ` y S S S S S S b   ` ` D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.Y S S S S S S #.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.4.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S { D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.N S S S S S S f.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.$.S S S S S S S D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.4 S S S S S S W D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.J S S S S S S : D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.e.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.~ S S S S S S k.D.D.D.D.D.D.D.D.D.D.D.D.D.D.a.S S S S S S y D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.v.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.y S S S S S S s.D.D.D.D.D.D.D.D.D.D.D.D.4 S S S S S S y D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.S S S S S S S 0.D.D.D.D.D.D.D.D.D.D.$.S S S S S S Y D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.@ S S S S S S b D.D.D.D.D.D.D.D.D.} S S S S S S S # D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.& S S S S S S ~ D.D.D.D.D.D.D.n.Y S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.% J S S S S S Y D.D.D.D.D.1.! S S S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.3 S S S S S N *.D.D.a.N N N S S S a.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.t.8.1 1 3 > ..} - ;.2.-.;.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D."
+};
diff --git a/src/icons/tools-48x48.png b/src/icons/tools-48x48.png
new file mode 100644 (file)
index 0000000..289bc71
Binary files /dev/null and b/src/icons/tools-48x48.png differ
diff --git a/src/icons/tools.xpm b/src/icons/tools.xpm
new file mode 100644 (file)
index 0000000..045fb53
--- /dev/null
@@ -0,0 +1,308 @@
+/* XPM */
+static const char *tools_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"48 48 254 2",
+"   c #435C69",
+".  c #47606D",
+"X  c #49626E",
+"o  c #4B6370",
+"O  c #546D7A",
+"+  c #57707D",
+"@  c #59717E",
+"#  c #008636",
+"$  c #058D3A",
+"%  c #0C8E3E",
+"&  c #029037",
+"*  c #0B933D",
+"=  c #0E9B3C",
+"-  c #20A23E",
+";  c #4CAE3D",
+":  c #52B030",
+">  c #5DB435",
+",  c #56B33D",
+"<  c #7EBF25",
+"1  c #74BC2D",
+"2  c #7DBF2B",
+"3  c #73BC34",
+"4  c #78BE3B",
+"5  c #7FC028",
+"6  c #7FC136",
+"7  c #7DC03D",
+"8  c #128F41",
+"9  c #139344",
+"0  c #199346",
+"q  c #119941",
+"w  c #1C9B4D",
+"e  c #21974D",
+"r  c #20994F",
+"t  c #249B53",
+"y  c #2A9F57",
+"u  c #1BA04A",
+"i  c #29A440",
+"p  c #21A04F",
+"a  c #3BAA4D",
+"s  c #29A256",
+"d  c #2DA35A",
+"f  c #3AA957",
+"g  c #32A55D",
+"h  c #33AA5D",
+"j  c #3CAD5D",
+"k  c #4EAF41",
+"l  c #57B44C",
+"z  c #41AC57",
+"x  c #43AE5B",
+"c  c #47B05C",
+"v  c #4CB15D",
+"b  c #5AB557",
+"n  c #53B35C",
+"m  c #5AB65B",
+"M  c #5FB85B",
+"N  c #6CBB43",
+"B  c #76BF42",
+"V  c #74BD49",
+"C  c #66BB55",
+"Z  c #6BBC54",
+"A  c #64BA5B",
+"S  c #6BBD5B",
+"D  c #71BF5E",
+"F  c #43A567",
+"G  c #48A86C",
+"H  c #4DB36E",
+"J  c #5EB862",
+"K  c #5BB76A",
+"L  c #57B375",
+"P  c #62BC7D",
+"I  c #79C044",
+"U  c #7EC150",
+"Y  c #75C061",
+"T  c #7AC265",
+"R  c #7FC469",
+"E  c #76C172",
+"W  c #70C07C",
+"Q  c #82C024",
+"!  c #83C229",
+"~  c #8BC536",
+"^  c #83C33B",
+"/  c #85C443",
+"(  c #8CC745",
+")  c #87C64B",
+"_  c #8AC74B",
+"`  c #8DC84D",
+"'  c #96CB45",
+"]  c #91C94D",
+"[  c #9BCE4E",
+"{  c #8ECA51",
+"}  c #92CA50",
+"|  c #95CB5B",
+" . c #98CD5D",
+".. c #82C66B",
+"X. c #99CD66",
+"o. c #9FD06C",
+"O. c #81C771",
+"+. c #8CCA75",
+"@. c #8ACA7A",
+"#. c #A2D36E",
+"$. c #ABD669",
+"%. c #5D7582",
+"&. c #5F7988",
+"*. c #5E7F91",
+"=. c #617580",
+"-. c #617986",
+";. c #647C89",
+":. c #687F8C",
+">. c #607F91",
+",. c #6B818D",
+"<. c #638495",
+"1. c #6B8694",
+"2. c #6E8897",
+"3. c #668698",
+"4. c #6C8B9C",
+"5. c #728793",
+"6. c #758A95",
+"7. c #768C9A",
+"8. c #798E9A",
+"9. c #7E929E",
+"0. c #66B881",
+"q. c #69BB82",
+"w. c #728FA0",
+"e. c #7592A4",
+"r. c #7C96A5",
+"t. c #7B98A9",
+"y. c #75C08C",
+"u. c #7AC391",
+"i. c #82939D",
+"p. c #8496A1",
+"a. c #8399A7",
+"s. c #8C9BA4",
+"d. c #819DAE",
+"f. c #8C9DA8",
+"g. c #909EA5",
+"h. c #8FA1AC",
+"j. c #93A3AD",
+"k. c #9AA7AD",
+"l. c #9BA8AF",
+"z. c #87A1B1",
+"x. c #8BA5B5",
+"c. c #93A5B0",
+"v. c #94A8B5",
+"b. c #9AA9B2",
+"n. c #93ACBB",
+"m. c #99AFBD",
+"M. c #99B0BF",
+"N. c #A2AEB4",
+"B. c #A2B2BC",
+"V. c #ABB5BB",
+"C. c #AEB8BE",
+"Z. c #B1BABF",
+"A. c #82C786",
+"S. c #97D087",
+"D. c #9BD084",
+"F. c #90CE9B",
+"G. c #A4D387",
+"H. c #B1D986",
+"J. c #B3DA8A",
+"K. c #AFD993",
+"L. c #A5D79C",
+"P. c #A7D89C",
+"I. c #ADD99D",
+"U. c #B1DA94",
+"Y. c #BADE9E",
+"T. c #90CEA2",
+"R. c #98CEA9",
+"E. c #93D1A0",
+"W. c #A0D5A6",
+"Q. c #ADD9A2",
+"!. c #B1DBA6",
+"~. c #BCDFA9",
+"^. c #A2D5B3",
+"/. c #A3D9B6",
+"(. c #ADDBB4",
+"). c #B0DABC",
+"_. c #BFE2B4",
+"`. c #C1E2AD",
+"'. c #CBE5A8",
+"]. c #CEE7B6",
+"[. c #D1E9BC",
+"{. c #9DB4C2",
+"}. c #A1B6C3",
+"|. c #A4B9C7",
+" X c #ABBAC3",
+".X c #A6BAC9",
+"XX c #ABBECD",
+"oX c #B3BDC2",
+"OX c #ABC1C0",
+"+X c #AEC1CE",
+"@X c #B9C2C7",
+"#X c #B3C2CC",
+"$X c #BCC5CB",
+"%X c #AFDEC1",
+"&X c #B7DCC1",
+"*X c #B9DDC3",
+"=X c #B5C7D3",
+"-X c #B9C7D0",
+";X c #B7C8D4",
+":X c #BACBD5",
+">X c #BFCFD9",
+",X c #C0C7CC",
+"<X c #C3CBCE",
+"1X c #C7D1CB",
+"2X c #CCD4CE",
+"3X c #C3CDD3",
+"4X c #C8CFD3",
+"5X c #CAD1D5",
+"6X c #C2D1DB",
+"7X c #CAD6DD",
+"8X c #CFD9DF",
+"9X c #D7DDD3",
+"0X c #DADDD5",
+"qX c #D1D7DA",
+"wX c #D4DADE",
+"eX c #D9DCDC",
+"rX c #C6E4CE",
+"tX c #D7ECC5",
+"yX c #D8ECC6",
+"uX c #D7ECCF",
+"iX c #D1EAD7",
+"pX c #DCEED6",
+"aX c #D4EADA",
+"sX c #E2E4DE",
+"dX c #E6EBDE",
+"fX c #E4F2DA",
+"gX c #CDD8E0",
+"hX c #D3DDE4",
+"jX c #D9DDE0",
+"kX c #D6E0E6",
+"lX c #DBE1E5",
+"zX c #DCE4E9",
+"xX c #E3E4E4",
+"cX c #E2EFE5",
+"vX c #E1E7EB",
+"bX c #E4EAEE",
+"nX c #EBECED",
+"mX c #E2F2E4",
+"MX c #EEF6E4",
+"NX c #E6F4EC",
+"BX c #EDF4ED",
+"VX c #EFF8ED",
+"CX c #F1F8E7",
+"ZX c #F2F8ED",
+"AX c #E6ECF0",
+"SX c #EAEEF1",
+"DX c #EDF1F3",
+"FX c #F2F4F5",
+"GX c #F5F9F4",
+"HX c #F9FBF7",
+"JX c #F4F6F8",
+"KX c #F7F9FA",
+"LX c #FDFDFD",
+"PX c None",
+/* pixels */
+"PXPXPXPXPXPXPXPXPXPXPXPXPXPX@XoXoXoX@X$X$XoXoXC.@XPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXPXPXPXPXPXPX X4XjXnXnXbXlXqX4X<X,X,X,X,X<X5XeXvXnXbXlX5XV.PXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXPXPXPXoXjXDXjXoXN.N.N.C.@X,X4X5X5X4X:X$X#X XB.b.j.j.l. XqXnXlX@XPXPXPXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXPX@XSXwXV.l.oXgXAXDXFXJXJXFXDXSXbXzXzXhXgXgX7X>X;X=X+X}.v.s.k.4XFX$XPXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPX5XnXV. X7XlXvXbXSXDXKXKXKXJXDXDXAXzXzXhXgXgXgX>X:X=X#XXXXX|.{.x.j.lXjXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXLX X3XgXhXlXzXAXSXDXJXKXKXJXDXSXAXvXzXkXgXgX6X>X:X=X+XXX.X|.|.{.m.j.LXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXLXhXgXhXhXkXzXbXSXDXJXJXJXJXDXAXAXzXkXhXhXgX6X>X:X=X+XXXXX|.|.{.{.{.KXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPX>XJXhXgXhXkXzXbXAXSXDXSXDXDXDXAXvXzXkXhXgXgX6X>X:X=X+XXX.X|.}.{.|.AXSXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPX<.XXGXDXzXkXzXzXvXAXAXSXSXAXAXbXvXzXhXgXgXgX6X:X;X+X+XXX{..X+XhXKXzX+XPXPXPXPXPXPXPXPXPXPXPX",
+"PXPX;.<.4..XvXKXDXDXAXAXvXAXAXAXvXzXzXkXhXgXgXgX6X:X;X;X>XgXkXJXKXvX>X+X|.PXPXPXPXPXPXPXPXPXPXPX",
+"PXPX<.<.3.4.w.z..XhXAXJXKXKXJXSXDXDXDXAXAXbXAXAXAXDXJXKXKXKXDXvXhXgX:X+X|.PXPXPXPXPXPXPXPXPXPXPX",
+"PXPX&.<.3.4.4.e.r.t.t.n.|.+X:XgXkXzXvXAXAXDXDXJXKXLXLXJXDXAXvXkXgXgX:X+X|.PXPXPXPXPXPXPXPXPXPXPX",
+"PXPX*.<.<.4.4.e.e.t.d.x.x.{.{.{..X+X=X>XgXkXzXSXFXLXKXJXDXAXzXkXhXgX:X+X|.PXPXPXPXPXPXPXPXPXPXPX",
+"PXPX*.<.3.3.4.w.e.t.d.z.x.n.{.{..X+X=X>XgXkXvXSXFXLXLXJXDXAXzXzXhX6X:XXX|.PXPXPXPXPXPXPXPXPXPXPX",
+"PXPX<.<.3.4.4.e.t.t.d.z.x.n.{.{..X+X=X>XgXkXvXSXFXLXLXJXDXAXvXkXhXgX:X+X|.PXPXPXPXPXPXPXPXPXPXPX",
+"PXPXPX<.3.4.4.e.e.t.d.x.x.{.{.{..X+X=X6XgXkXvXAXFXLXKXJXDXAXzXzXhX7X:X+XPXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXPXPX7.r.w.e.e.t.d.x.z.{.{.}..X+X=X6XgXhXbXSXJXKXKXJXDXbXvXhXjXgX-XPXPXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXPXC.bX5Xw.>.w.t.d.x.x.x.{.}..XXX=X>XgXhXbXSXJXLXLXJXDXAXzXoXN.<XSXoXPXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPX,XnXg.=.    . %.&.:.r.d.x.{.|.XX=X6XhXhXjXxXzXjX7XC.s.5.o X   @ i.xXeXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXLXg.%.O %.%.O %.O %.O %.%.=.&.;.>.<.:.:.:.;.-.%.+ + O O O %.@ O @ 6.LXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPXLXs.:.:.:.:.-.:.:.:.:.:.:.:.:.:.:.:.:.:.;.:.:.:.:.:.:.:.:.:.:.:.:.5.KXPXPXPXPXPXPXPXPXPXPXPX",
+"PXPX7XbXj.i.i.i.r.w.i.i.i.i.r.8.8.r.i.i.i.r.r.i.9.9.9.9.p.j.C.$X<X4X,X5XnXOXPXPXPXPXPXPXPXPXPXPX",
+"PXPX<.#XSXgX Xv.c.j.j.j.j.j.c.c.c.j.c.c.f.j.c.c.c.c.l.@XxXFXnXaX*X).iXcXFXxX1XPXPXPXPXPXPXPXPXPX",
+"PXPX*.<.p.XXnXDXjX3XXX}.}.}.}.}.}.}.}.B.}.}.}.V.}.$XnXGX^.G 8 # # # # % F R.VXxXPXPXPXPXPXPXPXPX",
+"PXPX*.<.<.4.w.x.XXhXSXFXDXAXvXzXhXhXhXgXhXhXhXjXjXKX).e $ 8 w y d d d t 0 $ 0 ^.nX2XPXPXPXPXPXPX",
+"PXPX*.<.3.3.4.e.e.t.z.{.|.=X6XgXhXzXbXSXSXDXJXFXLXq.$ 9 s g g g h g g g g d w $ q.BX2XPXPXPXPXPX",
+"PXPX*.<.3.3.4.e.t.t.t.x.x.{.{.{..XXX=X6XgXhXbXHXq.* w g h h h /.%X%X/.d g h g s % L GX1XPXPXPXPX",
+"PXPX*.<.4.3.4.e.t.t.d.z.x.{.x.{.|.=X=X6XgXzXHXT.$ p h j c c v BXLXLXNXg F c h h d * u.nXPXPXPXPX",
+"PXPX*.<.3.4.4.e.t.t.d.x.x.n.{.{.|.XX;X6XgXSXaXq u j c v n m M BXLXLXBXf m n v c j s = rX0XPXPXPX",
+"PXPXPX<.3.3.4.e.e.t.d.z.x.n.{.{..XXX;X6XhXKXP = c v m m A S Y VXLXLXNXz S M M m v j w H FXPXPXPX",
+"PXPXPXPX4.w.4.e.e.t.t.z.x.{.{.{..XXX;X>XcXmXu a n b A Y U Y Y NXLXLXNXc Y Y A J m n z - iX2XPXPX",
+"PXPXPXV.zX4X9.1.e.t.d.z.x.n.{.}..XXX=X6XDX(.: I M Y Y T E R ..VXLXLXNXv T T Y U A A A , E.xXPXPX",
+"PXPX@XDXk.@ o     O %.2.r.z.n.}..XXX;X7XJXA.3 [ T P.Q.!.!.!.!.HXLXLXGXF.!.!.Q.Q.P.J { I W nXPXPX",
+"PXPXLXs.+ O + O O O O O O O O + %.-.:.p.LXD ^ [ #.GXLXLXLXLXLXLXLXLXLXLXLXLXLXLXLXK [ ) b FXPXPX",
+"PXPXLXp.-.;.;.;.;.;.;.;.;.-.;.;.;.;.;.i.KXD / [ $.HXLXLXLXLXLXLXLXLXLXLXLXLXLXLXKXK [ ` l FXPXPX",
+"PXPXqXcXs.7.7.7.8.8.8.7.8.8.8.8.7.7.8.s.LXO.^ [ $.HXLXLXLXLXLXLXLXLXLXLXLXLXLXLXKXK [ ` C FXPXPX",
+"PXPX<.:XFX5XB.h.j.f.f.f.f.f.x.g.h.h.h.b.JXS.6 [ ' J.J.J.J.Y.'.GXLXLXGXR.Y.J.H.H.H.N [ / +.FXPXPX",
+"PXPX*.<.t.-XSXbXjX:X X}.B.B.B.B.B.B.M.B.SX_.4 ' Q Q Q Q Q Q ~ CXLXLXNXk ! ! Q Q Q Q ~ B I.xXPXPX",
+"PXPX*.<.3.4.e.v.=XzXJXJXSXvXhXhXhX7X7X7XnXmXV ! Q Q Q Q Q Q Q CXLXLXBX; Q Q Q Q Q Q ! N pX9XPXPX",
+"PXPX*.<.3.4.4.e.e.t.d.v.XX:XgXhXzXvXbXDXDXLXD.2 Q Q Q Q Q Q Q CXLXLXNX; Q Q Q Q Q Q 1 +.FXPXPXPX",
+"PXPX*.<.3.4.w.w.e.t.d.z.n.n.{.{..XXX;X6XgXDXdXU Q Q Q Q Q Q Q MXLXLXNX; Q Q Q Q Q 5 B uXxXPXPXPX",
+"PXPX*.<.3.4.4.w.e.t.d.z.x.{.{.{..XXX;X6XgXzXKX~./ Q Q Q Q Q Q CXLXHXNX; Q Q Q Q 5 4 I.FXPXPXPXPX",
+"PXPX<.<.3.3.4.e.r.t.d.x.x.n.{.{.|.XX=X6XgXhXSXLXK./ Q Q Q Q Q '.[.[.`.> Q Q Q < 7 G.GX0XPXPXPXPX",
+"PXPX1.<.3.4.4.e.e.t.d.x.x.x.{.{.|.XX=X6XgXhXbXJXHXY.} Q Q Q Q Q Q Q Q Q Q Q < ) K.GXsXPXPXPXPXPX",
+"PXPXPX5.5.4.4.w.e.t.d.x.x.x.{.{..XXX;X6XgXzXvXSXFXHXyXo.( Q Q Q Q Q Q Q < / X.[.HXsXPXPXPXPXPXPX",
+"PXPXPXPXPX6.7.7.e.t.d.z.n.{.{.{..XXX;X6XgXhXvXnXFXKXKXHX[.J. .] ( ( `  .H.].GXFXPXPXPXPXPXPXPXPX",
+"PXPXPXPXPXPXPXPX8.8.r.a.z.x.{.{.|.XX=X6XgXhXzXbXnXFXvXeXFXHXZXfXyXyXfXZXKXGXsXPXPXPXPXPXPXPXPXPX",
+"PXPXPXPXPXPXPXPXPXPXPXPXPXPXp.w.i.i.p.s.s.s.s.s.N.PXPXPXPXPXdXnXnXnXnXdXPXPXPXPXPXPXPXPXPXPXPXPX"
+};