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