Browse Source

Merge to HEAD

NIX User 3 years ago
parent
commit
82679630e0

+ 0 - 33
DICOMtools/CMakeLists.txt

@@ -1,33 +0,0 @@
-#-----------------------------------------------------------------------------
-set(MODULE_NAME DICOMtools)
-
-#-----------------------------------------------------------------------------
-set(MODULE_PYTHON_SCRIPTS
-	loadDicom.py
-	importDicom.py
-	exportDicom.py
-	vtkInterface.py
-  )
-
-set(MODULE_PYTHON_RESOURCES
-  Resources/Icons/${MODULE_NAME}.png
-  )
-
-#-----------------------------------------------------------------------------
-slicerMacroBuildScriptedModule(
-  NAME ${MODULE_NAME}
-  SCRIPTS ${MODULE_PYTHON_SCRIPTS}
-  RESOURCES ${MODULE_PYTHON_RESOURCES}
-  WITH_GENERIC_TESTS
-  )
-
-#-----------------------------------------------------------------------------
-if(BUILD_TESTING)
-
-  # Register the unittest subclass in the main script as a ctest.
-  # Note that the test will also be available at runtime.
-  #slicer_add_python_unittest(SCRIPT ${MODULE_NAME}.py)
-
-  # Additional build-time testing
-  #add_subdirectory(Testing)
-endif()

+ 0 - 270
DICOMtools/Resources/Icons/DICOMtools.fig

@@ -1,270 +0,0 @@
-#FIG 3.2  Produced by xfig version 3.2.6a
-Landscape
-Center
-Inches
-Letter
-500.00
-Single
--2
-1200 2
-0 32 #c8c8c8
-0 33 #ded7de
-0 34 #c1c1c1
-0 35 #6e6e6e
-0 36 #c1c1c1
-0 37 #444444
-0 38 #8d8e8d
-0 39 #8d8e8d
-0 40 #717171
-0 41 #adadad
-0 42 #333333
-0 43 #939295
-0 44 #747075
-0 45 #555555
-0 46 #b2b2b2
-0 47 #c1c1c1
-0 48 #c2c2c2
-0 49 #6d6d6d
-0 50 #454545
-0 51 #8d8d8d
-0 52 #8d8e8d
-0 53 #dc9d92
-0 54 #f0ebdf
-0 55 #c2c2c2
-0 56 #e1c7a7
-0 57 #e0e0e0
-0 58 #d1d1d1
-0 59 #ececec
-0 60 #d97a1a
-0 61 #f0e31a
-0 62 #877dc1
-0 63 #afa092
-0 64 #827cdc
-0 65 #d5d5d5
-0 66 #8b8ba4
-0 67 #4a4a4a
-0 68 #8b6b6b
-0 69 #5a5a5a
-0 70 #636363
-0 71 #8d8d8d
-0 72 #b69a73
-0 73 #4192fe
-0 74 #be703b
-0 75 #da7700
-0 76 #d9b700
-0 77 #006400
-0 78 #5a6b3b
-0 79 #d2d2d2
-0 80 #a9a9a9
-0 81 #8d8da3
-0 82 #f2b85d
-0 83 #88986b
-0 84 #646464
-0 85 #d5d5d5
-0 86 #8b8ba4
-0 87 #b6e5fe
-0 88 #85bfeb
-0 89 #bcbcbc
-0 90 #d29552
-0 91 #8d8d8d
-0 92 #97d1fd
-0 93 #8d8d8d
-0 94 #616161
-0 95 #adb1ad
-0 96 #fe9900
-0 97 #d5d5d5
-0 98 #8b8ba4
-0 99 #8b6b6b
-0 100 #8b9b6b
-0 101 #f66b00
-0 102 #5a6b39
-0 103 #8b9b6b
-0 104 #d5d5d5
-0 105 #8b8ba4
-0 106 #8b6b6b
-0 107 #8b9b6b
-0 108 #f66b00
-0 109 #8b9b7b
-0 110 #184a18
-0 111 #d5d5d5
-0 112 #8b8ba4
-0 113 #f6bc5a
-0 114 #8b9b6b
-0 115 #636b9b
-0 116 #8b6b6b
-0 117 #f6f6f6
-0 118 #dd0000
-0 119 #8b9b6b
-0 120 #d5d5d5
-0 121 #8b8ba4
-0 122 #f6bc5a
-0 123 #8b9b6b
-0 124 #d5d5d5
-0 125 #8b8ba4
-0 126 #f6bc5a
-0 127 #8b9b6b
-0 128 #636b9b
-0 129 #526b29
-0 130 #939393
-0 131 #006300
-0 132 #8b8ba4
-0 133 #8b8ba4
-0 134 #8b8ba4
-0 135 #00634a
-0 136 #7b834a
-0 137 #e6bc7b
-0 138 #8b9b7b
-0 139 #a4b4c5
-0 140 #6b6b93
-0 141 #836b6b
-0 142 #529b4a
-0 143 #d5e6e6
-0 144 #526363
-0 145 #186b4a
-0 146 #9ba4b4
-0 147 #fe9300
-0 148 #fe9300
-0 149 #8b6b6b
-0 150 #00634a
-0 151 #7b834a
-0 152 #63737b
-0 153 #e6bc7b
-0 154 #184a18
-0 155 #8b8ba4
-0 156 #f6bc5a
-0 157 #8b9b6b
-0 158 #d5d5d5
-0 159 #8b8ba4
-0 160 #8b6b6b
-0 161 #8b9b6b
-0 162 #d2d2d2
-0 163 #a9a9a9
-0 164 #8d8da3
-0 165 #f2b85d
-0 166 #88986b
-0 167 #d5d5d5
-0 168 #8b8ba4
-0 169 #d5d5d5
-0 170 #8b8ba4
-0 171 #8b6b6b
-0 172 #8b9b6b
-0 173 #d5d5d5
-0 174 #8b8ba4
-0 175 #8b6b6b
-0 176 #8b9b7b
-0 177 #000000
-0 178 #f63829
-0 179 #000000
-0 180 #fefe52
-0 181 #52794a
-0 182 #63995a
-0 183 #c56142
-0 184 #e66942
-0 185 #fe7952
-0 186 #dddddd
-0 187 #8b8ba4
-0 188 #f6bc5a
-0 189 #8b9b6b
-0 190 #636b9b
-0 191 #f6f6f6
-0 192 #d5d5d5
-0 193 #8b6b6b
-0 194 #d2d2d2
-0 195 #a9a9a9
-0 196 #8d8da3
-0 197 #f2b85d
-0 198 #88986b
-0 199 #d2d2d2
-0 200 #a9a9a9
-0 201 #8d8da3
-0 202 #f2b85d
-0 203 #88986b
-0 204 #d2d2d2
-0 205 #a9a9a9
-0 206 #8d8da3
-0 207 #f2b85d
-0 208 #88986b
-0 209 #d2d2d2
-0 210 #a9a9a9
-0 211 #8d8da3
-0 212 #f2b85d
-0 213 #88986b
-0 214 #d2d2d2
-0 215 #a9a9a9
-0 216 #8d8da3
-0 217 #f2b85d
-0 218 #88986b
-0 219 #d5d5d5
-0 220 #8b8ba4
-0 221 #d2d2d2
-0 222 #a9a9a9
-0 223 #8d8da3
-0 224 #f2b85d
-0 225 #88986b
-0 226 #d2d2d2
-0 227 #a9a9a9
-0 228 #8d8da3
-0 229 #f2b85d
-0 230 #88986b
-0 231 #d2d2d2
-0 232 #a9a9a9
-0 233 #8d8da3
-0 234 #f2b85d
-0 235 #88986b
-0 236 #d2d2d2
-0 237 #a9a9a9
-0 238 #8d8da3
-0 239 #f2b85d
-0 240 #88986b
-0 241 #d5d5d5
-0 242 #8b8ba4
-0 243 #f2edd2
-0 244 #f4ad5d
-0 245 #95cd98
-0 246 #a9a9a9
-0 247 #b4157d
-0 248 #ededed
-0 249 #838383
-0 250 #d5d5d5
-0 251 #8b8ba4
-0 252 #f6bc5a
-0 253 #8b9b6b
-0 254 #636b9b
-0 255 #7b7b7b
-0 256 #005a00
-0 257 #e67373
-0 258 #f6f6f6
-0 259 #dd0000
-0 260 #feca31
-0 261 #29794a
-0 262 #dd2821
-0 263 #2159c5
-0 264 #f7f7f7
-0 265 #ededed
-0 266 #e5e5e5
-0 267 #7b834a
-0 268 #d5d5d5
-0 269 #e6bc7b
-0 270 #8b9b7b
-0 271 #a4b4c5
-0 272 #6b6b93
-0 273 #836b6b
-0 274 #529b4a
-0 275 #d5e6e6
-0 276 #9ba4b4
-0 277 #21835a
-0 278 #8b8ba4
-0 279 #f6bc5a
-0 280 #8b9b6b
-0 281 #636b9b
-0 282 #d5d5d5
-0 283 #8b8ba4
-0 284 #f6bc5a
-0 285 #8b9b6b
-0 286 #8b6b6b
-2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 4500 3000 7125 3000 7125 5625 4500 5625 4500 3000
-2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
-	 6600 4800 6600 3600 5100 3600 5100 4800 6600 4800
-4 0 0 50 -1 4 16 0.0000 4 135 450 5400 4125 DICOM\001
-4 0 0 50 -1 4 14 0.0000 4 135 450 5550 4425 tools\001

BIN
DICOMtools/Resources/Icons/DICOMtools.png


BIN
DICOMtools/Resources/Screenshots/exportDICOM.png


+ 0 - 20
DICOMtools/Resources/Screenshots/importDICOM.fig

@@ -1,20 +0,0 @@
-#FIG 3.2  Produced by xfig version 3.2.6a
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
--2
-1200 2
-2 4 0 4 8 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11250 6150 11250 6150 10950 13200 10950 13200 11250
-2 4 0 4 15 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11625 6150 11625 6150 11325 13200 11325 13200 11625
-2 4 0 4 31 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12000 6150 12000 6150 11700 13200 11700 13200 12000
-2 4 0 4 18 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12375 6150 12375 6150 12075 13200 12075 13200 12375
-2 5 0 1 0 -1 55 -1 -1 0.000 0 0 -1 0 0 5
-	0 /data0/studen/data/blog/pelican/content/images/importDICOM.png
-	 4650 3825 17970 3825 17970 18870 4650 18870 4650 3825

BIN
DICOMtools/Resources/Screenshots/importDICOM.png


+ 0 - 24
DICOMtools/Resources/Screenshots/loadDICOM.fig

@@ -1,24 +0,0 @@
-#FIG 3.2  Produced by xfig version 3.2.6a
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
--2
-1200 2
-2 4 0 4 8 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11250 6150 11250 6150 10950 13200 10950 13200 11250
-2 4 0 4 15 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11625 6150 11625 6150 11325 13200 11325 13200 11625
-2 5 0 1 0 -1 55 -1 -1 0.000 0 0 -1 0 0 5
-	0 /data0/studen/data/blog/pelican/content/images/loadDICOM.png
-	 4650 3825 17970 3825 17970 18870 4650 18870 4650 3825
-2 4 0 4 18 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12675 6150 12675 6150 12375 13200 12375 13200 12675
-2 4 0 4 31 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12300 6150 12300 6150 12000 13200 12000 13200 12300
-2 4 0 4 12 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12000 6150 12000 6150 11700 13200 11700 13200 12000
-2 4 0 4 30 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12975 6150 12975 6150 12675 13200 12675 13200 12975

BIN
DICOMtools/Resources/Screenshots/loadDICOM.png


+ 0 - 452
DICOMtools/exportDicom.py

