From 555763dd8fba59a6fa5332d1faabef3076e925de Mon Sep 17 00:00:00 2001
From: Sinisa Veseli <sveseli@aps.anl.gov>
Date: Mon, 6 Mar 2017 22:02:49 +0000
Subject: [PATCH] adding skeleton for station gui

---
 bin/dm-station-gui                            | 18 ++++++
 .../dm/aps_beamline_tools/gui/__init__.py     |  1 +
 .../dm/aps_beamline_tools/gui/daqsTab.py      | 37 ++++++++++++
 .../dm/aps_beamline_tools/gui/dmApiFactory.py | 44 ++++++++++++++
 .../dm/aps_beamline_tools/gui/dmStationUi.py  | 58 +++++++++++++++++++
 .../aps_beamline_tools/gui/experimentsTab.py  | 36 ++++++++++++
 .../dm/aps_beamline_tools/gui/uploadsTab.py   | 35 +++++++++++
 .../dm/common/utility/configurationManager.py | 18 ++++++
 .../daq_web_service/api/experimentDaqApi.py   |  4 +-
 .../dm/ds_web_service/api/dsRestApiFactory.py |  7 +--
 10 files changed, 251 insertions(+), 7 deletions(-)
 create mode 100755 bin/dm-station-gui
 create mode 100644 src/python/dm/aps_beamline_tools/gui/__init__.py
 create mode 100644 src/python/dm/aps_beamline_tools/gui/daqsTab.py
 create mode 100755 src/python/dm/aps_beamline_tools/gui/dmApiFactory.py
 create mode 100755 src/python/dm/aps_beamline_tools/gui/dmStationUi.py
 create mode 100644 src/python/dm/aps_beamline_tools/gui/experimentsTab.py
 create mode 100644 src/python/dm/aps_beamline_tools/gui/uploadsTab.py