@@ -1,452 +0,0 @@
-import DICOMLib
-from slicer.ScriptedLoadableModule import *
-import slicerNetwork
-import qt,vtk,ctk,slicer
-import datetime
-import re
-import os
-import slicer.cli
-import json
-
-class exportDicom(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-  def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self, parent)
-        self.className="exportDicom"
-        self.parent.title="exportDicom"
-        self.parent.categories = ["LabKey"]
-        self.parent.dependencies = []
-        self.parent.contributors = ["Andrej Studen (University of Ljubljana)"] # replace with "Firstname Lastname (Organization)"
-        self.parent.helpText = """
-        This is an example of scripted loadable module bundled in an extension.
-        It adds hierarchy datat for reliable dicom export of a node
-        """
-        self.parent.helpText += self.getDefaultModuleDocumentationLink()
-        self.parent.acknowledgementText = """
-        This extension developed within Medical Physics research programe of ARRS
-        """ # replace with organization, grant and thanks.
-
-#
-# dataExplorerWidget
-
-
-
-class exportDicomWidget(ScriptedLoadableModuleWidget):
-  """Uses ScriptedLoadableModuleWidget base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setup(self):
-      ScriptedLoadableModuleWidget.setup(self)
-      self.logic=exportDicomLogic(self)
-
-      try:
-           fhome=os.environ["HOME"]
-      except:
-              #in windows, the variable is called HOMEPATH
-           fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
-
-      cfgPath=os.path.join(fhome,".labkey")
-      cfgNet=os.path.join(cfgPath,"Remote.json")
-
-      self.project='DICOM/Export'
-      
-      baseUUIDFile=os.path.join(cfgPath,"baseUUID.json")
-      baseUUIDCandidate='0.0.0.0.0'
-      try:
-          print("Opening {}".format(baseUUIDFile))
-          f=open(baseUUIDFile,'r')
-          print("Parsing {}".format(baseUUIDFile))
-          baseUUIDCfg=json.load(f)
-          print("Decoding {}".format(baseUUIDCfg))
-          baseUUIDCandidate=baseUUIDCfg['baseUUID']
-          print("baseUUID {}".format(baseUUIDCandidate))
-          self.project=baseUUIDCfg['project']
-          print("project {}".format(self.project))
-          
-      except IOError:
-          pass
-      except JSONDecodeError:
-          pass
-      except KeyError:
-          pass
-          
-      
-      self.Net=slicerNetwork.labkeyURIHandler()
-      self.Net.parseConfig(cfgNet)
-      self.Net.initRemote()
-
-      
-      datasetCollapsibleButton = ctk.ctkCollapsibleButton()
-      datasetCollapsibleButton.text = "Node data"
-      self.layout.addWidget(datasetCollapsibleButton)
-      # Layout within the dummy collapsible button
-      datasetFormLayout = qt.QFormLayout(datasetCollapsibleButton)
-
-      self.volumeNode=qt.QLineEdit("enter name of the volume Node")
-      datasetFormLayout.addRow("volumeNode:",self.volumeNode)
-      self.patientId=qt.QLineEdit("enter PatientID")
-      datasetFormLayout.addRow("PatientId:",self.patientId)
-      self.studyInstanceUid=qt.QLineEdit("enter study id")
-      datasetFormLayout.addRow("StudyInstanceUid:",self.studyInstanceUid)
-      self.studyDescription=qt.QLineEdit("enter study description")
-      datasetFormLayout.addRow("StudyDescription:",self.studyDescription)
-
-      self.addHierarchyButton=qt.QPushButton("Add hierarchy")
-      self.addHierarchyButton.clicked.connect(self.onAddHierarchyButtonClicked)
-      datasetFormLayout.addRow("Volume:",self.addHierarchyButton)
-      
-      self.baseUUIDText=qt.QLineEdit(baseUUIDCandidate)
-      datasetFormLayout.addRow("Base UUID:",self.baseUUIDText)
-      
-       
-
-      self.exportButton=qt.QPushButton("Export")
-      self.exportButton.clicked.connect(self.onExportButtonClicked)
-      datasetFormLayout.addRow("Export:",self.exportButton)
-
-
-
-  def onAddHierarchyButtonClicked(self):
-      metadata={'patientId':self.patientId.text,
-                'studyDescription':self.studyDescription.text,
-                'studyInstanceUid':self.studyInstanceUid.text,
-                'baseUUID':self.baseUUIDText.text}
-      node=slicer.util.getFirstNodeByName(self.volumeNode.text)
-      if node==None:
-          return
-      self.logic.addHierarchy(node,metadata)
-
-  def onExportButtonClicked(self):
-      metadata={'patientId':self.patientId.text,
-                'studyDescription':self.studyDescription.text,
-                'studyInstanceUid':self.studyInstanceUid.text,
-                'seriesInstanceUid':self.logic.generateSeriesUUID('volume',self.baseUUIDText.text),
-                'frameOfReferenceInstanceUid':self.logic.generateFrameOfReferenceUUID('volume',self.baseUUIDText.text)}
-      node=slicer.util.getFirstNodeByName(self.volumeNode.text)
-      if node==None:
-          return
-      self.logic.exportNodeAsDICOM(self.Net,self.project,node,metadata)
-
-
-
-class exportDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
-  def __init__(self,parent):
-       slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic.__init__(self, parent)
-       self.labelUUID={'series':'1','study':'2','instance':'3','frameOfReference':4}
-       self.dataUUID={'volume':'1','segmentation':'2','transformation':'3'}
-
-       try:
-           fhome=os.environ["HOME"]
-       except:
-              #in windows, the variable is called HOMEPATH
-           fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
-
-
-       self.basePath=os.path.join(fhome,'.dicom')
-
-       if not os.path.isdir(self.basePath):
-           os.mkdir(self.basePath)
-
-       self.itemLabel={
-            'patientName': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientNameAttributeName(),
-            'modality': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMSeriesModalityAttributeName(),
-            'patientId': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientIDAttributeName(),
-            'patientSex': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientSexAttributeName(),
-            'patientBirthDate': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientBirthDateAttributeName(),
-            'patientComments': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientCommentsAttributeName(),
-            'studyDescription': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyDescriptionAttributeName(),
-            'studyInstanceUid': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyInstanceUIDTagName(),
-            'studyDate': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyDateAttributeName(),
-            'studyId': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyIDTagName(),
-            'studyTime': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyTimeAttributeName()}
-
-
-
-
-
-
-  def generateStudyUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        date=x.strftime("%Y%m%d")
-        studyFile=os.path.join(self.basePath,'studyCount'+date+'.txt')
-
-        try:
-            f=open(studyFile,"r")
-            id=int(f.readline())
-            id=id+1
-            f.close()
-        except:
-            id=0
-
-        studyId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['study'],
-                        self.dataUUID[type],date,id)
-
-        f=open(studyFile,"w")
-        f.write("{}".format(id))
-        f.close()
-        return studyId
-
-
-
-
-  def generateSOPInstanceUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        date=x.strftime("%Y%m%d")
-        instanceFile=os.path.join(self.basePath,'instanceCount'+date+'.txt')
-
-        try:
-            f=open(instanceFile,"r")
-            id=int(f.readline())
-            id=id+1
-            f.close()
-        except:
-            id=0
-
-        instanceId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['instance'],
-                        self.dataUUID[type],date,id)
-
-        f=open(instanceFile,"w")
-        f.write("{}".format(id))
-        f.close()
-        return instanceId
-
-
-  def generateFrameOfReferenceUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        date=x.strftime("%Y%m%d")
-        forFile=os.path.join(self.basePath,'frameCount'+date+'.txt')
-
-        try:
-            f=open(studyFile,"r")
-            id=int(f.readline())
-            id=id+1
-            f.close()
-        except:
-            id=0
-
-        forId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['frameOfReference'],
-                        self.dataUUID[type],date,id)
-
-        f=open(forFile,"w")
-        f.write("{}".format(id))
-        f.close()
-        return forId
-  
-  def generateSeriesUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        seriesInstanceUid=baseUUID+'.'+self.labelUUID['series']+'.'
-        seriesInstanceUid+=self.dataUUID[type]+'.'+x.strftime("%Y%m%d")+'.'+getTimeCode(x)
-        return seriesInstanceUid
-
-  def setAttribute(self,shn,itemId,label,metadata):
-        try:
-            shn.SetItemAttribute(itemId,self.itemLabel['modality'],metadata['modality'])
-        except KeyError:
-            pass
-
-  def addHierarchy(self,dataNode,metadata):
-        #convert dataNode to fully fledged DICOM object in hierarchy
-
-        #variation of addSeriesInSubjectHierarchy
-        shn=slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
-        sceneItemId=shn.GetSceneItemID()
-
-        #add the series for the data node
-        seriesItemId=shn.CreateItem(sceneItemId,dataNode)
-
-        x=datetime.datetime.now()
-        hour=x.strftime("%H")
-        hour=re.sub('^0','',hour)
-        ft=hour+x.strftime("%M%S")
-        seriesInstanceUid=metadata['baseUUID']+'.'+self.labelUUID['series']+'.'
-        seriesInstanceUid+=self.dataUUID['volume']+'.'+x.strftime("%Y%m%d")+'.'+ft
-        shn.SetItemUID(seriesItemId,slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMUIDName(),
-            seriesInstanceUid)
-
-        self.setAttribute(shn,seriesItemId,'modality',metadata)
-        self.setAttribute(shn,seriesItemId,'seriesNumber',metadata)
-
-        #add PatientId
-        try:
-            patientId=metadata['patientId']
-        except KeyError:
-            patientId='Unknown'
-
-        try:
-            studyInstanceUid=metadata['studyInstanceUid']
-        except KeyError:
-            studyInstanceUid=self.generateStudyUUID('volume',metadata['baseUUID'])
-
-        slicer.vtkSlicerSubjectHierarchyModuleLogic.InsertDicomSeriesInHierarchy(shn,patientId,
-            studyInstanceUid,seriesInstanceUid)
-
-        patientItemId=shn.GetItemByUID(slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMUIDName(),patientId)
-
-        self.setAttribute(shn,patientItemId,'patientName',metadata)
-        self.setAttribute(shn,patientItemId,'patientId',metadata)
-        self.setAttribute(shn,patientItemId,'patientSex',metadata)
-        self.setAttribute(shn,patientItemId,'patientBirthDate',metadata)
-        self.setAttribute(shn,patientItemId,'patientComments',metadata)
-
-        patientItemName=patientId
-        shn.SetItemName(patientItemId,patientItemName)
-
-        studyItemId=shn.GetItemByUID(slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMUIDName(),studyInstanceUid)
-
-        self.setAttribute(shn,studyItemId,'studyDescription',metadata)
-        self.setAttribute(shn,studyItemId,'studyInstanceUid',metadata)
-        self.setAttribute(shn,studyItemId,'studyId',metadata)
-        self.setAttribute(shn,studyItemId,'studyDate',metadata)
-        self.setAttribute(shn,studyItemId,'studyTime',metadata)
-
-        studyItemName=studyInstanceUid
-        shn.SetItemName(studyItemId,studyItemName)
-
-  def setTagValue(self,cliparameters,metadata,field):
-       try:
-           cliparameters[field]=metadata[field]
-       except KeyError:
-           pass
-
-  def setDirectoryValue(self,cliparameters,cliKey,metadata,key):
-       try:
-           cliparameters[cliKey]=metadata[key]
-       except KeyError:
-           pass
-
- 
-
-  def generateDicom(self, volumeNode, metadata, fdir):
-
-       cliparameters={}
-       tagList=['patientName',
-               'patientComments',
-               'studyDate',
-               'studyTime',
-               'studyDescription',
-               'modality',
-               'manufacturer',
-               'model',
-               'seriesDescription',
-               'seriesNumber',
-               'seriesDate',
-               'seriesTime',
-               'contentDate',
-               'contentTime']
-
-       for tag in tagList:
-           self.setTagValue(cliparameters,metadata,tag)
-
-       valuePairs={'patientID':'patientId',
-                    'studyID':'studyId',
-                    'seriesInstanceUID':'seriesInstanceUid',
-                    'studyInstanceUID':'studyInstanceUid',
-                    'frameOfReferenceInstanceUID':'frameOfReferenceInstanceUid'}
-
-       for key in valuePairs:
-           self.setDirectoryValue(cliparameters,key,metadata,valuePairs[key])
-
-
-       cliparameters['dicomDirectory']=fdir
-       try:
-            cliparameters['dicomPrefix']=metadata['fileName']
-       except KeyError:
-            cliparameters['dicomPrefix']='IMG'
-       cliparameters['inputVolume']=volumeNode.GetID()
-
-       print("[CLI]SeriesInstanceUID: {}").format(cliparameters['seriesInstanceUID'])
-       print("[MeD]SeriesInstanceUID: {}").format(metadata['seriesInstanceUid'])
-
-       try:
-           dicomWrite=slicer.modules.createdicomseries
-       except AttributeError:
-           print("Missing dicom exporter")
-           return
-
-       cliNode=slicer.cli.run(dicomWrite,None,cliparameters,wait_for_completion=True)
-       status=cliNode.GetStatusString()
-       print("Status: {}").format(status)
-       if status.find("error")>-1:
-              print("Error: {}").format(cliNode.GetErrorText())
-              return False
-       return True
-
-
-  def exportNodeAsDICOM(self,net, project,volumeNode,metadata):
-
-
-       #buffed up exportable is now ready to be stored
-       fdir=net.GetLocalCacheDirectory()
-       #project=project.replace('/','\\')
-       fdir=os.path.join(fdir,project)
-       fdir=os.path.join(fdir,'%40files')
-       fdir=os.path.join(fdir,metadata['patientId'])
-       #fdirReg=os.path.join(fdir,'Registration')
-
-       if not os.path.isdir(fdir):
-           os.makedirs(fdir)
-       
-       relDir=net.GetRelativePathFromLocalPath(fdir)
-       remoteDir=net.GetLabkeyPathFromRelativePath(relDir)
-
-       if not net.isRemoteDir(remoteDir):
-            net.mkdir(remoteDir)
-
-              
-       dirName=volumeNode.GetName();
-       dirName=dirName.replace(" ","_")
-       fdir=os.path.join(fdir,dirName)
-
-       if not os.path.isdir(fdir):
-           os.mkdir(fdir)
-
-       relDir=net.GetRelativePathFromLocalPath(fdir)
-       remoteDir=net.GetLabkeyPathFromRelativePath(relDir)
-
-       if not net.isRemoteDir(remoteDir):
-            net.mkdir(remoteDir)
-
-       if not self.generateDicom(volumeNode,metadata,fdir):
-           return
-
-       for f in os.listdir(fdir):
-           localPath=os.path.join(fdir,f)
-           print("localPath: {}").format(localPath)
-           relativePath=net.GetRelativePathFromLocalPath(localPath)
-           print("relativePath: {}").format(relativePath)
-           remotePath=net.GetLabkeyPathFromRelativePath(relativePath)
-           print("remotePath: {}").format(relativePath)
-           net.copyLocalFileToRemote(localPath,remotePath)
-
-def getTimeCode(x):
-    hour=x.strftime("%H")
-    hour=re.sub('^0','',hour)
-    return hour+x.strftime("%M%S")
- 
-def generateExportMap():
-    exportMap={}
-    exportMap['patientName']='UNKONWN'
-    exportMap['patientComments']='NONE'
-    exportMap['studyDate']='UNKNOWN'
-    exportMap['studyTime']='UNKNOWN'
-    exportMap['studyDescription']='NONE'
-    exportMap['modality']='UNKNOWN'
-    exportMap['manufacturer']='UNKNOWN'
-    exportMap['model']='UNKNOWN'
-    exportMap['seriesDescription']='NONE'
-    exportMap['seriesNumber']='0'
-    exportMap['seriesDate']='UNKNOWN'
-    exportMap['seriesTime']='UNKNOWN'
-    exportMap['contentDate']='UNKNOWN'
-    exportMap['contentTime']='UNKNOWN'
-    exportMap['patientId']='UNKNOWN'
-    exportMap['studyId']='UNKNOWN'
-    exportMap['seriesInstanceUid']='0.0.0.0'
-    exportMap['studyInstanceUid']='0.0.0.0'
-    exportMap['frameOfReferenceInstanceUid']='0.0.0.0'
-    return exportMap
-

+ 0 - 359
DICOMtools/importDicom.py

@@ -1,359 +0,0 @@
-import dicom
-import vtkInterface as vi
-import os
-import vtk, qt, ctk, slicer
-from slicer.ScriptedLoadableModule import *
-import slicerNetwork
-import json
-import loadDicom
-import DICOMLib
-
-class importDicom(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self, parent)
-        self.className="importDICOM"
-        self.parent.title="importDICOM"
-        self.parent.categories = ["LabKey"]
-        self.parent.dependencies = []
-        self.parent.contributors = ["Andrej Studen (UL/FMF)"] # replace with "Firstname Lastname (Organization)"
-        self.parent.helpText = """
-                utilities for parsing dicom entries
-                """
-        self.parent.acknowledgementText = """
-                Developed within the medical physics research programme of the Slovenian research agency.
-                """ # replace with organization, grant and thanks.
-
-class importDicomWidget(slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget):
-  """Uses ScriptedLoadableModuleWidget base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setup(self):
-      
-    slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget.setup(self)
-    self.logic=importDicomLogic(self)
-    self.network=slicerNetwork.labkeyURIHandler()
-    
-    connectionCollapsibleButton = ctk.ctkCollapsibleButton()
-    connectionCollapsibleButton.text = "Connection"
-    self.layout.addWidget(connectionCollapsibleButton)
-
-    connectionFormLayout = qt.QFormLayout(connectionCollapsibleButton)
-    
-    self.loadConfigButton=qt.QPushButton("Load configuration")
-    self.loadConfigButton.toolTip="Load configuration"
-    self.loadConfigButton.connect('clicked(bool)',self.onLoadConfigButtonClicked)
-    connectionFormLayout.addRow("Connection:",self.loadConfigButton)
-
-    self.DICOMDirectory=qt.QLineEdit("Test/Temp/%40files/TEST/MLEM")
-    connectionFormLayout.addRow("LabKey directory:",self.DICOMDirectory)
-
-
-    #loadDICOMButton=qt.QPushButton("Load")
-    #loadDICOMButton.toolTip="Load DICOM"
-    #loadDICOMButton.clicked.connect(self.onLoadDICOMButtonClicked)
-    #connectionFormLayout.addRow("DICOM:",loadDICOMButton)
-
-    self.DICOMFilter=qt.QLineEdit('{"seriesNumber":"SeriesLabel"}')
-    connectionFormLayout.addRow("Filter(JSON):",self.DICOMFilter)
-
-    loadDICOMFilterButton=qt.QPushButton("Load with filter")
-    loadDICOMFilterButton.toolTip="Load DICOM with filter"
-    loadDICOMFilterButton.clicked.connect(self.onLoadDICOMFilterButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMFilterButton)
-
-  def onLoadConfigButtonClicked(self):
-       filename=qt.QFileDialog.getOpenFileName(None,'Open configuration file (JSON)',
-            os.path.join(os.path.expanduser('~'),'.labkey'), '*.json')
-       self.network.parseConfig(filename)
-       self.network.initRemote()
-       self.loadConfigButton.setText(os.path.basename(filename))
-  
-  def onLoadDICOMFilterButtonClicked(self):
-      filter=json.loads(self.DICOMFilter.text)
-      #print("Filter is {}".format(filter))
-      self.logic.loadVolumes(self.network,self.DICOMDirectory.text,filter)
-    
-  def onLoadDICOMButtonClicked(self):
-      self.logic.load(self.network,self.DICOMDirectory.text)
-       
-
-
-#equivalent of loadable + labkey interface
-class dicomSeries():
-    def __init__(self):
-        self.data = []
-        self.idx = []
-        self.z = []
-        self.pixel_size = [0,0,0]
-        self.lpsOrigin = [0,0,0]
-        self.lpsOrigin[2]=1e30
-        self.lpsOrientation=[0,0,0,0,0,0]
-        self.local=False
-
-
-    def getfile(self,net,relativePath):
-        if self.local:
-                return open(relativePath,'rb')
-        return net.readFileToBuffer(relativePath)
-
-    def addFile(self,f):
-        try:
-            self.files.append(f)
-        except:
-            self.files=[f]
-
-    def setLabel(self,label):
-        self.label=label
-
-    def getLabel(self):
-        try:
-            return self.label
-        except:
-            return None
-
-    def setMetadata(self,key,value):
-        try:
-            self.metadata[key]=value
-        except:
-            self.metadata={key:value}
-
-    def getMetadata(self):
-        try:
-            return self.metadata
-        except:
-            return {}
-
-            
-
-    def load(self,net):
-
-        for f in self.files:
-            print '{}:'.format(f)
-            fileBuffer=self.getfile(net,f)
-            self.loadFile(fileBuffer)
-
-        nz=len(self.idx)
-        sh=self.data[-1].shape
-        sh_list=list(sh)
-        sh_list.append(nz)
-        data_array=np.zeros(sh_list)
-
-        for k in range(0,nz):
-            kp=int(np.round((self.z[k]-self.center[2])/self.pixel_size[2]))
-            data_array[:,:,kp]=np.transpose(self.data[k])
-
-        try:
-            nodeName='Series'+self.label
-        except:
-            print('Could not set series label')
-            nodeName='UnknownSeries'
-
-        newNode=slicer.vtkMRMLScalarVolumeNode()
-        newNode.SetName(nodeName)
-
-        ijkToRAS = vtk.vtkMatrix4x4()
-        #think how to do this with image orientation
-
-        rasOrientation=[-self.lpsOrientation[i] if (i%3 < 2) else self.lpsOrientation[i]
-          for i in range(0,len(self.lpsOrientation))]
-        rasOrigin=[-self.lpsOrigin[i] if (i%3<2) else self.lpsOrigin[i] for i in range(0,len(self.lpsOrigin))]
-
-        for i in range(0,3):
-             for j in range(0,3):
-                 ijkToRAS.SetElement(i,j,self.pixel_size[i]*rasOrientation[3*j+i])
-
-             ijkToRAS.SetElement(i,3,rasOrigin[i])
-
-        newNode.SetIJKToRASMatrix(ijkToRAS)
-
-        v=vtk.vtkImageData()
-        v.GetPointData().SetScalars(
-            vtk.util.numpy_support.numpy_to_vtk(
-                np.ravel(self.data,order='F'),deep=True, array_type=vtk.VTK_FLOAT))
-        v.SetOrigin(0,0,0)
-        v.SetSpacing(1,1,1)
-        v.SetDimensions(self.data.shape)
-
-        newNode.SetAndObserveImageData(v)
-        slicer.mrmlScene.AddNode(newNode)
-        volume={'node':newNode,'metadata':self.metadata}
-        return volume
-
-    def loadFile(self,fileBuffer):
-
-        plan=dicom.read_file(fileBuffer)
-
-        self.data.append(plan.pixel_array)
-        self.idx.append(plan.InstanceNumber)
-        self.z.append(plan.ImagePositionPatient[2])
-
-
-        #pixelSize
-        pixel_size=[plan.PixelSpacing[0],plan.PixelSpacing[1],
-                    plan.SliceThickness]
-
-        for i in range(0,3):
-            if self.pixel_size[i] == 0:
-                self.pixel_size[i] = float(pixel_size[i])
-            if abs(self.pixel_size[i]-pixel_size[i]) > 1e-3:
-                print 'Pixel size mismatch {.2f}/{.2f}'.format(self.pixel_size[i],
-                        pixel_size[i])
-
-        #origin
-        for i in range(0,2):
-            if self.lpsOrigin[i] == 0:
-                self.lpsOrigin[i] = float(plan.ImagePositionPatient[i])
-            if abs(self.lpsOrigin[i]-plan.ImagePositionPatient[i]) > 1e-3:
-                print 'Image center mismatch {.2f}/{.2f}'.format(self.lpsOrigin[i],
-                    plan.ImagePositionPatient[i])
-        #not average, but minimum (!) why??
-
-        if plan.ImagePositionPatient[2]<self.lpsOrigin[2]:
-            self.lpsOrigin[2]=plan.ImagePositionPatient[2]
-
-
-        #orientation
-        for i in range(0,6):
-            if self.lpsOrientation[i] == 0:
-                self.lpsOrientation[i] = float(plan.ImageOrientationPatient[i])
-            if abs(self.lpsOrientation[i]-plan.ImageOrientationPatient[i]) > 1e-3:
-                print 'Image orientation mismatch {0:.2f}/{1:.2f}'.format(self.lpsOrientation[i],
-                        plan.ImageOrientationPatient[i])
-
-        return True
-
-class importDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic.__init__(self, parent)
-        self.local=False
-        self.tag={
-        'studyInstanceUid':0x0020000d,
-        'seriesInstanceUid':0x0020000e,
-        'patientId':0x00100020,
-        'patientName':0x00100010,
-        'sequenceName':0x00180024,
-        'seriesNumber':0x00200011,
-        'percentPhaseFieldOfView':0x00180094,
-        'modality': 0x00080060,
-        'patientSex': 0x00100040,
-        'patientBirthDate': 0x00100030,
-        'patientComments': 0x00104000,
-        'studyDescription': 0x00081030,
-        'studyDate': 0x00080020,
-        'studyId': 0x00200010,
-        'studyTime': 0x00080030,
-        'frameOfReferenceInstanceUid':0x00200052}
-    
-
-
-    def setLocal(self, basePath):
-        self.local=True
-        self.basePath=basePath
-
-        
-    def loadVolumes(self,net,directory,filter):
-        #mimic examineForImport
-        seriesList=self.examineForImport(net,directory,filter)
-        print("Got {} series").format(len(seriesList))
-        volumes=[]
-
-        for s in seriesList:
-            try:
-                volumes.append(s.load(net))
-                #often fails, e.g. JPEGLossles
-            except:
-                loadable=DICOMLib.DICOMLoadable()
-                loadable.name='Series'+str(s.getLabel())
-                print("Loading for {} number of files (pre-load) {}").format(loadable.name,len(s.files))
-                loadable.files=[net.DownloadFileToCache(f) for f in s.files]
-                print("Loading for {} number of files (pre-sort) {}").format(loadable.name,len(loadable.files))
-
-                loadable.files,distances,loadable.warning=DICOMLib.DICOMUtils.getSortedImageFiles(loadable.files,1e-3)
-
-                print("Loading for {} number of files {}").format(loadable.name,len(loadable.files))
-                try:
-                    volumeNode=self.volumePlugin.load(loadable)
-                except:
-                    self.volumePlugin=slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
-                    volumeNode=self.volumePlugin.load(loadable)
-                volume={'node':volumeNode,'metadata':s.getMetadata()}
-                volumes.append(volume)
-
-
-        return volumes
-
-
-    def listdir(self,net,relativeDirectory):
-        if self.local:
-            dirs=os.listdir(os.path.join(self.basePath,relativeDirectory))
-            return [os.path.join(relativeDirectory,dir) for dir in dirs]
-        return net.listRelativeDir(relativeDirectory)
-
-    def getfile(self,net,relativePath):
-        if self.local:
-            return open(os.path.join(self.basePath,relativePath),'rb')
-        return net.readFileToBuffer(relativePath)
-
-    def examineForImport(self,net,directory,filter):
-        #split by series
-        seriesList=[]
-
-        files=self.listdir(net,directory)
-        if len(files)==0:
-            print("No input found in {}".format(directory))
-            return seriesList
-
-
-        for f in files:
-            fileBuffer=self.getfile(net,f)
-
-            #validate
-            try:
-                plan = dicom.read_file(fileBuffer)
-            except:
-                print ("{}: Not a dicom file")
-                continue
-
-            #determine validity first
-            fileValid=True
-            for key in filter:
-                if filter[key]==None:
-                    continue
-                if filter[key]=='SeriesLabel':
-                    seriesTag=self.tag[key]
-                    continue
-
-                v=plan[self.tag[key]].value
-                if not v==filter[key]:
-                    print('Filter mismatch {}{:x}: {}/{}').format(key,self.tag[key],v,filter[key])
-                    fileValid=False
-
-            if not fileValid:
-                continue
-
-            #determine serieslabel second
-            seriesLabel=plan[seriesTag].value
-                
-            try:
-                if series.getLabel()==seriesLabel:
-                    series.addFile(f)
-                    continue
-            except NameError:
-                pass
-
-            #add new series
-            seriesList.append(dicomSeries())
-            series=seriesList[-1]
-            series.local=self.local
-
-            #set series parameters
-            series.addFile(f)
-            series.setLabel(seriesLabel)
-            for key in filter:
-                if not filter[key]==None:
-                    continue
-                v=plan[self.tag[key]].value
-                series.setMetadata(key,v)
-
-        return seriesList