diff --git a/bin/dm-station-gui b/bin/dm-station-gui
new file mode 100755
index 00000000..55325469
--- /dev/null
+++ b/bin/dm-station-gui
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Run command
+
+if [ -z $DM_ROOT_DIR ]; then
+    cd `dirname $0` && myDir=`pwd`
+    setupFile=$myDir/../setup.sh
+    if [ ! -f $setupFile ]; then
+        echo "Cannot find setup file: $setupFile"
+        exit 1
+    fi
+    source $setupFile > /dev/null
+fi
+source $DM_ROOT_DIR/bin/dm_command_setup.sh
+
+eval "$DM_ROOT_DIR/src/python/dm/aps_beamline_tools/gui/dmStationUi.py $DM_COMMAND_ARGS"
+
+
diff --git a/src/python/dm/aps_beamline_tools/gui/__init__.py b/src/python/dm/aps_beamline_tools/gui/__init__.py
new file mode 100644
index 00000000..63426004
--- /dev/null
+++ b/src/python/dm/aps_beamline_tools/gui/__init__.py
@@ -0,0 +1 @@
+__version__ = "1.1 (2017.03.01)"
diff --git a/src/python/dm/aps_beamline_tools/gui/daqsTab.py b/src/python/dm/aps_beamline_tools/gui/daqsTab.py
new file mode 100644
index 00000000..1da1ab47
--- /dev/null
+++ b/src/python/dm/aps_beamline_tools/gui/daqsTab.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+import wx
+from dmApiFactory import DmApiFactory
+ 
+# Define the DAQs tab content:
+class DaqsTab(wx.ListCtrl):
+    def __init__(self, stationName, parent, id=-1):
+        wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT)
+        self.stationName = stationName
+        self.experimentDaqApi = DmApiFactory.getInstance().getExperimentDaqApi()
+
+        self.InsertColumn(0, 'Id')
+        self.InsertColumn(2, 'Data Directory')
+        self.InsertColumn(3, '# Files')
+
+        self.SetColumnWidth(0, 150)
+        self.SetColumnWidth(1, 350)
+        self.SetColumnWidth(2, 250)
+
+        self.updateList()
+
+    def updateList(self):
+        self.daqList = self.experimentDaqApi.listDaqs()
+
+        i = 0
+        for daq in self.daqList:
+            print daq
+            self.InsertStringItem(i, daq.get('id'))
+            self.SetStringItem(i, 1, daq.get('dataDirectory', ''))
+            self.SetStringItem(i, 2, str(daq.get('nFiles', '0')))
+            if (i % 2) == 0:
+                self.SetItemBackgroundColour(i, '#e6f1f5')
+            i += 1
+
+ 
+
diff --git a/src/python/dm/aps_beamline_tools/gui/dmApiFactory.py b/src/python/dm/aps_beamline_tools/gui/dmApiFactory.py
new file mode 100755
index 00000000..de3b6571
--- /dev/null
+++ b/src/python/dm/aps_beamline_tools/gui/dmApiFactory.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+from dm.common.utility.singleton import Singleton
+from dm.common.utility.loggingManager import LoggingManager
+from dm.common.utility.configurationManager import ConfigurationManager
+
+class DmApiFactory(Singleton):
+
+
+    def __init__(self):
+        self.__configure()
+
+    def __configure(self):
+        self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__)
+        configManager = ConfigurationManager.getInstance()
+        (self.username,self.password) = configManager.parseLoginFile()
+        self.protocol = configManager.getWebServiceProtocol()
+        self.dsHost = configManager.getDsWebServiceHost()
+        self.dsPort = configManager.getDsWebServicePort()
+        self.daqHost = configManager.getDaqWebServiceHost()
+        self.daqPort = configManager.getDaqWebServicePort()
+
+    def getUserDsApi(self):
+        from dm.ds_web_service.api.userDsApi import UserDsApi
+        api = UserDsApi(self.username, self.password, self.dsHost, self.dsPort, self.protocol)
+        return api
+
+    def getExperimentDsApi(self):
+        from dm.ds_web_service.api.experimentDsApi import ExperimentDsApi
+        api = ExperimentDsApi(self.username, self.password, self.dsHost, self.dsPort, self.protocol)
+        return api
+
+    def getExperimentDaqApi(self):
+        from dm.daq_web_service.api.experimentDaqApi import ExperimentDaqApi
+        api = ExperimentDaqApi(self.username, self.password, self.daqHost, self.daqPort, self.protocol)
+        return api
+
+
+####################################################################
+# Testing
+
+if __name__ == '__main__':
+    pass
+
diff --git a/src/python/dm/aps_beamline_tools/gui/dmStationUi.py b/src/python/dm/aps_beamline_tools/gui/dmStationUi.py
new file mode 100755
index 00000000..bd2926cc
--- /dev/null
+++ b/src/python/dm/aps_beamline_tools/gui/dmStationUi.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+import sys
+import wx
+
+from dm.common.constants import dmStatus
+from dm.common.exceptions.dmException import DmException
+from dm.common.exceptions.configurationError import ConfigurationError
+from dm.common.utility.loggingManager import LoggingManager
+from dm.common.utility.configurationManager import ConfigurationManager
+
+from experimentsTab import ExperimentsTab
+from daqsTab import DaqsTab
+from uploadsTab import UploadsTab
+ 
+class DmStationUi(wx.Frame):
+    def __init__(self):
+        self.__configure()
+        self.logger.debug('Starting UI for DM Station: %s' % self.stationName)
+        wx.Frame.__init__(self, None, title='DM Station: %s' % self.stationName, size=(900,500))
+ 
+        # Create a panel and notebook (tabs holder)
+        p = wx.Panel(self)
+        nb = wx.Notebook(p)
+ 
+        # Create the tab windows
+        experimentsTab = ExperimentsTab(self.stationName, nb)
+        daqsTab = DaqsTab(self.stationName, nb)
+        uploadsTab = UploadsTab(self.stationName, nb)
+ 
+        # Add the windows to tabs and name them.
+        nb.AddPage(experimentsTab, "Experiments")
+        nb.AddPage(daqsTab, "Real Time DAQs")
+        nb.AddPage(uploadsTab, "Data Uploads")
+ 
+        # Set noteboook in a sizer to create the layout
+        sizer = wx.BoxSizer()
+        sizer.Add(nb, 1, wx.EXPAND)
+        p.SetSizer(sizer)
+
+    def __configure(self):
+        self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__)
+        configManager = ConfigurationManager.getInstance()
+        self.stationName = configManager.getInstance().getStationName()
+        if not self.stationName:
+            raise ConfigurationError('DM_STATION_NAME environment variable is not defined.')
+ 
+if __name__ == "__main__":
+    try:
+        app = wx.App()
+        DmStationUi().Show()
+        app.MainLoop()
+    except DmException, ex:
+        print >>sys.stderr, 'ERROR: %s' % ex
+        raise SystemExit(ex.getErrorCode())
+    except Exception, ex:
+        print >>sys.stderr, '%s' % ex
+        raise SystemExit(dmStatus.DM_ERROR)
diff --git a/src/python/dm/aps_beamline_tools/gui/experimentsTab.py b/src/python/dm/aps_beamline_tools/gui/experimentsTab.py
new file mode 100644
index 00000000..a4b28474
--- /dev/null
+++ b/src/python/dm/aps_beamline_tools/gui/experimentsTab.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+import wx
+from dmApiFactory import DmApiFactory
+ 
+# Define the experiments tab content:
+class ExperimentsTab(wx.ListCtrl):
+    def __init__(self, stationName, parent, id=-1):
+        wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT)
+        self.stationName = stationName
+        self.experimentDsApi = DmApiFactory.getInstance().getExperimentDsApi()
+
+        self.InsertColumn(0, 'Name')
+        self.InsertColumn(1, 'Description')
+        self.InsertColumn(2, 'Start Date')
+
+        self.SetColumnWidth(0, 150)
+        self.SetColumnWidth(1, 500)
+        self.SetColumnWidth(2, 250)
+
+        self.updateList()
+
+    def updateList(self):
+        self.experimentList = self.experimentDsApi.getExperimentsByStation(self.stationName)
+
+        i = 0
+        for experiment in self.experimentList:
+            self.InsertStringItem(i, experiment.get('name'))
+            self.SetStringItem(i, 1, experiment.get('description', ''))
+            self.SetStringItem(i, 2, str(experiment.get('startDate', '')))
+            if (i % 2) == 0:
+                self.SetItemBackgroundColour(i, '#e6f1f5')
+            i += 1
+
+
+
diff --git a/src/python/dm/aps_beamline_tools/gui/uploadsTab.py b/src/python/dm/aps_beamline_tools/gui/uploadsTab.py
new file mode 100644
index 00000000..1ed425d1
--- /dev/null
+++ b/src/python/dm/aps_beamline_tools/gui/uploadsTab.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+import wx
+from dmApiFactory import DmApiFactory
+ 
+# Define the experiments tab content:
+class UploadsTab(wx.ListCtrl):
+    def __init__(self, stationName, parent, id=-1):
+        wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT)
+        self.stationName = stationName
+        self.experimentDaqApi = DmApiFactory.getInstance().getExperimentDaqApi()
+
+        self.InsertColumn(0, 'Id')
+        self.InsertColumn(2, 'Data Directory')
+        self.InsertColumn(3, '# Files')
+
+        self.SetColumnWidth(0, 150)
+        self.SetColumnWidth(1, 350)
+        self.SetColumnWidth(2, 250)
+
+        self.updateList()
+
+    def updateList(self):
+        self.uploadList = self.experimentDaqApi.listUploads()
+
+        i = 0
+        for upload in self.uploadList:
+            self.InsertStringItem(i, upload.get('id'))
+            self.SetStringItem(i, 1, upload.get('dataDirectory', ''))
+            self.SetStringItem(i, 2, str(upload.get('nFiles', '0')))
+            if (i % 2) == 0:
+                self.SetItemBackgroundColour(i, '#e6f1f5')
+            i += 1
+ 
+
diff --git a/src/python/dm/common/utility/configurationManager.py b/src/python/dm/common/utility/configurationManager.py
index 09c20cd2..af29ba51 100755
--- a/src/python/dm/common/utility/configurationManager.py
+++ b/src/python/dm/common/utility/configurationManager.py
@@ -924,6 +924,24 @@ class ConfigurationManager(UserDict.UserDict):
     def hasBeamlineManagers(self):
         return self.has_key('beamlineManagers')
 
+    # Parse given login file for username/password
+    # Assume form <username><delimiter><password>
+    def parseLoginFile(self, loginFile=None, delimiter='|'):
+        username = None
+        password = None
+        if not loginFile:
+            loginFile = self.getLoginFile()
+        if not loginFile:
+            raise ConfigurationError('DM login file is not defined.')
+        try:
+            tokenList = open(loginFile).readline().split(delimiter)
+            if len(tokenList) == 2:
+                username = tokenList[0].strip()
+                password = tokenList[1].strip()
+        except Exception, ex:
+            raise ConfigurationError('Cannot parse login file %s: ex.' % (loginFile, ex))
+        return (username,password)
+
 #######################################################################
 # Testing.
 
diff --git a/src/python/dm/daq_web_service/api/experimentDaqApi.py b/src/python/dm/daq_web_service/api/experimentDaqApi.py
index cb68f542..4dc9f83f 100755
--- a/src/python/dm/daq_web_service/api/experimentDaqApi.py
+++ b/src/python/dm/daq_web_service/api/experimentDaqApi.py
@@ -239,7 +239,7 @@ class ExperimentDaqApi(DaqRestApi):
 
         :raises DmException: in case of any other errors
 
-        >>> uplaodInfo = api.getUploadInfo('84311a75-c88b-4605-8948-08257eae6f5c')
+        >>> uploadInfo = api.getUploadInfo('84311a75-c88b-4605-8948-08257eae6f5c')
         >>> uploadStatus = uploadInfo.get('status')
         '''
 
@@ -292,7 +292,7 @@ class ExperimentDaqApi(DaqRestApi):
 
         :raises DmException: in case of any other errors
 
-        >>> uplaodInfo = api.stopUpload('84311a75-c88b-4605-8948-08257eae6f5c')
+        >>> uploadInfo = api.stopUpload('84311a75-c88b-4605-8948-08257eae6f5c')
         >>> print uploadInfo.get('nCompletedFiles')
         '''
         url = '%s/experimentUploads/stopUpload/%s' % (self.getContextRoot(),id)
diff --git a/src/python/dm/ds_web_service/api/dsRestApiFactory.py b/src/python/dm/ds_web_service/api/dsRestApiFactory.py
index 2b39f81b..e74c1700 100755
--- a/src/python/dm/ds_web_service/api/dsRestApiFactory.py
+++ b/src/python/dm/ds_web_service/api/dsRestApiFactory.py
@@ -52,11 +52,7 @@ class DsRestApiFactory:
     @classmethod
     def getExperimentDsApi(cls):
         from experimentDsApi import ExperimentDsApi
-        try:
-            (username, password, host, port, protocol) = cls.__getConfiguration()
-        except Exception, ex:
-            print ex
-            raise
+        (username, password, host, port, protocol) = cls.__getConfiguration()
         api = ExperimentDsApi(username, password, host, port, protocol)
         return api
 
@@ -66,6 +62,7 @@ class DsRestApiFactory:
         (username, password, host, port, protocol) = cls.__getConfiguration()
         api = FileDsApi(username, password, host, port, protocol)
         return api
+
 ####################################################################
 # Testing
 
-- 
GitLab