+ 0 - 528
DICOMtools/loadDicom.py

@@ -1,528 +0,0 @@
-import slicer
-import os
-import subprocess
-import re
-import slicerNetwork
-import ctk,qt
-import json
-
-dicomModify=os.getenv("HOME")
-if not dicomModify==None:
-    dicomModify+="/software/install/"
-    dicomModify+="dicomModify/bin/dicomModify"
-
-class loadDicom(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self, parent)
-        self.className="loadDicom"
-        self.parent.title="loadDicom"
-        self.parent.categories = ["LabKey"]
-        self.parent.dependencies = []
-        self.parent.contributors = ["Andrej Studen (UL/FMF)"] # replace with "Firstname Lastname (Organization)"
-        self.parent.helpText = """
-            utilities for parsing dicom entries
-            """
-        self.parent.acknowledgementText = """
-            Developed within the medical physics research programme of the Slovenian research agency.
-            """ # replace with organization, grant and thanks.
-
-class loadDicomWidget(slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget):
-  """Uses ScriptedLoadableModuleWidget base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setup(self):
-    slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget.setup(self)
-    self.logic=loadDicomLogic(self)
-    self.network=slicerNetwork.labkeyURIHandler()
-    
-    connectionCollapsibleButton = ctk.ctkCollapsibleButton()
-    connectionCollapsibleButton.text = "Connection"
-    self.layout.addWidget(connectionCollapsibleButton)
-
-    connectionFormLayout = qt.QFormLayout(connectionCollapsibleButton)
-    
-    self.loadConfigButton=qt.QPushButton("Load configuration")
-    self.loadConfigButton.toolTip="Load configuration"
-    self.loadConfigButton.connect('clicked(bool)',self.onLoadConfigButtonClicked)
-    connectionFormLayout.addRow("Connection:",self.loadConfigButton)
-
-    self.DICOMDirectory=qt.QLineEdit("Test/Temp/%40files/TEST/MLEM")
-    connectionFormLayout.addRow("LabKey directory:",self.DICOMDirectory)
-
-
-    loadDICOMButton=qt.QPushButton("Load")
-    loadDICOMButton.toolTip="Load DICOM"
-    loadDICOMButton.clicked.connect(self.onLoadDICOMButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMButton)
-
-    self.DICOMFilter=qt.QLineEdit('{"seriesNumber":"SeriesLabel"}')
-    connectionFormLayout.addRow("Filter(JSON):",self.DICOMFilter)
-
-    loadDICOMFilterButton=qt.QPushButton("Load with filter")
-    loadDICOMFilterButton.toolTip="Load DICOM with filter"
-    loadDICOMFilterButton.clicked.connect(self.onLoadDICOMFilterButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMFilterButton)
-
-    loadDICOMSegmentationFilterButton=qt.QPushButton("Load segmentation with filter")
-    loadDICOMSegmentationFilterButton.toolTip="Load DICOM (RT contour) with filter"
-    loadDICOMSegmentationFilterButton.clicked.connect(self.onLoadDICOMSegmentationFilterButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMSegmentationFilterButton)
-
-
-  def onLoadConfigButtonClicked(self):
-       filename=qt.QFileDialog.getOpenFileName(None,'Open configuration file (JSON)',
-            os.path.join(os.path.expanduser('~'),'.labkey'), '*.json')
-       self.network.parseConfig(filename)
-       self.network.initRemote()
-       self.loadConfigButton.setText(os.path.basename(filename))
-  
-  def onLoadDICOMFilterButtonClicked(self):
-      filter=json.loads(self.DICOMFilter.text)
-      #print("Filter is {}".format(filter))
-      self.logic.loadVolumes(self.network,self.DICOMDirectory.text,filter)
-    
-  def onLoadDICOMSegmentationFilterButtonClicked(self):
-      filter=json.loads(self.DICOMFilter.text)
-      #print("Filter is {}".format(filter))
-      self.logic.loadSegmentations(self.network,self.DICOMDirectory.text,filter)
-  
-  def onLoadDICOMButtonClicked(self):
-      self.logic.load(self.network,self.DICOMDirectory.text)
-       
-
-class loadDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.\
-                ScriptedLoadableModuleLogic.__init__(self, parent)
-
-        self.tag={
-              'sopInstanceUid' : {'tag':"0008,0018",'VR':'UI'},
-              'studyDate': {'tag':"0008,0020",'VR':'DA'},
-              'studyTime': {'tag':"0008,0030",'VR':'TM'},
-              'seriesTime': {'tag':"0008,0031",'VR':'TM'},
-              'acquisitionTime':{'tag':"0008,0032",'VR':'TM'},
-              'modality': {'tag':"0008,0060",'VR':'CS'},
-              'presentationIntentType': {'tag':"0008,0068",'VR':'CS'},
-              'manufacturer': {'tag':"0008,0070",'VR':'LO'},
-              'institutionName': {'tag':"0008,0080",'VR':'LO'},
-              'studyDescription': {'tag':"0008,1030",'VR':'LO'},
-              'seriesDescription': {'tag':"0008,103e",'VR':'LO'},
-              'manufacturerModelName': {'tag':"0008,1090",'VR':'LO'},
-              'patientName': {'tag':"0010,0010",'VR':'PN'},
-              'patientId': {'tag':"0010,0020",'VR':'LO'},
-              'patientBirthDate': {'tag':"0010,0030",'VR':'DA'},
-              'patientSex': {'tag':"0010,0040",'VR':'CS'},
-              'patientAge': {'tag':"0010,1010",'VR':'AS'},
-              'patientComments': {'tag':"0010,4000",'VR':'LT'},
-              'sequenceName': {'tag':"0018,0024",'VR':'SH'},
-              'kVP': {'tag':"0018,0060",'VR':'DS'},
-              'percentPhaseFieldOfView': {'tag':"0018,0094",'VR':'DS'},
-              'xRayTubeCurrent': {'tag':"0018,1151",'VR':'IS'},
-              'exposure': {'tag':"0018,1152",'VR':'IS'},
-              'imagerPixelSpacing': {'tag':"0018,1164",'VR':'DS'},
-              'anodeTargetMaterial':{'tag':"0018,1191",'VR':'CS'},
-              'bodyPartThickness': {'tag':"0018,11a0",'VR':'DS'},
-              'compressionForce': {'tag':"0018,11a2",'VR':'DS'},
-              'viewPosition': {'tag':"0018,5101",'VR':'CS'},
-              'fieldOfViewHorizontalFlip': {'tag':"0018,7034",'VR':'CS'},
-              'filterMaterial':{'tag':"0018,7050",'VR':'CS'},
-              'studyInstanceUid': {'tag':"0020,000d",'VR':'UI'},
-              'seriesInstanceUid': {'tag':"0020,000e",'VR':'UI'},
-              'studyId': {'tag':"0020,0010",'VR':'SH'},
-              'seriesNumber': {'tag':"0020,0011",'VR':'IS'},
-              'instanceNumber': {'tag':"0020,0013",'VR':'IS'},
-              'frameOfReferenceInstanceUid': {'tag':"0020,0052",'seqTag':"3006,0010",'VR':'UI'},
-              'imageLaterality': {'tag':"0020,0062",'VR':'CS'},
-              'imagesInAcquisition': {'tag':"0020,1002",'VR':'IS'},
-              'photometricInterpretation': {'tag':"0028,0004",'VR':'CS'},
-              'organDose':{'tag':"0040,0316",'VR':'DS'},
-              'entranceDoseInmGy':{'tag':"0040,8302",'VR':'DS'},
-              'reconstructionMethod': {'tag':"0054,1103",'VR':'LO'}
-        }
-        self.tagPyDicom={
-              'studyDate': 0x00080020,
-              'studyTime': 0x00080030,
-              'modality': 0x00080060,
-              'presentationIntentType': 0x00080068,
-              'manufacturer': 0x00080070,
-              'studyDescription': 0x00081030,
-              'seriesDescription': 0x0008103e,
-              'patientName': 0x00100010,
-              'patientId': 0x00100020,
-              'patientBirthDate': 0x00100030,
-              'patientSex': 0x00100040,
-              'patientComments': 0x00104000,
-              'sequenceName': 0x00180024,
-              'kVP': 0x00180060,
-              'percentPhaseFieldOfView': 0x00180094,
-              'xRayTubeCurrent': 0x00181151,
-              'exposure': 0x00181152,
-              'imagerPixelSpacing': 0x00181164,
-              'bodyPartThickness': 0x001811a0,
-              'compressionForce': 0x001811a2,
-              'viewPosition': 0x00185101,
-              'studyInstanceUid': 0x0020000d,
-              'seriesInstanceUid': 0x0020000e,
-              'studyId': 0x00200010,
-              'seriesNumber': 0x00200011,
-              'instanceNumber': 0x00200013,
-              'frameOfReferenceInstanceUid': 0x00200052
-              }
-        self.local=False
-        self.useDicomModify=False
-
-    def enableDicomModify(self):
-        self.useDicomModify=True
-
-    def setLocal(self,basePath):
-        self.local=True
-        self.basePath=basePath
-        
-
-    def getHex(self,key):
-        #convert string to hex key;
-        fv=key.split(",")
-        return int(fv[0],16)*0x10000+int(fv[1],16)
-
-    def load(self,sNet,dir,doRemove=True):
-        #load directory using DICOMLib tools
-
-        print("Loading dir {}").format(dir)
-        dicomFiles=self.listdir(sNet,dir)
-        
-        filelist=[]
-        for f in dicomFiles:
-                localPath=self.getfile(sNet,f)
-                filelist.append(localPath)
-                if not self.useDicomModify:
-                    continue
-                if dicomModify==None:
-                    continue
-                f0=localPath
-                f1=f0+"1"
-                try:
-                   subprocess.call(\
-                           dicomModify+" "+f0+" "+f1+" && mv "+f1+" "+f0+";", 
-                           shell=True)
-                except OSError:
-                   print("dicomModify failed")
-
-        try:
-            loadables=self.volumePlugin.examineForImport([filelist])
-        except AttributeError:
-            self.volumePlugin=slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
-            loadables=self.volumePlugin.examineForImport([filelist])
-
-
-        for loadable in loadables:
-            #check if it makes sense to load a particular loadable
-            
-            if loadable.name.find('imageOrientationPatient')>-1:
-                continue
-            filter={}
-            filter['seriesNumber']=None 
-            metadata={}
-            if not self.applyFilter(loadable,filter,metadata):
-                continue
-            volumeNode=self.volumePlugin.load(loadable)
-            if volumeNode != None:
-                vName='Series'+metadata['seriesNumber']
-                volumeNode.SetName(vName)
-
-        try:
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-        except:
-            self.RTPlugin=plugin=slicer.modules.dicomPlugins['DicomRtImportExportPlugin']()
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-
-        for loadable in loadableRTs:
-            segmentationNode=self.RTPlugin.load(loadable)
-           
-        if not doRemove:
-            return
-
-        for f in filelist:
-            self.removeLocal(f)
-
-    def applyFilter(self,loadable,filter,nodeMetadata):
-        #apply filter to loadable.file[0]. Return true if file matches prescribed filter and
-        #false otherwise
-
-        #filter is a directory with keys equal to pre-specified values listed above
-        #if value associated to key equals None, that value gets set in nodeMetadata
-        #if value is set, a match is attempted and result reported in return value
-        #all filters should match for true output
-
-        return self.applyFilterFile(loadable.files[0],filter,nodeMetadata)
-    
-    def applyFilterFile(self,file,filter,nodeMetadata,shell=False,debug=False):
-        #apply filter to file. Return true if file matches prescribed filter and
-        #false otherwise
-
-        #filter is a directory with keys equal to pre-specified values listed above
-        #if value associated to key equals None, that value gets set in nodeMetadata
-        #if value is set, a match is attempted and result reported in return value
-        #all filters should match for true output
-
-        filterOK=True
-        
-        for key in filter:
-            try:
-                fileValue=dicomValue(file,self.tag[key]['tag'],self.tag[key]['seqTag'],shell=shell)
-            except KeyError:
-                fileValue=dicomValue(file,self.tag[key]['tag'],shell=shell)
-
-
-            if filter[key]=="SeriesLabel":
-                nodeMetadata['seriesLabel']=fileValue
-                continue
-
-            if not filter[key]==None:
-                if not fileValue==filter[key]:
-                    if debug:
-                        print("File {} failed for tag {}: {}/{}").format(\
-                            file,key,fileValue,filter[key])
-                    filterOK=False
-                    break
-
-            nodeMetadata[key]=fileValue
-
-
-        return filterOK
-
-    def listdir(self,sNet,dir):
-        #list remote directory
-        if self.local:
-            dir1=os.path.join(self.basePath,dir)
-            dirs=os.listdir(dir1)
-            return [os.path.join(dir1,f) for f in dirs]
-        return sNet.listRelativeDir(dir)
-
-    def getfile(self,sNet,file):
-        #get remote file
-        if self.local:
-            return file
-        return sNet.DownloadFileToCache(file)
-
-    def removeLocal(self,localFile):
-        if self.local:
-            return
-        os.remove(localFile)
-        
-
-    def loadVolumes(self,sNet,dir,filter,doRemove=True):
-#returns all series from the directory, each as a separate node in a node list
-#filter is a dictionary of speciifed dicom values, 
-#if filter(key)=None, that value
-#get set, if it isn't, the file gets checked for a match
-
-        print("Loading dir {}").format(dir)
-        dicomFiles=self.listdir(sNet,dir)
-        #filelist=[os.path.join(dir,f) for f in os.listdir(dir)]
-        filelist=[]
-        for f in dicomFiles:
-            localPath=self.getfile(sNet,f)
-            filelist.append(localPath)
-            if not self.useDicomModify:
-                continue
-            if dicomModify==None:
-                continue
-
-            f0=localPath
-            f1=f0+"1"
-            try:
-                cmd=dicomModify+" "+f0+" "+f1+" && mv "+f1+" "+f0+";"
-                subprocess.call(cmd, shell=False)
-            except OSError:
-                print("dicomModify failed")
-
-        try:
-            loadables=self.volumePlugin.examineForImport([filelist])
-        except AttributeError:
-            self.volumePlugin=\
-                    slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
-            loadables=self.volumePlugin.examineForImport([filelist])
-
-
-        volumeNodes=[]
-        print("Number of loadables:{}").format(len(loadables))
-        for loadable in loadables:
-            #TODO check if it makes sense to load a particular loadable
-
-            print "{}: Checking number of files: {}".format(\
-                    loadable.name,len(loadable.files))
-            
-            #perform checks
-            fileMetadata={}
-            loadable.files[:]=[f for f in loadable.files \
-                    if self.applyFilterFile(f,filter,fileMetadata)]
-            
-            if len(loadable.files)<1:
-                #skip this loadable
-                continue
-
-            print "{}: Final number of files: {}".format(\
-                    loadable.name,len(loadable.files))
-            
-            nodeMetadata={}
-            self.applyFilterFile(loadable.files[0],filter,nodeMetadata)
-
-
-
-            volumeNode=self.volumePlugin.load(loadable,"DCMTK")
-            if volumeNode != None:
-                vName='Series'+nodeMetadata['seriesLabel']
-                volumeNode.SetName(vName)
-                volume={'node':volumeNode,'metadata':nodeMetadata}
-                volumeNodes.append(volume)
-
-        self.volumePlugin.loadableCache.clear()
-
-        if self.local:
-            return volumeNodes
-
-        if doRemove:
-            for f in filelist:
-                self.removeLocal(f)
-
-        return volumeNodes
-
-    def loadSegmentations(self,net,dir,filter,doRemove=True):
-
-        print("Loading dir {}").format(dir)
-        dicomFiles=self.listdir(net,dir)
-        filelist=[self.getfile(net,f) for f in dicomFiles]
-        segmentationNodes=[]
-
-        try:
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-        except:
-            self.RTPlugin=plugin=slicer.modules.dicomPlugins['DicomRtImportExportPlugin']()
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-
-        for loadable in loadableRTs:
-
-            nodeMetadata={}
-            filterOK=self.applyFilter(loadable,filter,nodeMetadata)
-
-            if not filterOK:
-                continue
-
-            success=self.RTPlugin.load(loadable)
-
-            if not success:
-                print("Could not load RT structure set")
-                return
-
-            segNodes=slicer.util.getNodesByClass("vtkMRMLSegmentationNode")
-            segmentationNode=segNodes[0]
-            #assume we loaded the first node in list
-
-            if segmentationNode != None:
-                sName='Segmentation'+nodeMetadata['seriesLabel']
-                segmentationNode.SetName(sName)
-                segmentation={'node':segmentationNode,'metadata':nodeMetadata}
-                segmentationNodes.append(segmentation)
-
-        if not doRemove:
-            return segmentationNodes
-        
-        for f in filelist:
-            self.removeLocal(f)
-
-        return segmentationNodes
-
-def isDicom(file):
-    #check if file is a dicom file
-    try:
-        f=open(file,'rb')
-    except IOError:
-        return False
-
-    f.read(128)
-    dt=f.read(4)
-    f.close()
-    return dt=='DICM'
-
-
-def dicomValue(fileName,tag,seqTag=None,shell=False):
-    #query dicom value of file using dcmdump (DCMTK routine)
-
-    #shell must be false for *nix
-    if os.name=="posix":
-        shell=False
-
-    debug=False
-    dcmdump=os.path.join(os.environ['SLICER_HOME'],"bin","dcmdump")
-    
-    try:
-        if debug:
-            print("Calling {}".format(dcmdump))
-        out=subprocess.check_output([dcmdump,'+p','+P',tag,fileName],shell=shell)
-        if debug:
-            print("Got {}".format(out))
-    except subprocess.CalledProcessError as e:
-        return None
-    
-    
-    if debug:
-        print("Tag {} Line '{}'").format(tag,out)
-    if len(out)==0:
-        return out
-
-    #parse multi-match outputs which appear as several lines
-    lst=out.split('\n')
-    return getTagValue(lst,tag,seqTag)
-    
-def getTagValue(lst,tag,seqTag=None):
-    #report tag value from a list lst of lines reported by dcmdump        
-    
-    debug=False
-    
-    #parse output
-    longTag="^\({}\)".format(tag)
-    #combine sequence and actual tags to long tags
-    if not seqTag==None:
-        if debug:
-            print("Tag:{} seqTag:{}").format(tag,seqTag)
-        longTag="^\({}\).\({}\)".format(seqTag,tag)
-    
-    #pick the values
-    pattern=r'^.*\[(.*)\].*$'
-    
-    #extract tag values
-    rpl=[re.sub(pattern,r'\1',f) for f in lst]
-    
-    #logical whether the line can be matched to typical dcmdump output
-    mtchPattern=[re.match(pattern,f) for f in lst]
-    #find matching tags
-    mtchTag=[re.match(longTag,f) for f in lst]
-    
-    #weed out non-matching lines and lines not matching longTag
-    mtch=[None if x==None or y==None else x \
-            for x,y in zip(mtchTag,mtchPattern)]
-    #set values 
-    out=[x for y,x in zip(mtch,rpl) if not y==None]
-    if len(out)==0:
-        return ''
-    #return first match
-    out=out[0]
-    
-    if debug:
-        print("Tag {} Parsed value {}").format(tag,out)
-    #split output to lists if values are DICOM lists
-    if out.find('\\')>-1:
-        out=out.split('\\')
-
-    return out
-        
-
-def clearNodes():
-    nodes=[]
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLScalarVolumeNode"))
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLScalarVolumeDisplayNode"))
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLSegmentationNode"))
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLSegmentationDisplayNode"))
-    for node in nodes:
-        slicer.mrmlScene.RemoveNode(node)

+ 0 - 111
DICOMtools/vtkInterface.py

@@ -1,111 +0,0 @@
-import vtk, qt, ctk, slicer
-import numpy as np
-import SimpleITK as sitk
-
-#set of routines to transform images from one form to another, most notably
-#numpy to vtk to itk and all possible combinations inbetween. Keep track of
-#orientation, origin and spacing between transforms
-
-class vtkInterface:
-  def __init__(self, parent):
-    #parent.title = "vtk Interface"
-    #parent.categories = ["LabKey"]
-    parent.dependencies = []
-    parent.title ="vtkInterface"
-    parent.contributors = ["Andrej Studen (FMF/JSI)"] # replace with "Firstname Lastname (Org)"
-    parent.helpText = """
-    Convert native numpy data structures to vtk
-    """
-    parent.acknowledgementText = """
-    This module was developed within the frame of the ARRS sponsored medical
-    physics research programe to investigate quantitative measurements of cardiac
-    function using sestamibi-like tracers
-    """ # replace with organization, grant and thanks.
-    self.parent = parent
-
-
-def numpyToVTK(numpy_array, shape, data_type=vtk.VTK_FLOAT):
-    v=vtk.vtkImageData()
-    v.GetPointData().SetScalars(
-        vtk.util.numpy_support.numpy_to_vtk(
-            np.ravel(numpy_array,order='F'),deep=True, array_type=data_type))
-    v.SetOrigin(0,0,0)
-    v.SetSpacing(1,1,1)
-    v.SetDimensions(shape)
-    return v
-
-
-def completeOrientation(orientation):
-    o=orientation
-    o.append(o[1]*o[5]-o[2]*o[4])#0,3
-    o.append(o[2]*o[3]-o[0]*o[5])#1,4
-    o.append(o[0]*o[4]-o[1]*o[3])#2,5
-    return o
-
-
-def ITK2VTK(img):
-    #convert itk to vtk format.
-    #get the array
-    data=sitk.GetArrayFromImage(img)
-    #reverse the shape (don't ask, look at vtk manual if really curios)
-    shape=list(reversed(data.shape))
-    return numpyToVTK(data.ravel(),shape)
-
-def VTK2ITK(v):
-    #convert vtk image to sitk image
-    #convert to numpy first and then go to sitk
-    scalars=v.GetPointData().GetScalars()
-    shape=v.GetDimensions()
-    data=vtk.util.numpy_support.vtk_to_numpy(scalars)
-    #now convert to sitk (notice the little reversal of the shape)
-    return sitk.GetImageFromArray(np.reshape(data,list(reversed(shape))))
-
-def ITKfromNode(nodeName):
-    #use node as data source and generate an itk image
-    node=slicer.mrmlScene.GetFirstNodeByName(nodeName)
-    if node==None:
-        print "Node {0} not available".format(nodeName)
-        return
-
-    img=VTK2ITK(node.GetImageData())
-
-    img.SetOrigin(node.GetOrigin())
-    img.SetSpacing(node.GetSpacing())
-    m=vtk.vtkMatrix4x4()
-    node.GetIJKToRASDirectionMatrix(m)
-    orientation=[0]*9
-    for i in range(0,3):
-        for j in range (0,3):
-            orientation[3*j+i]=m.GetElement(i,j)
-    img.SetDirection(orientation)
-    return img
-
-
-
-def ITKtoNode(img,nodeName):
-    #display itk image and assign it a volume node
-    #useful for displaying outcomes of itk calculations
-    node=slicer.mrmlScene.GetFirstNodeByName(nodeName)
-    if node==None:
-        node=slicer.vtkMRMLScalarVolumeNode()
-        node.SetName(nodeName)
-        slicer.mrmlScene.AddNode(node)
-
-    node.SetAndObserveImageData(ITK2VTK(img))
-
-    #hairy - keep orientation, spacing and origin from node and pass it to itk
-    #for future reference
-    spacing=img.GetSpacing()
-    orientation=img.GetDirection()
-    origin=img.GetOrigin()
-
-    #we should get orientation, spacing and origin from somewhere
-    ijkToRAS = vtk.vtkMatrix4x4()
-    
-    for i in range(0,3):
-       for j in range(0,3):
-           ijkToRAS.SetElement(i,j,spacing[i]*orientation[3*j+i])
-
-       ijkToRAS.SetElement(i,3,origin[i])
-
-    node.SetIJKToRASMatrix(ijkToRAS)

+ 0 - 297
labkeyBrowser/fileIO.py

@@ -1,297 +0,0 @@
-import slicerNetwork
-import slicer
-import qt
-import ctk
-import json
-import os
-import shutil
-
-class fileIO(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self, parent)
-        self.className="fileIO"
-        self.parent.title="fileIO"
-
-        self.parent.categories = ["LabKey"]
-        self.parent.dependencies = []
-        self.parent.contributors = ["Andrej Studen (UL/FMF)"] # replace with "Firstname Lastname (Organization)"
-        self.parent.helpText = """
-                    File IO for Labkey interface to slicer
-                                """
-        self.parent.acknowledgementText = """
-            Developed within the medical physics research programme of the Slovenian research agency.
-                """ # replace with organization, grant and thanks.
-
-class remoteFileSelector(qt.QMainWindow):
-    def __init__(self, parent=None):
-        super(remoteFileSelector, self).__init__(parent)
-        self.setup()
-
-
-    def setMaster(self,master):
-        self.master=master
-
-    def setup(self):
-        centralWidget=qt.QWidget(self)
-        fileDialogFormLayout = qt.QFormLayout(centralWidget)
-        #self.layout.addWidget(fileDialogFormLayout)
-
-        #add item list for each found file/directory
-        self.fileList=qt.QListWidget()
-        self.fileList.toolTip="Select remote file"
-        self.fileList.itemDoubleClicked.connect(self.onFileListDoubleClicked)
-        self.currentRelativeDir=''
-
-        #add dummy entry
-        items=('.','..')
-        self.populateFileList(items)
-
-        fileDialogFormLayout.addWidget(self.fileList)
-
-        self.selectedPath=qt.QLineEdit("")
-        self.selectedPath.toolTip="Selected path"
-
-        fileDialogFormLayout.addRow("Selected path :",self.selectedPath)
-
-        self.closeButton=qt.QPushButton("Close")
-        self.closeButton.toolTip="Close"
-        self.closeButton.connect('clicked(bool)',self.onCloseButtonClicked)
-        fileDialogFormLayout.addRow(self.closeButton)
-        self.setCentralWidget(centralWidget);
-
-    def onFileListDoubleClicked(self,item):
-        if item == None:
-            print("Selected items: None")
-            return
-
-        iText=item.text()
-        print ("Selected items: {0} ").format(iText)
-
-
-        #this is hard -> compose path string from currentRelativeDir and selection
-        if item.text().find('..')==0:
-            #one up
-            idx=self.currentRelativeDir.rfind('/')
-            if idx<0:
-                self.currentRelativeDir=''
-            else:
-                self.currentRelativeDir=self.currentRelativeDir[:idx]
-        elif item.text().find('.')==0:
-            pass
-        else:
-            if len(self.currentRelativeDir)>0:
-                self.currentRelativeDir+='/'
-            self.currentRelativeDir+=item.text()
-
-        print ("Listing {0}").format(self.currentRelativeDir)
-        flist=self.master.network.toRelativePath(
-            self.master.network.listRelativeDir(self.currentRelativeDir))
-        print ("Got")
-        print (flist)
-        flist.insert(0,'..')
-        flist.insert(0,'.')
-        self.populateFileList(flist)
-        self.selectedPath.setText(self.currentRelativeDir)
-        self.master.remotePath.setText(self.master.network.GetLabkeyPathFromRelativePath(self.currentRelativeDir))
-
-    def populateFileList(self,items):
-        self.fileList.clear()
-        for it_text in items:
-          item=qt.QListWidgetItem(self.fileList)
-          item.setText(it_text)
-          item.setIcon(qt.QIcon(it_text))
-
-    def onCloseButtonClicked(self):
-        self.hide()
-
-
-class fileIOWidget(slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget):
-    def __init__(self,parent):
-       slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget.__init__(self, parent)
-       self.selectRemote=remoteFileSelector()
-       #self.selectLocal=qt.QFileDialog()
-       #self.selectLocal.connect('fileSelected(QString)',self.onLocalFileSelected)
-       self.selectRemote.setMaster(self)
-       self.network=slicerNetwork.labkeyURIHandler()
-
-    def setup(self):
-        connectionCollapsibleButton = ctk.ctkCollapsibleButton()
-        connectionCollapsibleButton.text = "Connection"
-        self.layout.addWidget(connectionCollapsibleButton)
-
-        connectionFormLayout = qt.QFormLayout(connectionCollapsibleButton)
-        self.loadConfigButton=qt.QPushButton("Load configuration")
-        self.loadConfigButton.toolTip="Load configuration"
-        self.loadConfigButton.connect('clicked(bool)',self.onLoadConfigButtonClicked)
-        connectionFormLayout.addRow("Connection:",self.loadConfigButton)
-
-        fileDialogCollapsibleButton = ctk.ctkCollapsibleButton()
-        fileDialogCollapsibleButton.text = "Paths"
-        self.layout.addWidget(fileDialogCollapsibleButton)
-
-        fileDialogFormLayout = qt.QFormLayout(fileDialogCollapsibleButton)
-
-        self.listRemoteButton=qt.QPushButton("List Remote")
-        self.listRemoteButton.toolTip="List Remote"
-        self.listRemoteButton.connect('clicked(bool)',self.onListRemoteButtonClicked)
-        fileDialogFormLayout.addRow(self.listRemoteButton)
-
-        self.listLocalButton=qt.QPushButton("List Local")
-        self.listLocalButton.toolTip="List Local"
-        self.listLocalButton.connect('clicked(bool)',self.onListLocalButtonClicked)
-        fileDialogFormLayout.addRow(self.listLocalButton)
-
-        #add selected file display
-        self.remotePath=qt.QLineEdit("")
-        self.remotePath.toolTip="Remote path"
-
-        fileDialogFormLayout.addRow("RemotePath :",self.remotePath)
-
-        self.localPath=qt.QLineEdit("")
-        self.localPath.toolTip="Local path"
-
-        fileDialogFormLayout.addRow("LocalPath :",self.localPath)
-
-        copyToRemoteButton=qt.QPushButton("Local->Remote")
-        copyToRemoteButton.toolTip="Local -> Remote"
-        copyToRemoteButton.connect('clicked(bool)',self.onCopyToRemoteButtonClicked)
-        fileDialogFormLayout.addRow(copyToRemoteButton)
-
-        copyToLocalButton=qt.QPushButton("Remote -> Local")
-        copyToLocalButton.toolTip="Remote -> Local"
-        copyToLocalButton.connect('clicked(bool)',self.onCopyToLocalButtonClicked)
-        fileDialogFormLayout.addRow(copyToLocalButton)
-
-        removeRemoteButton=qt.QPushButton("Remove remote")
-        removeRemoteButton.toolTip="Remove Remote"
-        removeRemoteButton.connect('clicked(bool)',self.onRemoveRemoteButtonClicked)
-        fileDialogFormLayout.addRow(removeRemoteButton)
-
-        mkdirRemoteButton=qt.QPushButton("Mkdir remote")
-        mkdirRemoteButton.toolTip="Mkdir Remote"
-        mkdirRemoteButton.connect('clicked(bool)',self.onMkdirRemoteButtonClicked)
-        fileDialogFormLayout.addRow(mkdirRemoteButton)
-
-    def onListLocalButtonClicked(self):
-        self.localPath.setText(qt.QFileDialog.getOpenFileName(None,"Select local"))
-
-    def onListRemoteButtonClicked(self):
-        self.selectRemote.show()
-
-    def onLoadConfigButtonClicked(self):
-
-        filename=qt.QFileDialog.getOpenFileName(None,'Open configuration file (JSON)',
-            '.', '*.json')
-
-        with open(filename,'r') as f:
-           dt=json.load(f)
-
-        if dt.has_key('host'):
-           self.network.hostname=dt['host']
-
-        if dt.has_key('SSL'):
-           self.network.configureSSL(dt['SSL']['user'],dt['SSL']['key'],
-                dt['SSL']['keyPwd'],dt['SSL']['ca'])
-
-        if dt.has_key('labkey'):
-           if dt['labkey'].has_key('user'):
-               self.network.auth_name=dt['labkey']['user']
-           if dt['labkey'].has_key('password'):
-               self.network.auth_pass=dt['labkey']['password']
-
-        self.loadConfigButton.setText(os.path.basename(filename))
-        self.network.initRemote()
-
-    def copyLocalToRemote(self,localPath,remotePath):
-        if os.path.isfile(localPath):
-            #end recursion
-            print ("Copy {} to {}").format(localPath,remotePath)
-            self.network.copyLocalFileToRemote(localPath,remotePath)
-            return
-
-        dirName=os.path.basename(os.path.normpath(localPath))
-        remotePath+='/'+dirName
-        if not self.network.isRemoteDir(remotePath):
-            self.network.mkdir(remotePath+'/')
-        for f in os.listdir(localPath):
-            #enter recursion
-            localfile=os.path.join(localPath,f)
-            self.copyLocalFileToRemote(localfile,remotePath)
-
-    def copyRemoteToLocal(self,localPath,remotePath):
-        ok,files=self.network.listRemoteDir(remotePath)
-        if not ok:
-            print 'Troubles getting remote dir content for {}'.format(remotePath)
-            return
-        #remove trailing slash
-        for f in files:
-            if f[-1]=='/':
-                f=f[:-1]
-
-            bf=f[f.rfind('/')+1:]
-            dirUrl=self.network.GetLabkeyWebdavUrl()+"/"+f
-            if self.network.isDir(dirUrl):
-                lp=os.path.join(localPath,bf)
-                if not os.path.isdir(lp):
-                    os.mkdir(lp)
-                    print 'Creating {}'.format(lp)
-                print 'Copying directory {} to {}'.format(f,lp)
-                self.copyRemoteToLocal(lp,f)
-            else:
-                rf=self.network.readFile(f)
-                fout=os.path.join(localPath,bf)
-                print 'Copying file {} to {}'.format(f,fout)
-                with open (fout, 'w') as fd:
-                    rf.seek (0)
-                    shutil.copyfileobj (rf, fd)
-                fd.close()
-
-    def onCopyToRemoteButtonClicked(self):
-        self.copyLocalFileToRemote(self.localPath.text,self.remotePath.text)
-
-    def onCopyToLocalButtonClicked(self):
-        self.copyRemoteToLocal(self.localPath.text,self.remotePath.text)
-
-    def onRemoveRemoteButtonClicked(self):
-        remotePath=self.remotePath.text
-        if self.network.isRemoteDir(remotePath):
-            resp=qt.QMessageBox.question(None,'Delete directory',
-                'Do you want to delete directory {}'.format(remotePath))
-            if resp == qt.QMessageBox.No:
-                return
-        self.network.rmdir(remotePath)
-
-    def onMkdirRemoteButtonClicked(self):
-        remotePath=self.remotePath.text
-        self.network.mkdir(remotePath)
-
-
-class fileIOLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
-    def __init__(self,parent):
-       slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic.__init__(self, parent)
-
-
-class fileIOTest(slicer.ScriptedLoadableModule.ScriptedLoadableModuleTest):
-  """
-  This is the test case for your scripted module.
-  Uses ScriptedLoadableModuleTest base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setUp(self):
-    """ Do whatever is needed to reset the state - typically a scene clear will be enough.
-    """
-    slicer.mrmlScene.Clear(0)
-
-  def runTest(self):
-    """Run as few or as many tests as needed here.
-    """
-    self.setUp()
-    self.test_fileIO()
-
-  def test_fileIO(self):
-    """ Ideally you should have several levels of tests.  At the lowest level
-    tests should exercise the functionality of the logic with different inputs
-    (both valid andclass dataExplorerTest(ScriptedLoadableModuleTest):
-  """
-    pass

+ 0 - 675
labkeyBrowser/slicerNetwork.py

@@ -1,675 +0,0 @@
-import qt
-import urllib2
-import socket
-import ssl
-import cookielib
-import xml.etree.ElementTree as ET
-import re
-import StringIO
-import slicer
-import shutil
-import distutils
-import os
-import base64
-import json
-
-#see https://gist.github.com/logic/2715756, allow requests to do Put
-class MethodRequest(urllib2.Request):
-    def __init__(self, *args, **kwargs):
-        if 'method' in kwargs:
-            self._method = kwargs['method']
-            del kwargs['method']
-        else:
-            self._method = None
-        return urllib2.Request.__init__(self, *args, **kwargs)
-
-    def get_method(self, *args, **kwargs):
-        if self._method is not None:
-            return self._method
-        return urllib2.Request.get_method(self, *args, **kwargs)
-
-
-class ConnectionError(Exception):
-    def __init__(self,message):
-        self.message=message
-
-
-class slicerNetwork(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-    def __init__(self, parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self,parent)
-        self.parent.title="slicerNetwork"
-        pass
-
-class labkeyURIHandler(slicer.vtkURIHandler):
-    def __init__(self):
-        slicer.vtkURIHandler.__init__(self)
-        self.className="labkeyURIHandler"
-        slicer.mrmlScene.AddURIHandler(self)
-        try:
-            fhome=os.environ["HOME"]
-        except:
-	           #in windows, the variable is called HOMEPATH
-            fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
-
-        self.localCacheDirectory=os.path.join(fhome,"labkeyCache")
-        self.configDir=os.path.join(fhome,".labkey")
-        self.mode="http"
-        #try initializing network from default config file, if found
-        self.initFromConfig()
-
-
-    def CanHandleURI(self,uri):
-        print("labkeyURIHandler::CanHandleURI({0})").format(uri)
-        if uri.find('labkey://')==0:
-            return 1
-        return 0
-
-    def GetClassName(self):
-        return self.className
-
-
-    def GetHostName(self):
-        return self.hostname
-
-    def SetHostName(self,host):
-        self.hostname=host
-
-    def SetLocalCahceDirectory(self,dir):
-        self.localCacheDirectory=dir
-
-    def GetLocalCacheDirectory(self):
-        return self.localCacheDirectory
-
-    def GetLabkeyUrl(self):
-        return self.hostname+"/labkey"
-
-    def GetLabkeyWebdavUrl(self):
-        return self.GetLabkeyUrl()+"/_webdav"
-
-    #configuration part
-
-    def configureSSL(self,cert,key,pwd,cacert):
-    #do this first
-        try:
-            self.ctx=ssl.SSLContext(ssl.PROTOCOL_SSLv23)
-            self.ctx.load_cert_chain(cert,keyfile=key,password=pwd)
-            self.ctx.verify_mode=ssl.CERT_REQUIRED
-            self.ctx.load_verify_locations(cacert)
-        except ssl.SSLError as err:
-            print(" Failed to configure SSL: {0}").format(str(err))
-        self.mode="https"
-
-
-    def initRemote(self):
-        if self.mode=="https":
-            http_handler=urllib2.HTTPSHandler(context=self.ctx)
-        if self.mode=="http":
-            http_handler=urllib2.HTTPHandler()
-        #cookie part
-        cj=cookielib.CookieJar()
-        cookie_handler=urllib2.HTTPCookieProcessor(cj)
-        self.opener=urllib2.build_opener(http_handler,cookie_handler)
-
-    def initFromConfig(self):
-        path=os.path.join(self.configDir,"Remote.json")
-        try:
-            self.parseConfig(path)
-        except OSError:
-            return
-        self.initRemote()
-
-    def parseConfig(self,fname,parent=None):
-        try:
-            f=open(fname)
-        except OSError as e:
-            print("Confgiuration error: OS error({0}): {1}").format(e.errno, e.strerror)
-            raise
-
-        dt=json.load(f)
-        self.mode="http"
-        if dt.has_key('SSL'):
-            self.configureSSL(
-                dt['SSL']['user'],
-                dt['SSL']['key'],
-                dt['SSL']['keyPwd'],
-                dt['SSL']['ca']
-                )
-            if not parent==None:
-                parent.userCertButton.setText(dt['SSL']['user'])
-                parent.caCertButton.setText(dt['SSL']['ca'])
-                parent.privateKeyButton.setText(dt['SSL']['key'])
-                parent.pwd=dt['SSL']['keyPwd']
-
-
-        self.hostname=dt['host']
-        self.auth_name=dt['labkey']['user']
-        self.auth_pass=dt['labkey']['password']
-        if not parent==None:
-            parent.serverURL.setText(dt['host'])
-            parent.authName.setText(dt['labkey']['user'])
-            parent.authPass.setText(dt['labkey']['password'])
-
-
-    #path convention
-
-    #localPath is a path on local filesystem. It means it has to adhere to OS
-    #policy, especially in separators
-
-    #relativePath is just the portion of the path that is equal both locally
-    #and remotely. In relativePath, separator is according to http convention,
-    #which equals separator in osx and *nix
-
-    #labkeyPath or remotePath is the full URL to the resource,
-    #including http-like header and all intermediate portions
-
-    #the following functions convert between different notations
-
-    #was GetLocalPath
-    def GetLocalPathFromRelativePath(self,relativePath):
-        debug=False
-        relativePath=re.sub('labkey://','',relativePath)
-        sp=os.sep.encode('string-escape')
-        if debug:
-            print("Substituting / with {0} in {1}").format(sp,relativePath)
-        relativePath=re.sub('/',sp,relativePath)
-        return os.path.join(self.GetLocalCacheDirectory(),relativePath)
-
-    #was GetRemotePath
-    def GetLabkeyPathFromRelativePath(self,source):
-        return self.GetLabkeyWebdavUrl()+"/"+source
-
-    #was GetLabkeyPathFromLocalPath
-    def GetRelativePathFromLocalPath(self,f):
-        debug=False
-        #report it with URL separator, forward-slash
-        if f.find(self.localCacheDirectory)<-1:
-            print("Localpath misformation. Exiting")
-            return "NULL"
-        f0=re.sub('\\\\','\\\\\\\\',self.localCacheDirectory)
-        relativePath=re.sub(re.compile(f0),'',f)
-        if debug:
-            print("[SEP] Relative path {}").format(relativePath)
-        #leaves /ContextPath/%40files/subdirectory_list/files
-        #remove first separator
-        sp=os.path.sep
-        f1=re.sub('\\\\','\\\\\\\\',sp)
-        if relativePath[0]==sp:
-            relativePath=relativePath[1:len(relativePath)]
-
-        if debug:
-            print("[SLASH] Relative path {}").format(relativePath)
-
-        return re.sub(f1,'/',relativePath)
-
-    #was GetLabkeyPathFromRemotePath
-    def GetRelativePathFromLabkeyPath(self,f):
-        #used to query labkey stuff, so URL separator is used
-
-        #in old conventions, labkey://was used to tag a labkeyPath
-        f=re.sub('labkey://','',f)
-        f=re.sub(self.GetLabkeyWebdavUrl(),'',f)
-
-        if f[0]=='/':
-            f=f[1:len(f)]
-        return f;
-
-
-    #standard HTTP
-    def get(self,url):
-
-        debug=False
-        if debug:
-            print("GET: {0}").format(url)
-            print("as {0}").format(self.auth_name)
-        r=urllib2.Request(url)
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-        try:
-            return self.opener.open(r)
-        #f contains json as a return value
-        except urllib2.HTTPError as e:
-            print e.code
-            print e.read()
-            return e
-        except urllib2.URLError as e:
-            print("Handling URLError")
-            print e
-            return None
-    
-    #a HEAD request
-    def head(self,url):
-    
-        debug=False
-        if debug:
-            print("HEAD: {0}").format(url)
-            print("as {0}").format(self.auth_name)
-        r=MethodRequest(url.encode('utf-8'),method="HEAD")
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-        try:
-            return self.opener.open(r)
-        #f contains json as a return value
-        except urllib2.HTTPError as e:
-            print e.code
-            print e.read()
-            return e
-
-
-    def post(self,url,data):
-
-        debug=False
-        r=urllib2.Request(url)
-        #makes it a post
-        r.add_data(data)
-        r.add_header("Content-Type","application/json")
-        #add csrf
-        csrf=self.getCSRF()
-        r.add_header("X-LABKEY-CSRF",csrf)
-
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-        if debug:
-            print("{}: {}").format(r.get_method(),r.get_full_url())
-            print("data: {}").format(r.get_data())
-            print("Content-Type: {}").format(r.get_header('Content-Type'))
-        try:
-            return self.opener.open(r)
-        except urllib2.HTTPError as e:
-            print e.code
-            print e.read()
-            return e
-        #f contains json as a return value
-
-    def put(self,url,data):
-
-        debug=False
-
-        if debug:
-            print("PUT: {}").format(url)
-        r=MethodRequest(url.encode('utf-8'),method="PUT")
-        #makes it a post
-        r.add_data(data)
-        print("PUT: data size: {}").format(len(data))
-        r.add_header("content-type","application/octet-stream")
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-
-        return self.opener.open(r)
-        #f contains json as a return value
-
-    def getCSRF(self):
-        url=self.GetLabkeyUrl()+'/login/whoAmI.view'
-        try:
-            jsonData=json.load(self.get(url))
-        except AttributeError:
-            print("Failed")
-            return None
-        
-        return jsonData["CSRF"]
-
-
-    #file manipulation routiens
-
-    #was GetFile
-    def DownloadFileToCache(self,relativePath):
-        debug=False
-        # check for file in cache. If available, use, if not, download
-        localPath=self.GetLocalPathFromRelativePath(relativePath)
-        if os.path.isfile(localPath):
-            if debug:
-                print("Returning localFile {}".format(localPath))
-            return localPath
-
-        if debug:
-            print("labkeyURIHandler::DownloadFileToCache({0}->{1})").format(relativePath,localPath)
-
-        #make all necessary directories LOCALLY
-        path=os.path.dirname(localPath)
-        if debug:
-            print("Target directory: '{}''".format(path))
-        if not os.path.isdir(path):
-            os.makedirs(path)
-
-        localBuffer=open(localPath,'wb')
-        #make sure we are at the begining of the file
-
-
-        #labkeyPath=self.GetLabkeyPathFromRelativePath(relativePath)
-        remoteBuffer=self.readFileToBuffer(relativePath)
-
-	    #check file size
-        if debug:
-	         remoteBuffer.seek(0,2)
-	         sz=remoteBuffer.tell()
-	         print("Remote size: {0}").format(sz)
-
-
-        remoteBuffer.seek(0)
-
-        shutil.copyfileobj(remoteBuffer,localBuffer)
-        if debug:
-	         print("Local size: {0}").format(localBuffer.tell())
-        localBuffer.close()
-        return localPath
-
-    def fileTypesAvailable(self):
-        return ('VolumeFile','SegmentationFile','TransformFile')
-
-    #mimic slicer.util.loadNodeFromFile
-    def loadNode(self, relativeName, filetype, properties={},returnNode=False, keepCached=True):
-         #this is the only relevant part - file must be downloaded to cache
-         #labkeyName is just the relative part (from labkey onwards)
-         
-         localPath=self.DownloadFileToCache(relativeName)
-         
-         if not returnNode:
-             slicer.util.loadNodeFromFile(localPath,filetype,properties,returnNode=False)
-             if not keepCached:
-                 os.remove(localPath)
-             return
-         
-         ok,node=slicer.util.loadNodeFromFile(localPath,filetype,properties,returnNode=True)
-         if ok:
-             if not keepCached:
-                 os.remove(localPath)
-             return node
-         
-
-         os.remove(localPath)
-         return None
-    #     #remove retrieved file
-
-    def storeNode(self,node,project,dir=None):
-
-        removeFile=True
-        relativePath=project+'/%40files'
-        if not dir==None:
-            relativePath+='/'+dir
-        labkeyPath=self.GetLabkeyPathFromRelativePath(relativePath)
-        print ("Remote: {}").format(labkeyPath)
-      
-        #checks if exists
-        self.mkdir(labkeyPath)
-
-        localPath=self.GetLocalPathFromRelativePath(relativePath)
-        localPath.replace('/',os.path.sep)
-
-        nodeName=node.GetName()
-
-        suffix=".nrrd"
-        if node.__class__.__name__=="vtkMRMLDoubleArrayNode":
-            suffix=".mcsv"
-        if node.__class__.__name__=="vtkMRMLTransformNode":
-            suffix=".h5"
-        fileName=nodeName+suffix
-        file=os.path.join(localPath,fileName)
-        slicer.util.saveNode(node,file)
-        print("Stored to: {}").format(file)
-        f=open(file,"rb")
-
-        f.seek(0,2)
-        sz=f.tell()
-        print("File size in memory: {0}").format(sz)
-        f.seek(0)
-
-        localBuffer=f.read()
-        print("Local buffer size: {}").format(len(localBuffer))
-        remoteFile=labkeyPath+'/'+fileName
-        resp=self.put(remoteFile,localBuffer)
-        print(resp.read())
-        f.close()
-        if removeFile:
-            os.remove(file)
-
-
-
-    def remoteDirExists(self,url):
-        status,dirs=self.listRemoteDir(url);
-        return status
-
-    def mkdir(self,remoteDir):
-        if self.remoteDirExists(remoteDir):
-            return False
-        r=MethodRequest(remoteDir,method="MKCOL")
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-        try:
-            f=self.opener.open(r)
-        except:
-            print("Error: Failed MKCOL {}").format(remoteDir)
-            return False
-        return True
-
-    def mkdirs(self,remoteDir):
-        relativePath=self.GetRelativePathFromLabkeyPath(remoteDir)
-        s=0
-        while True:
-            s1=relativePath.find('/',s)
-            if s1<0:
-                break
-            path=relativePath[0:s1]
-            remotePath=self.GetLabkeyPathFromRelativePath(relativePath)
-            dirExists=self.remoteDirExists(remotePath)
-            if not dirExists:
-                if not self.mkdir(remotePath):
-                    return False
-            s=s1+1
-        return self.mkdir(remoteDir)
-
-    def rmdir(self,remoteDir):
-        if not self.remoteDirExists(remoteDir):
-            return True
-        r=MethodRequest(remoteDir,method="DELETE")
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-        try:
-            f=self.opener.open(r)
-        except:
-            print("Error: Failed DELETE {}").format(remoteDir)
-            return False
-        return True
-
-    #was listDir
-    def listRelativeDir(self,relativeDir):
-        print("Listing for {0}").format(relativeDir)
-        dirUrl=self.GetLabkeyPathFromRelativePath(relativeDir)
-        status,dirs=self.listRemoteDir(dirUrl)
-        dirs=[self.GetRelativePathFromLabkeyPath(d) for d in dirs];
-        return dirs
-
-    #was isDir
-    def isRemoteDir(self, remotePath):
-        #print "isDir: {}".format(remotePath)
-        r=MethodRequest(remotePath,method="PROPFIND")
-        PROPFIND=u"""<?xml version="1.0" encoding="utf-8"?>\n
-            <a:propfind xmlns:a="DAV:">\n
-            <a:prop>\n
-            <a:resourcetype/>\n
-            </a:prop>\n
-            </a:propfind>"""
-        r.add_header('content-type','text/xml; charset="utf-8"')
-        r.add_header('content-length',str(len(PROPFIND)))
-        r.add_header('Depth','0')
-        r.add_data(PROPFIND)
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-        print("PROPFIND: {0}").format(remotePath)
-        try:
-            f=self.opener.open(r)
-        except:
-            return False
-        tree=ET.XML(f.read())
-        try:
-            rps=tree.find('{DAV:}response').find('{DAV:}propstat')
-            rps=rps.find('{DAV:}prop')
-            rps=rps.find('{DAV:}resourcetype').find('{DAV:}collection')
-            if rps != None:
-                return True
-            else:
-                return False
-        except:
-            return False
-
-    def listRemoteDir(self,dirUrl):
-        #input is remoteDir, result are remoteDirs
-
-        r=MethodRequest(dirUrl,method="PROPFIND")
-        PROPFIND=u"""<?xml version="1.0" encoding="utf-8"?>\n
-                    <propfind xmlns="DAV:">\n
-                    <prop>\n
-                    <getetag/>\n
-                    </prop>\n
-                    </propfind>"""
-        r.add_header('content-type','text/xml; charset="utf-8"')
-        r.add_header('content-length',str(len(PROPFIND)))
-        r.add_header('Depth','1')
-        r.add_data(PROPFIND)
-        base64string = base64.b64encode('%s:%s' % (self.auth_name, self.auth_pass))
-        r.add_header("Authorization", "Basic %s" % base64string)
-        print("PROPFIND: {0}").format(dirUrl)
-        dirs=[]
-        try:
-            f=self.opener.open(r)
-        except:
-            return False,dirs
-        tree=ET.XML(f.read())
-        rps=tree.findall('{DAV:}response')
-        for r in rps:
-            hr=r.find('{DAV:}href')
-            dirent=hr.text
-            #dirent=re.sub('/labkey/_webdav/','',dirent)
-            dirent=self.GetHostName()+dirent
-            dirs.append(dirent)
-        del dirs[0]
-        return True,dirs
-
-    def toRelativePath(self,dirs):
-        flist1=[]
-        for d in dirs:
-            if d[-1]=='/':
-                d=d[:-1]
-            if d.rfind('/')>-1:
-                d=d[d.rfind('/')+1:]
-            flist1.append(d)
-        return flist1
-
-    def readFileToBuffer(self, relativePath):
-        dirUrl=self.GetLabkeyPathFromRelativePath(relativePath)
-        f=self.get(dirUrl)
-        return StringIO.StringIO(f.read())
-
-    def uploadFile(self,localPath):
-        #get upstream directories sorted out
-        relativePath=self.GetRelativePathFromLocalPath(localPath)
-        if relativePath=="NULL":
-            errorCode="Failed to upload {}. Potential incorrect location"
-            errorCode+=". Should be in labkeyCache!"
-            print(errorCode.format(relativePath))
-            return False
-        relativeDir=relativePath[0:labkeyPath.rfind('/')]
-        remoteDir=self.GetLabkeyPathFromRemotePath(relativeDir)
-        if not self.remoteDirExists(remoteDir):
-            if not self.mkdirs(remoteDir):
-                errorCode="UploadFile: Could not create directory {}"
-                print(errorCode.format(remoteDir))
-                return False
-
-        #make an URL request
-        with open(localPath, 'rb') as f:
-            data=f.read()
-        remotePath=self.GetLabkeyPathFromRelativePath(relativePath)
-        self.put(remotePath,data)
-
-    #was copyFileToRemote
-    def copyLocalFileToRemote(self,localPath, remotePath):
-        #get upstream directories sorted out
-
-        remoteDir=os.path.dirname(remotePath)
-        if not self.remoteDirExists(remoteDir):
-            if not self.mkdirs(remoteDir):
-                errorCode="UploadFile: Could not create directory {}"
-                print(errorCode.format(remoteDir))
-                return False
-
-        #make an URL request
-        if (self.isRemoteDir(remotePath)):
-            remotePath=remotePath+'/'+os.path.basename(localPath)
-
-        with open(localPath, 'rb') as f:
-            data=f.read()
-
-        itry=0
-        while itry<10:
-            try:
-                self.put(remotePath,data)
-                break
-            except (socket.error,urllib2.URLError):
-                print("[{}] Failed to execute put(), retry".format(itry))
-                itry=itry+1
-        if itry==10:
-            raise ConnectionError('Could not copy file, number of tries exceeded') 
-
-    #was loadDir
-    def DownloadDirToCache(self, relativePath):
-
-        files=self.listRelativeDir(relativePath)
-        fdir="NONE"
-        for f in files:
-            #f is local path
-            try:
-                localDir=os.path.dirname(self.DownloadFileToCache(f))
-            except:
-                #fails if there is a subdirectory; go recursively
-                print("self.readDir(f) not implemented")
-        return localDir
-
-    #database routines
-
-    def loadDataset(self,project,dataset):
-        url=self.GetLabkeyUrl()+'/'+project
-        url+='/query-selectRows.api?schemaName=study&query.queryName='+dataset
-        return json.load(self.get(url))
-
-    def filterDataset(self,project,dataset,filter):
-        debug=False
-        url=self.GetLabkeyUrl()+'/'+project
-        url+='/query-selectRows.api?schemaName=study&query.queryName='+dataset
-        for f in filter:
-            url+="&query."+f['variable']+"~"+f['oper']+"="+f['value']
-        if debug:
-            print("Sending {}").format(url)
-        return json.load(self.get(url))
-
-
-    def modifyDataset(self,method,project,dataset,rows):
-        #method can be insert or update
-        data={}
-        data['schemaName']='study'
-        data['queryName']=dataset
-        data['rows']=rows
-        url=self.GetLabkeyUrl()+'/'+project
-        url+='/query-'+method+'Rows.api?'
-        return self.post(url,json.dumps(data))
-
-    def filterList(self,project,dataset,filter):
-        schemaName='lists'
-        debug=False
-        url=self.GetLabkeyUrl()+'/'+project
-        url+='/query-selectRows.api?schemaName='+schemaName+'&query.queryName='+dataset
-        for f in filter:
-            url+="&query."+f['variable']+"~"+f['oper']+"="+f['value']
-        if debug:
-            print("Sending {}").format(url)
-        return json.load(self.get(url))
-
-
-    def modifyList(self,method,project,dataset,rows):
-        #method can be insert or update
-        data={}
-        schemaName='lists'
-        data['schemaName']=schemaName
-        data['queryName']=dataset
-        data['rows']=rows
-        url=self.GetLabkeyUrl()+'/'+project
-        url+='/query-'+method+'Rows.api?'
-        return self.post(url,json.dumps(data))

+ 0 - 2
labkeyBrowser/CMakeLists.txt → slicerModules/CMakeLists.txt

@@ -4,8 +4,6 @@ set(MODULE_NAME labkeySlicerPythonExtension)
 #-----------------------------------------------------------------------------
 #-----------------------------------------------------------------------------
 set(MODULE_PYTHON_SCRIPTS
 set(MODULE_PYTHON_SCRIPTS
   ${MODULE_NAME}.py
   ${MODULE_NAME}.py
-  fileIO.py
-  slicerNetwork.py
   )
   )
 
 
 set(MODULE_PYTHON_RESOURCES
 set(MODULE_PYTHON_RESOURCES

+ 0 - 0
labkeyBrowser/Resources/Icons/labkeyBrowser.png → slicerModules/Resources/Icons/labkeyBrowser.png


+ 0 - 0
labkeyBrowser/Resources/Screenshots/slicerLabkeyExtensionCaption.png → slicerModules/Resources/Screenshots/slicerLabkeyExtensionCaption.png


+ 0 - 0
labkeyBrowser/Testing/CMakeLists.txt → slicerModules/Testing/CMakeLists.txt


+ 0 - 0
labkeyBrowser/Testing/Python/CMakeLists.txt → slicerModules/Testing/Python/CMakeLists.txt


+ 240 - 75
labkeyBrowser/labkeyBrowser.py → slicerModules/labkeyBrowser.py

@@ -2,10 +2,13 @@ import os
 import unittest
 import unittest
 from __main__ import vtk, qt, ctk, slicer
 from __main__ import vtk, qt, ctk, slicer
 from slicer.ScriptedLoadableModule import *
 from slicer.ScriptedLoadableModule import *
-import slicerNetwork
-import loadDicom
+#import slicerNetwork
 import json
 import json
-
+import zipfile
+import pathlib
+import sys
+import urllib3
+import string
 #
 #
 # labkeySlicerPythonExtension
 # labkeySlicerPythonExtension
 #
 #
@@ -41,7 +44,38 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
     ScriptedLoadableModuleWidget.setup(self)
     ScriptedLoadableModuleWidget.setup(self)
     # Instantiate and connect widgets ...
     # Instantiate and connect widgets ...
     self.logic=labkeyBrowserLogic(self)
     self.logic=labkeyBrowserLogic(self)
-    self.network=slicerNetwork.labkeyURIHandler()
+
+    fhome=os.path.expanduser('~')
+    fsetup=os.path.join(fhome,'.labkey','setup.json')
+    try:
+        with open(fsetup) as f:
+            self.setup=json.load(f)
+    except FileNotFoundError:
+        self.setup={}
+
+    try:
+        pt=self.setup['paths']
+    except KeyError:
+        self.setup['paths']={}
+
+    try:    
+        sys.path.append(self.setup['paths']['labkeyInterface'])
+    except KeyError:
+        self.setup['paths']['labkeyInterface']=loadLibrary('labkeyInterface')
+        with open(fsetup,'w') as f:
+            json.dump(self.setup,f,indent='\t')
+    
+    import labkeyInterface
+    import labkeyDatabaseBrowser
+    import labkeyFileBrowser
+
+    #self.network=slicerNetwork.labkeyURIHandler()
+    self.network=labkeyInterface.labkeyInterface()
+    fconfig=os.path.join(fhome,'.labkey','network.json')
+    self.network.init(fconfig)
+    self.db=labkeyDatabaseBrowser.labkeyDB(self.network)
+    self.fb=labkeyFileBrowser.labkeyFileBrowser(self.network)
+
     #
     #
     # Parameters Area
     # Parameters Area
     #
     #
@@ -54,12 +88,12 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
     self.configDir=os.path.join(os.path.expanduser('~'),".labkey")
     self.configDir=os.path.join(os.path.expanduser('~'),".labkey")
 
 
     self.serverURL=qt.QLineEdit("https://merlin.fmf.uni-lj.si")
     self.serverURL=qt.QLineEdit("https://merlin.fmf.uni-lj.si")
-    self.serverURL.textChanged.connect(self.updateServerURL)
+    #self.serverURL.textChanged.connect(self.updateServerURL)
     connectionFormLayout.addRow("Server: ", self.serverURL)
     connectionFormLayout.addRow("Server: ", self.serverURL)
     #copy initial setting
     #copy initial setting
-    self.updateServerURL(self.serverURL.text);
+    #self.updateServerURL(self.serverURL.text);
 
 
-    self.startDir=os.path.join(os.path.expanduser('~'),"temp/crt")
+    self.startDir=os.path.join(os.path.expanduser('~'),"temp","crt")
 
 
     self.userCertButton=qt.QPushButton("Load")
     self.userCertButton=qt.QPushButton("Load")
     self.userCertButton.toolTip="Load user certificate (crt)"
     self.userCertButton.toolTip="Load user certificate (crt)"
@@ -69,7 +103,8 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
 
 
     self.privateKeyButton=qt.QPushButton("Load")
     self.privateKeyButton=qt.QPushButton("Load")
     self.privateKeyButton.toolTip="Load private key"
     self.privateKeyButton.toolTip="Load private key"
-    self.privateKeyButton.connect('clicked(bool)',self.onPrivateKeyButtonClicked)
+    self.privateKeyButton.connect('clicked(bool)',\
+            self.onPrivateKeyButtonClicked)
 
 
     connectionFormLayout.addRow("Private key:",self.privateKeyButton)
     connectionFormLayout.addRow("Private key:",self.privateKeyButton)
 
 
@@ -82,26 +117,39 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
 
 
     self.loadConfigButton=qt.QPushButton("Load configuration")
     self.loadConfigButton=qt.QPushButton("Load configuration")
     self.loadConfigButton.toolTip="Load configuration"
     self.loadConfigButton.toolTip="Load configuration"
-    self.loadConfigButton.connect('clicked(bool)',self.onLoadConfigButtonClicked)
+    self.loadConfigButton.connect('clicked(bool)',\
+            self.onLoadConfigButtonClicked)
     connectionFormLayout.addRow("Configuration:",self.loadConfigButton)
     connectionFormLayout.addRow("Configuration:",self.loadConfigButton)
 
 
+    self.loadZipButton=qt.QPushButton("Load certificates (.zip)")
+    self.loadZipButton.toolTip="Load certificates from zip file"
+    self.loadZipButton.connect('clicked(bool)',\
+            self.onLoadZipButtonClicked)
+    connectionFormLayout.addRow("Load certificates (merlin):",\
+            self.loadZipButton)
+    
     self.saveConfigButton=qt.QPushButton("Save configuration")
     self.saveConfigButton=qt.QPushButton("Save configuration")
     self.saveConfigButton.toolTip="Save configuration"
     self.saveConfigButton.toolTip="Save configuration"
     self.saveConfigButton.clicked.connect(self.onSaveConfigButtonClicked)
     self.saveConfigButton.clicked.connect(self.onSaveConfigButtonClicked)
     connectionFormLayout.addRow("Configuration:",self.saveConfigButton)
     connectionFormLayout.addRow("Configuration:",self.saveConfigButton)
     
     
+    self.resetConfigButton=qt.QPushButton("Reset configuration")
+    self.resetConfigButton.toolTip="Reset configuration"
+    self.resetConfigButton.clicked.connect(self.onResetConfigButtonClicked)
+    connectionFormLayout.addRow("Configuration:",self.resetConfigButton)
+    
     self.initButton=qt.QPushButton("Init")
     self.initButton=qt.QPushButton("Init")
     self.initButton.toolTip="Initialize connection to the server"
     self.initButton.toolTip="Initialize connection to the server"
     self.initButton.connect('clicked(bool)',self.onInitButtonClicked)
     self.initButton.connect('clicked(bool)',self.onInitButtonClicked)
     connectionFormLayout.addRow("Connection:",self.initButton)
     connectionFormLayout.addRow("Connection:",self.initButton)
 
 
     self.authName=qt.QLineEdit("email")
     self.authName=qt.QLineEdit("email")
-    self.authName.textChanged.connect(self.updateAuthName)
+    #self.authName.textChanged.connect(self.updateAuthName)
     connectionFormLayout.addRow("Labkey username: ", self.authName)
     connectionFormLayout.addRow("Labkey username: ", self.authName)
 
 
     self.authPass=qt.QLineEdit("")
     self.authPass=qt.QLineEdit("")
     self.authPass.setEchoMode(qt.QLineEdit.Password)
     self.authPass.setEchoMode(qt.QLineEdit.Password)
-    self.authPass.textChanged.connect(self.updateAuthPass)
+    #self.authPass.textChanged.connect(self.updateAuthPass)
     connectionFormLayout.addRow("Labkey password: ", self.authPass)
     connectionFormLayout.addRow("Labkey password: ", self.authPass)
 
 
     
     
@@ -118,7 +166,8 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
     self.fileList=qt.QListWidget()
     self.fileList=qt.QListWidget()
     self.fileList.toolTip="Select remote file"
     self.fileList.toolTip="Select remote file"
     self.fileList.itemDoubleClicked.connect(self.onFileListDoubleClicked)
     self.fileList.itemDoubleClicked.connect(self.onFileListDoubleClicked)
-    self.currentRemoteDir=''
+    #remote dir is a list
+    self.currentRemoteDir=[]
 
 
     #add dummy entry
     #add dummy entry
     items=('.','..')
     items=('.','..')
@@ -136,7 +185,8 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
     self.fileTypeSelector=qt.QComboBox()
     self.fileTypeSelector=qt.QComboBox()
     self.fileTypeSelector.toolTip="Select file type"
     self.fileTypeSelector.toolTip="Select file type"
 
 
-    items=self.network.fileTypesAvailable()
+    items=('VolumeFile','SegmentationFile','TransformFile')
+
     self.populateFileTypeSelector(items)
     self.populateFileTypeSelector(items)
 
 
     fileDialogFormLayout.addRow("File type :",self.fileTypeSelector)
     fileDialogFormLayout.addRow("File type :",self.fileTypeSelector)
@@ -198,11 +248,11 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
 
 
      certList=qt.QSslCertificate.fromPath(filename)
      certList=qt.QSslCertificate.fromPath(filename)
      if len(certList) < 1:
      if len(certList) < 1:
-         print ("Troubles parsing {0}").format(filename)
+         print ("Troubles parsing {0}".format(filename))
          return
          return
 
 
      self.logic.cert=qt.QSslCertificate(f)
      self.logic.cert=qt.QSslCertificate(f)
-     print("cert.isNull()={0}").format(self.logic.cert.isNull())
+     print("cert.isNull()={0}".format(self.logic.cert.isNull()))
      self.userCertButton.setText(filename)
      self.userCertButton.setText(filename)
      self.authName.setText(self.logic.cert.subjectInfo("emailAddress"))
      self.authName.setText(self.logic.cert.subjectInfo("emailAddress"))
 
 
@@ -240,7 +290,7 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
       certList=qt.QSslCertificate.fromPath(filename)
       certList=qt.QSslCertificate.fromPath(filename)
 
 
       if len(certList) < 1:
       if len(certList) < 1:
-          print("Troubles parsing {0}").format(filename)
+          print("Troubles parsing {0}".format(filename))
           return
           return
       self.logic.caCert=qt.QSslCertificate(f)#certList[0]
       self.logic.caCert=qt.QSslCertificate(f)#certList[0]
       self.caCertButton.setText(filename)
       self.caCertButton.setText(filename)
@@ -248,14 +298,77 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
   def onLoadConfigButtonClicked(self):
   def onLoadConfigButtonClicked(self):
        filename=qt.QFileDialog.getOpenFileName(None,'Open configuration file (JSON)',
        filename=qt.QFileDialog.getOpenFileName(None,'Open configuration file (JSON)',
             self.configDir, '*.json')
             self.configDir, '*.json')
-       self.network.parseConfig(filename,self)
+ 
+        
+       self.network.init(filename)
+
+       cfg=self.network.connectionConfig
+
+       if 'SSL' in cfg:
+           sslSetup=cfg['SSL']
+           self.privateKeyButton.setText(sslSetup['key'])
+           self.userCertButton.setText(sslSetup['user'])
+           self.caCertButton.setText(sslSetup['ca'])
+      
+       self.serverURL.setText(cfg['host'])
+       if 'labkey' in cfg:
+           labkey=cfg['labkey']
+           self.authName.setText(labkey['user'])
+           self.authPass.setText(labkey['password'])
+
        #self.serverURL.setText(self.network.hostname)
        #self.serverURL.setText(self.network.hostname)
        #self.authName.setText(self.network.auth_name)
        #self.authName.setText(self.network.auth_name)
        #self.authPass.setText(self.network.auth_pass)
        #self.authPass.setText(self.network.auth_pass)
 
 
        self.loadConfigButton.setText(os.path.basename(filename))
        self.loadConfigButton.setText(os.path.basename(filename))
-  
+ 
+  def onLoadZipButtonClicked(self):
+       filename=qt.QFileDialog.getOpenFileName(\
+               None,'Open certificate file (zip)',
+               self.configDir, '*.zip')
+       zpath=pathlib.Path(filename)
+       user=zpath.stem
+       userDir=os.path.join(os.path.expanduser('~'),'.labkey',user)
+       if not os.path.isdir(userDir):
+           os.mkdir(userDir)
+           
+       caName=None
+       with zipfile.ZipFile(filename,'r') as zipObj:
+           zipObj.extract(user+'.crt',userDir)
+           zipObj.extract(user+'.key',userDir)
+           zipList=zipObj.namelist()
+           for f in zipList:
+               if f.find('CA')>-1:
+                   caName=f
+                   zipObj.extract(f,userDir)
+
+       self.serverURL.setText('https://merlin.fmf.uni-lj.si')
+       self.privateKeyButton.setText(os.path.join(userDir,user+'.key'))
+       self.userCertButton.setText(os.path.join(userDir,user+'.crt'))
+       self.pwd='notUsed'
+       self.caCertButton.setText(os.path.join(userDir,caName))
+       self.authName.setText("guest")
+       self.authPass.setText("guest")
+
+
+
+
+
   def onSaveConfigButtonClicked(self):
   def onSaveConfigButtonClicked(self):
+      connectionConfig=self.generateConfig()
+      fhome=os.path.expanduser('~')
+      labkeyDir=os.path.join(fhome,".labkey")
+      if not os.path.isdir(labkeyDir):
+          os.mkdir(labkeyDir)
+      fconfig=os.path.join(labkeyDir,'network.json')
+
+      with open(fconfig,'w') as f:
+            json.dump(connectionConfig,f,indent=3)
+
+      print("Done")
+
+
+  def generateConfig(self):
       connectionConfig={}
       connectionConfig={}
        
        
        #setup SSL
        #setup SSL
@@ -269,8 +382,12 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
             sslSetup['user']=self.userCertButton.text
             sslSetup['user']=self.userCertButton.text
             sslSetup['key']=self.privateKeyButton.text
             sslSetup['key']=self.privateKeyButton.text
             sslSetup['ca']=self.caCertButton.text
             sslSetup['ca']=self.caCertButton.text
-            sslSetup['keyPwd']=self.pwd
+            try:
+                sslSetup['keyPwd']=self.pwd
+            except AttributeError:
+                sslSetup['keyPwd']='notUsed'
             connectionConfig['SSL']=sslSetup
             connectionConfig['SSL']=sslSetup
+
       connectionConfig["host"]=self.serverURL.text
       connectionConfig["host"]=self.serverURL.text
       connectionConfig["context"]="labkey"
       connectionConfig["context"]="labkey"
       labkeySetup={}
       labkeySetup={}
@@ -286,49 +403,43 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
       orthancSetup['user']='ask'
       orthancSetup['user']='ask'
       orthancSetup['password']='askPassword'
       orthancSetup['password']='askPassword'
       connectionConfig['orthanc']=orthancSetup
       connectionConfig['orthanc']=orthancSetup
+      return connectionConfig
 
 
-
-      fhome=os.path.expanduser('~')
-      labkeyDir=os.path.join(fhome,".labkey")
-      if not os.path.isdir(labkeyDir):
-          os.mkdir(labkeyDir)
-      fconfig=os.path.join(labkeyDir,'network.json')
-
-      with open(fconfig,'w') as f:
-            json.dump(connectionConfig,f,indent=3)
-
-      print("Done")
-
+  def onResetConfigButtonClicked(self):
+      self.serverURL.setText('URL')
+      self.privateKeyButton.setText("Load")
+      self.userCertButton.setText("Load")
+      self.caCertButton.setText("Load")
+      self.authName.setText("labkey username")
+      self.authPass.setText("password")
 
 
   def onInitButtonClicked(self):
   def onInitButtonClicked(self):
-      if self.serverURL.text.find("https")==0:
-          try:
-            self.network.configureSSL(
-              self.userCertButton.text,
-              self.privateKeyButton.text,
-              self.pwd,
-              self.caCertButton.text)
-          except AttributeError:
-            pass
-        
+
+      self.network.connectionConfig=self.generateConfig()
+      print(self.network.connectionConfig['labkey']['user'])
 
 
       self.network.initRemote()
       self.network.initRemote()
-      if self.network.getCSRF()==None:
+      remoteId=self.network.getUserId()
+      if remoteId==None:
           self.initButton.setStyleSheet("background-color: red")
           self.initButton.setStyleSheet("background-color: red")
       else:
       else:
-          self.initButton.setStyleSheet("background-color: green")
+          if remoteId['email']==self.network.connectionConfig['labkey']['user']:
+              self.initButton.setStyleSheet("background-color: green")
+          else:
+              self.initButton.setStyleSheet("background-color: orange")
+
 
 
-  def updateAuthName(self,txt):
-      self.network.auth_name=txt
-      print("Setting username to {0}").format(self.network.auth_name);
+  #def updateAuthName(self,txt):
+      #self.network.auth_name=txt
+      #print("Setting username to {0}".format(self.network.auth_name))
 
 
-  def updateAuthPass(self,txt):
-      self.network.auth_pass=txt
-      print("Setting password.")
+  #def updateAuthPass(self,txt):
+      #self.network.auth_pass=txt
+      #print("Setting password.")
 
 
-  def updateServerURL(self,txt):
-      self.network.hostname=txt
-      print("Setting hostname to {0}").format(self.network.hostname);
+  #def updateServerURL(self,txt):
+      #self.network.hostname=txt
+      #print("Setting hostname to {}".format(self.network.hostname))
 
 
   def onFileListDoubleClicked(self,item):
   def onFileListDoubleClicked(self,item):
         if item == None:
         if item == None:
@@ -336,26 +447,26 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
             return
             return
 
 
         iText=item.text()
         iText=item.text()
-        print("Selected items: {0} ").format(iText)
-
+        print("Selected items: {0} ".format(iText))
 
 
+        
         #this is hard -> compose path string from currentRemoteDir and selection
         #this is hard -> compose path string from currentRemoteDir and selection
         if item.text().find('..')==0:
         if item.text().find('..')==0:
             #one up
             #one up
-            idx=self.currentRemoteDir.rfind('/')
-            if idx<0:
-                self.currentRemoteDir=''
-            else:
-                self.currentRemoteDir=self.currentRemoteDir[:idx]
+            try:
+                self.currentRemoteDir.pop()
+            except IndexError:
+                pass
         elif item.text().find('.')==0:
         elif item.text().find('.')==0:
             pass
             pass
         else:
         else:
-            if len(self.currentRemoteDir)>0:
-                self.currentRemoteDir+='/'
-            self.currentRemoteDir+=item.text()
-        print("Listing {0}").format(self.currentRemoteDir)
-        flist=self.network.toRelativePath(
-            self.network.listRelativeDir(self.currentRemoteDir))
+            self.currentRemoteDir.append(item.text())
+        print("Listing {}".format(self.currentRemoteDir))
+        remoteDirString=self.fb.GetRootUrl()
+        if len(self.currentRemoteDir):
+            remoteDirString+='/'+'/'.join(self.currentRemoteDir)
+        ok,lst=self.fb.listRemoteDir(remoteDirString)
+        flist=[self.fb.baseDir(f) for f in lst] 
         print("Got")
         print("Got")
         print(flist)
         print(flist)
         flist.insert(0,'..')
         flist.insert(0,'..')
@@ -365,20 +476,32 @@ class labkeyBrowserWidget(ScriptedLoadableModuleWidget):
 
 
   def onLoadFileButtonClicked(self):
   def onLoadFileButtonClicked(self):
       properties={}
       properties={}
-      localPath=self.network.DownloadFileToCache(self.selectedFile.text)
+      
+      #local path
+      tempDir=os.path.join(os.path.expanduser('~'),'temp')
+      if not os.path.isdir(tempDir):
+          os.mkdir(tempDir)
+      localPath=os.path.join(tempDir,self.currentRemoteDir[-1])
+
+      print(localPath)
+
+      #remote path
+      remotePath=self.fb.GetRootUrl()+'/'+'/'.join(self.currentRemoteDir)
+      print(remotePath)
+
+      #copy over
+      self.fb.readFileToFile(remotePath,localPath)
+      
+      #do slicer magic
       slicer.util.loadNodeFromFile(localPath,self.fileTypeSelector.currentText,
       slicer.util.loadNodeFromFile(localPath,self.fileTypeSelector.currentText,
         properties,returnNode=False)
         properties,returnNode=False)
-      if not self.keepCachedFileCheckBox.isChecked():
-              os.remove(localPath)
+      
+      #if not self.keepCachedFileCheckBox.isChecked():
+      os.remove(localPath)
 
 
   def onLoadDirButtonClicked(self):
   def onLoadDirButtonClicked(self):
-    #dir=self.network.loadDir(self.selectedFile.text)
-    dir=self.selectedFile.text
-    try:
-        self.loadDicomLogic.load(self.network,dir)
-    except:
-        self.loadDicomLogic=loadDicom.loadDicomLogic(self)
-        self.loadDicomLogic.load(self.network,dir)
+
+    print('Not implemented')
 
 
 # labkeySlicerPythonExtensionLogic
 # labkeySlicerPythonExtensionLogic
 #
 #
@@ -524,3 +647,45 @@ def getHomeDir():
     except:
     except:
       fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
       fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
       return fhome
       return fhome
+
+
+def loadLibrary(name):
+    #load library from git, store it at a default location and return path to the stored location
+    remoteSources={
+            "labkeyInterface":\
+                    "http://wiscigt.powertheword.com/labkey/labkeyinterface/-/archive/master/labkeyinterface-master.zip"
+    }
+    #two steps:
+    #1 Download
+
+    tempDir=os.path.join(os.path.expanduser('~'),'temp')
+    if not os.path.isdir(tempDir):
+        os.mkdir(tempDir)
+    tempFile=os.path.join(tempDir,name+'.zip')
+    
+    http = urllib3.PoolManager()
+    r = http.request('GET', remoteSources[name], preload_content=False)
+    chunk_size=65536 
+    with open(tempFile, 'wb') as out:
+        while True:
+            data = r.read(chunk_size)
+            if not data:
+                break
+            out.write(data)
+
+    r.release_conn()
+    
+    #2 Unzip
+    installDir=os.path.join(os.path.expanduser('~'),'.labkey','software','src')
+    if not os.path.isdir(installDir):
+        os.makedirs(installDir)
+    
+    with zipfile.ZipFile(tempFile,'r') as zip_ref:
+        zip_ref.extractall(installDir)
+    #cleanup
+    os.remove(tempFile)
+
+    zipName=name.lower()+'-master'
+    os.rename(os.path.join(installDir,zipName),os.path.join(installDir,name))
+
+    return os.path.join(installDir,name)

+ 0 - 442
utils/resample.py

@@ -1,442 +0,0 @@
-import slicer
-import vtk
-import os
-from slicer.ScriptedLoadableModule import *
-import ctk
-import qt
-
-class resample(ScriptedLoadableModule):
-  """Uses ScriptedLoadableModule base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-  def __init__(self, parent):
-    ScriptedLoadableModule.__init__(self, parent)
-    parent.title = "Resample"
-    parent.categories = ["LabKey"]
-    parent.dependencies = []
-    parent.contributors = ["Andrej Studen (FMF/JSI)"] # replace with "Firstname Lastname (Org)"
-    parent.helpText = """
-    Resample to different shapes
-    """
-    parent.acknowledgementText = """
-    This module was developed within the frame of the ARRS sponsored medical
-    physics research programe to investigate quantitative measurements of cardiac
-    function using sestamibi-like tracers
-    """ # replace with organization, grant and thanks.
-    self.parent.helpText += self.getDefaultModuleDocumentationLink()
-    self.parent = parent
-
-#
-# resampleWidget
-#
-class resampleWidget(ScriptedLoadableModuleWidget):
-  """Uses ScriptedLoadableModuleWidget base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setup(self):
-    ScriptedLoadableModuleWidget.setup(self)
-    self.logic=resampleLogic(self)
-
-    datasetCollapsibleButton = ctk.ctkCollapsibleButton()
-    datasetCollapsibleButton.text = "Dataset"
-    self.layout.addWidget(datasetCollapsibleButton)
-    # Layout within the dummy collapsible button
-    datasetFormLayout = qt.QFormLayout(datasetCollapsibleButton)
-
-    self.transformNode=qt.QLineEdit("NodeToTransform")
-    datasetFormLayout.addRow("TransformedNode:",self.transformNode)
-    self.referenceNode=qt.QLineEdit("ReferenceNode")
-    datasetFormLayout.addRow("ReferenceNode:",self.referenceNode)
-
-    self.transformButton=qt.QPushButton("Transform")
-    self.transformButton.clicked.connect(self.onTransformButtonClicked)
-    datasetFormLayout.addRow("Volume:",self.transformButton)
-
-    self.transformSegmentationButton=qt.QPushButton("Transform")
-    self.transformSegmentationButton.clicked.connect(self.onTransformSegmentationButtonClicked)
-    datasetFormLayout.addRow("Segmentation:",self.transformSegmentationButton)
-
-
-  def onTransformButtonClicked(self):
-    node=slicer.util.getFirstNodeByName(self.transformNode.text)
-    if node==None:
-        print("Transform node [{}] not found").format(self.transformNode.text)
-        return
-    refNode=slicer.util.getFirstNodeByName(self.referenceNode.text)
-    if refNode==None:
-        print("Reference node [{}] not found").format(self.referenceNode.text)
-        return
-
-    self.logic.rebinNode(node,refNode)
-
-  def onTransformSegmentationButtonClicked(self):
-
-      segNodes=slicer.util.getNodesByClass("vtkMRMLSegmentationNode")
-      segNode=None
-      for s in segNodes:
-          print ("SegmentationNode: {}").format(s.GetName())
-          if s.GetName()==self.transformNode.text:
-              segNode=s
-              break
-
-      if segNode==None:
-          print("Segmentation node [{}] not found").format(self.transformNode.text)
-          return
-
-      refNode=slicer.util.getFirstNodeByName(self.referenceNode.text)
-      if refNode==None:
-          print("Reference node [{}] not found").format(self.referenceNode.text)
-          return
-
-      self.logic.rebinSegmentation(segNode,refNode)
-
-
-
-class resampleLogic(ScriptedLoadableModuleLogic):
-  """This class should implement all the actual
-  computation done by your module.  The interface
-  should be such that other python code can import
-  this class and make use of the functionality without
-  requiring an instance of the Widget.
-  Uses ScriptedLoadableModuleLogic base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-  def __init__(self,parent):
-      ScriptedLoadableModuleLogic.__init__(self, parent)
-      try:
-          fhome=os.environ["HOME"]
-      except:
-             #in windows, the variable is called HOMEPATH
-          fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
-      self.baseLog=os.path.join(fhome,".resample")
-      if not os.path.isdir(self.baseLog):
-          os.mkdir(self.baseLog)
-
-  def printMe(self):
-      print("resampleLogic ready")
-      print("Log: {}").format(self.baseLog)
-
-
-  def cast(self,newImage,originalImage):
-      if newImage.GetPointData().GetScalars().GetDataType()==originalImage.GetPointData().GetScalars().GetDataType():
-          return newImage
-      outputType=originalImage.GetPointData().GetScalars().__class__.__name__
-      shifter=vtk.vtkImageShiftScale()
-      shifter.SetInputData(newImage)
-      if outputType=="vtkUnsignedShortArray":
-          shifter.SetOutputScalarTypeToUnsignedShort()
-      if outputType=="vtkShortArray":
-          shifter.SetOutputScalarTypeToShort()
-      shifter.SetScale(1)
-      shifter.SetShift(0)
-      shifter.Update()
-      return shifter.GetOutput()
-
-
-
-  def rebinNode(self,node,refNode):
-      #refNodeName="2SBMIRVolume19"
-      #nodeName="2SMobrVolume19"
-      #node=slicer.util.getFirstNodeByName(nodeName)
-      #refNode=slicer.util.getFirstNodeByName(refNodeName)
-      #transformNodeName="2SMobr_DF"
-      #transformNode=slicer.util.getFirstNodeByName(transformNodeName)
-      #node.SetAndObserveTransformNodeID(transformNode.GetID())
-
-      log=open(os.path.join(self.baseLog,"rebinNode.log"),"w")
-
-
-      log.write(("rebinNode: volume: {} ref: {}\n").format(node.GetName(),refNode.GetName()))
-      refImage=refNode.GetImageData()
-      n=refImage.GetNumberOfPoints()
-      refIJKtoRAS=vtk.vtkMatrix4x4()
-      refNode.GetIJKToRASMatrix(refIJKtoRAS)
-
-      nodeRAStoIJK=vtk.vtkMatrix4x4()
-      node.GetRASToIJKMatrix(nodeRAStoIJK)
-      nodeName=node.GetName()
-
-      coeff=vtk.vtkImageBSplineCoefficients()
-      coeff.SetInputData(node.GetImageData())
-      coeff.SetBorderMode(vtk.VTK_IMAGE_BORDER_CLAMP)
-      #between 3 and 5
-      coeff.SetSplineDegree(5)
-      coeff.Update()
-      #interpolation ready to use
-
-      #this is tough. COpy only links (ie. shallow copy)
-      newImage=vtk.vtkImageData()
-      newImage.DeepCopy(refNode.GetImageData())
-      newImage=self.cast(newImage,node.GetImageData())
-      newScalars=newImage.GetPointData().GetScalars()
-      #doesn't set the scalars
-      log.write(("Iterating: {} points\n").format(n))
-
-
-      for i in range(0,n):
-            refIJK=refImage.GetPoint(i)
-            refIJK=list(refIJK)
-            refIJK.append(1)
-            #shift to world coordinates to match global points
-            refPos=refIJKtoRAS.MultiplyPoint(refIJK)
-            refPos=refPos[0:3]
-            fWorld=[0,0,0]
-            #apply potential transformations
-            refNode.TransformPointToWorld(refPos,fWorld)
-
-            #now do the opposite on the target node; reuse fPos
-            nodePos=[0,0,0]
-            node.TransformPointFromWorld(fWorld,nodePos)
-            nodePos.append(1)
-            nodeIJK=nodeRAStoIJK.MultiplyPoint(nodePos)
-
-            #here we should apply some sort of interpolation
-            nodeIJK=nodeIJK[0:3]
-            v=coeff.Evaluate(nodeIJK)
-            v0=newScalars.GetTuple1(i)
-            newScalars.SetTuple1(i,v)
-            if i%10000==0:
-                log.write(("[{}]: {}->{}\n").format(i,v0,v))
-
-      #node.SetName(nodeName+"_BU")
-
-
-      newNode=slicer.vtkMRMLScalarVolumeNode()
-      newNode.SetName(nodeName+"_RS")
-      newNode.SetOrigin(refNode.GetOrigin())
-      newNode.SetSpacing(refNode.GetSpacing())
-      newNode.SetIJKToRASMatrix(refIJKtoRAS)
-
-      newNode.SetAndObserveImageData(newImage)
-      slicer.mrmlScene.AddNode(newNode)
-      log.write(("Adding node {}\n").format(newNode.GetName()))
-      log.close()
-      return newNode
-
-
-  def inMask(self,binaryRep,fpos):
-
-       local=[0,0,0]
-
-       segNode=binaryRep['node']
-       segNode.TransformPointFromWorld(fpos,local)
-
-       mask=binaryRep['mask']
-       maskWorldToImageMatrix=vtk.vtkMatrix4x4()
-       mask.GetWorldToImageMatrix(maskWorldToImageMatrix)
-       local.append(1)
-       maskIJK=maskWorldToImageMatrix.MultiplyPoint(local)
-       #mask IJK is in image coordinates. However, binaryLabelMap is a truncated
-       #version of vtkImageData, so more work is required
-       maskIJK=maskIJK[0:3]#skip last (dummy) coordinate
-       maskIJK=[r*s for r,s in zip(maskIJK,mask.GetSpacing())]
-       maskIJK=[r+c for r,c in zip(maskIJK,mask.GetOrigin())]
-
-       maskI=mask.FindPoint(maskIJK)
-       try:
-           return mask.GetPointData().GetScalars().GetTuple1(maskI)
-       except:
-           return 0
-
-  def rebinSegment(self,refNode,binaryRep):
-
-       refIJKtoRAS=vtk.vtkMatrix4x4()
-       refNode.GetIJKToRASMatrix(refIJKtoRAS)
-       refImage=refNode.GetImageData()
-
-       #create new node for each segment
-       newImage=vtk.vtkImageData()
-       newImage.DeepCopy(refNode.GetImageData())
-       n=newImage.GetNumberOfPoints()
-       newScalars=newImage.GetPointData().GetScalars()
-
-       segNode=binaryRep['node']
-       mask=binaryRep['mask']
-
-       for j in range(0,n):
-           refIJK=refImage.GetPoint(j)
-           refIJK=list(refIJK)
-           refIJK.append(1)
-
-           #shift to world coordinates to match global points
-           refPos=refIJKtoRAS.MultiplyPoint(refIJK)
-           refPos=refPos[0:3]
-           fWorld=[0,0,0]
-
-           #apply potential transformations
-           refNode.TransformPointToWorld(refPos,fWorld)
-
-           v=self.inMask(binaryRep,fWorld)
-           #print("[{}]  Setting ({}) to: {}\n").format(j,fWorld,v)
-           newScalars.SetTuple1(j,v)
-
-       newNode=slicer.vtkMRMLScalarVolumeNode()
-       newNode.SetName(segNode.GetName()+'_'+binaryRep['segId'])
-       newNode.SetOrigin(refNode.GetOrigin())
-       newNode.SetSpacing(refNode.GetSpacing())
-       newNode.SetIJKToRASMatrix(refIJKtoRAS)
-
-       newNode.SetAndObserveImageData(newImage)
-       slicer.mrmlScene.AddNode(newNode)
-       return newNode
-
-
-  def rebinSegmentation(self,segNode,refNode):
-
-       log=open(os.path.join(self.baseLog,"rebinSegmentation.log"),"w")
-
-       log.write(("rebinNode: {} {}\n").format(segNode.GetName(),refNode.GetName()))
-
-       nSeg=segNode.GetSegmentation().GetNumberOfSegments()
-       ## DEBUG:
-       #nSeg=1
-       #n=1000
-
-       for i in range(0,nSeg):
-           #segID
-           segID=segNode.GetSegmentation().GetNthSegmentID(i)
-           log.write(("Parsing segment {}").format(segNode.GetSegmentation.GetNthSegment(i).GetName()))
-           binaryRep={'node':segNode,
-                      'mask':segNode.GetBinaryLabelmapRepresentation(segID)}
-           newNode=self.rebinSegment(refNode,binaryRep)
-           log.write(("Adding node: {}").format(newNode.GetName()))
-
-       log.close()
-
-  def rebinSegmentation1(self,segNode,refNode):
-
-
-     logfile="C:\\Users\\studen\\labkeyCache\\log\\resample.log"
-     print("rebinNode: {} {}\n").format(segNode.GetName(),refNode.GetName())
-     refImage=refNode.GetImageData()
-     refIJKtoRAS=vtk.vtkMatrix4x4()
-     refNode.GetIJKToRASMatrix(refIJKtoRAS)
-     refRAStoIJK=vtk.vtkMatrix4x4()
-     refNode.GetRASToIJKMatrix(refRAStoIJK)
-
-     nSeg=segNode.GetSegmentation().GetNumberOfSegments()
-     ## DEBUG:
-     nSeg=1
-
-     for i in range(0,nSeg):
-         #segID
-         segID=segNode.GetSegmentation().GetNthSegmentID(i)
-         binaryRep={'node':segNode,
-                    'mask': segNode.GetBinaryLabelmapRepresentation(segID)}
-
-         mask=binaryRep['mask']
-         #create new node for each segment
-         newImage=vtk.vtkImageData()
-         newImage.DeepCopy(refNode.GetImageData())
-         newScalars=newImage.GetPointData().GetScalars()
-         refN=newImage.GetNumberOfPoints()
-         for k in range(0,refN):
-             newScalars.SetTuple1(k,0)
-
-         maskN=binaryRep['mask'].GetNumberOfPoints()
-         maskScalars=mask.GetPointData().GetScalars()
-         maskImageToWorldMatrix=vtk.vtkMatrix4x4()
-         binaryRep['mask'].GetImageToWorldMatrix(maskImageToWorldMatrix)
-
-         for j in range(0,maskN):
-
-             if maskScalars.GetTuple1(j)==0:
-                 continue
-
-             maskIJK=mask.GetPoint(j)
-             maskIJK=[r-c for r,c in zip(maskIJK,mask.GetOrigin())]
-             maskIJK=[r/s for r,s in zip(maskIJK,mask.GetSpacing())]
-             maskIJK.append(1)
-             maskPos=maskImageToWorldMatrix.MultiplyPoint(maskIJK)
-             maskPos=maskPos[0:3]
-             fWorld=[0,0,0]
-             #apply segmentation transformation
-             segNode.TransformPointToWorld(maskPos,fWorld)
-
-             refPos=[0,0,0]
-
-             #apply potential reference transformations
-             refNode.TransformPointFromWorld(fWorld,refPos)
-             refPos.append(1)
-             refIJK=refRAStoIJK.MultiplyPoint(refPos)
-             refIJK=refIJK[0:3]
-             i1=newImage.FindPoint(refIJK)
-             if i1<0:
-                 continue
-             if i1<refN:
-                 newScalars.SetTuple1(i1,1)
-
-         newNode=slicer.vtkMRMLScalarVolumeNode()
-         newNode.SetName(segNode.GetName()+'_'+segNode.GetSegmentation().GetNthSegmentID(i))
-         newNode.SetOrigin(refNode.GetOrigin())
-         newNode.SetSpacing(refNode.GetSpacing())
-         newNode.SetIJKToRASMatrix(refIJKtoRAS)
-
-         newNode.SetAndObserveImageData(newImage)
-         slicer.mrmlScene.AddNode(newNode)
-
-
-
-
-class resampleTest(ScriptedLoadableModuleTest):
-  """
-  This is the test case for your scripted module.
-  Uses ScriptedLoadableModuleTest base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setUp(self):
-    """ Do whatever is needed to reset the state - typically a scene clear will be enough.
-    """
-    slicer.mrmlScene.Clear(0)
-    refNodeName="2SBMIRVolume19"
-    nodeName="2SMobrVolume19"
-    transformNodeName="2SMobr_DF"
-    path="c:\\Users\\studen\\labkeyCache\\dinamic_spect\\Patients\\@files"
-
-    refPath=os.path.join(path,"2SBMIR")
-    refPath=os.path.join(refPath,refNodeName+".nrrd")
-    slicer.util.loadNodeFromFile(refPath,'VolumeFile')
-
-    transformPath=os.path.join(path,"2SMobr")
-    transformPath=os.path.join(transformPath,transformNodeName+".h5")
-    slicer.util.loadNodeFromFile(transformPath,'TransformFile')
-
-    nodePath=os.path.join(path,"2SMobr")
-    nodePath=os.path.join(nodePath,nodeName+".nrrd")
-
-    slicer.util.loadNodeFromFile(nodePath,'VolumeFile')
-
-    self.node=slicer.util.getFirstNodeByName(nodeName)
-    self.refNode=slicer.util.getFirstNodeByName(refNodeName)
-    self.transformNode=slicer.util.getFirstNodeByName(transformNodeName)
-    self.node.SetAndObserveTransformNodeID(self.transformNode.GetID())
-
-    self.resampler=resampleLogic(None)
-
-  def runTest(self):
-    """Run as few or as many tests as needed here.
-    """
-    self.setUp()
-    self.test_resample()
-
-  def test_resample(self):
-    """ Ideally you should have several levels of tests.  At the lowest level
-    tests should exercise the functionality of the logic with different inputs
-    (both valid and invalid).  At higher levels your tests should emulate the
-    way the user would interact with your code and confirm that it still works
-    the way you intended.
-    One of the most important features of the tests is that it should alert other
-    developers when their changes will have an impact on the behavior of your
-    module.  For example, if a developer removes a feature that you depend on,
-    your test should break so they know that the feature is needed.
-    """
-
-    self.delayDisplay("Starting the test")
-    #
-    # first, get some data
-    #
-    self.resampler.rebinNode(self.node,self.refNode)
-
-    self.delayDisplay('Test passed!')