#!/usr/bin/env python """ binoculars gui for data processing Created on 2015-06-04 author: Remy Nencib (remy.nencib@esrf.r) """ import sys import os import time from PyQt4 import QtGui, QtCore def set_src(): import sys import os.path as osp dirpath = osp.join(osp.dirname(osp.abspath(__file__)), osp.pardir) sys.path.insert(0, osp.abspath(dirpath)) try: import binoculars.main import binoculars.util except ImportError: # try to use code from src distribution set_src() import binoculars.main import binoculars.util #--------------------------------------------CREATE MAIN WINDOW---------------------------------------- class Window(QtGui.QMainWindow): def __init__(self): super(Window, self).__init__() self.initUI() self.tab_widget = QtGui.QTabWidget(self) self.setCentralWidget(self.tab_widget) # add the close button for tabs close = self.tab_widget.setTabsClosable(True) self.tab_widget.tabCloseRequested.connect(self.close_tab) #method for close tabs def close_tab(self, tab): self.tab_widget.removeTab(tab) def initUI(self): #we create the menu bar openFile = QtGui.QAction('Open', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Open new File') openFile.triggered.connect(self.ShowFile) saveFile = QtGui.QAction('Save', self) saveFile.setShortcut('Ctrl+S') saveFile.setStatusTip('Save File') saveFile.triggered.connect(self.Save) Create = QtGui.QAction('Create', self) Create.setStatusTip('Create Configfile') Create.triggered.connect(self.New_Config) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(openFile) fileMenu.addAction(saveFile) fileMenu = menubar.addMenu('&New Configfile') fileMenu.addAction(Create) #we configue the main windows palette = QtGui.QPalette() palette.setColor(QtGui.QPalette.Background, QtCore.Qt.gray) self.setPalette(palette) self.setGeometry(50, 100, 700, 700) self.setWindowTitle('Binoculars processgui') self.show() self.ListCommand = QtGui.QTableWidget(1, 2, self) self.ListCommand.verticalHeader().setVisible(True) self.ListCommand.horizontalHeader().setVisible(False) self.ListCommand.horizontalHeader().stretchSectionCount() self.ListCommand.setColumnWidth(0, 80) self.ListCommand.setColumnWidth(1, 80) self.ListCommand.setRowCount(0) self.buttonDelete = QtGui.QPushButton('Delete', self) self.connect(self.buttonDelete, QtCore.SIGNAL("clicked()"), self.removeConf) self.process = QtGui.QPushButton('run', self) self.process.setStyleSheet("background-color: darkred") self.connect(self.process, QtCore.SIGNAL("clicked()"), self.run) self.wid = QtGui.QWidget() self.CommandLayout = QtGui.QVBoxLayout() self.CommandLayout.addWidget(self.ListCommand) self.CommandLayout.addWidget(self.process) self.CommandLayout.addWidget(self.buttonDelete) self.wid.setLayout(self.CommandLayout) self.Dock = QtGui.QDockWidget() self.Dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea) self.Dock.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures) self.Dock.setWidget(self.wid) self.Dock.setMaximumWidth(200) self.Dock.setMinimumWidth(200) self.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.Dock) def removeConf(self): self.ListCommand.removeRow(self.ListCommand.currentRow()) def Add_To_Liste(self, xxx_todo_changeme): (command, cfg) = xxx_todo_changeme row = self.ListCommand.rowCount() index = self.tab_widget.currentIndex() filename = self.tab_widget.tabText(index) self.ListCommand.insertRow(self.ListCommand.rowCount()) dic = {filename: cfg} self.item1 = QtGui.QTableWidgetItem(str(command)) self.item1.command = command self.item2 = QtGui.QTableWidgetItem(str(filename)) self.item2.cfg = dic[filename] self.ListCommand.setItem(row, 0, self.item1) self.ListCommand.setItem(row, 1, self.item2) #We run the script and create a hdf5 file def run(self): maximum = self.ListCommand.rowCount() pd = QtGui.QProgressDialog('running', 'Cancel', 0, maximum, self) pd.setWindowModality(QtCore.Qt.WindowModal) pd.show() def progress(cfg, command): if pd.wasCanceled(): raise KeyboardInterrupt QtGui.QApplication.processEvents() return binoculars.main.Main.from_object(cfg, command) try: for index in range(self.ListCommand.rowCount()): pd.setValue(index) cfg = self.ListCommand.item(index, 1).cfg command = self.ListCommand.item(index, 0).command print(cfg) progress(cfg, command) self.ListCommand.clear() self.ListCommand.setRowCount(0) except BaseException as e: #cfg = self.ListCommand.item(index,1).cfg #print cfg QtGui.QMessageBox.about(self, "Error", "There was an error processing one of the scans: {0}".format(e)) finally: pd.close() #we call the load function def ShowFile(self): filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File', '') confwidget = Conf_Tab(self) confwidget.read_data(str(filename)) newIndex = self.tab_widget.addTab(confwidget, os.path.basename(str(filename))) QtCore.QObject.connect(confwidget, QtCore.SIGNAL("command"), self.Add_To_Liste) self.tab_widget.setCurrentIndex(newIndex) #we call the save function def Save(self): filename = QtGui.QFileDialog().getSaveFileName(self, 'Save', '', '*.txt') widget = self.tab_widget.currentWidget() widget.save(filename) #we call the new tab conf def New_Config(self): widget = Conf_Tab(self) self.tab_widget.addTab(widget, 'New configfile') QtCore.QObject.connect(widget, QtCore.SIGNAL("command"), self.Add_To_Liste) #---------------------------------------------------------------------------------------------------- #-----------------------------------------CREATE TABLE----------------------------------------------- class Table(QtGui.QWidget): def __init__(self, label, parent=None): super(Table, self).__init__() # create a QTableWidget self.table = QtGui.QTableWidget(1, 2, self) self.table.setHorizontalHeaderLabels(['Parameter', 'Value', 'Comment']) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.table.setTextElideMode(QtCore.Qt.ElideLeft) #create combobox self.combobox = QtGui.QComboBox() #add items self.cell = QtGui.QTableWidgetItem(QtCore.QString("type")) self.table.setItem(0, 0, self.cell) self.table.setCellWidget(0, 1, self.combobox) #we create pushbuttons and we call the method when we clic on self.btn_add_row = QtGui.QPushButton('+', self) self.connect(self.btn_add_row, QtCore.SIGNAL('clicked()'), self.add_row) self.buttonRemove = QtGui.QPushButton('-', self) self.connect(self.buttonRemove, QtCore.SIGNAL("clicked()"), self.remove) #the dispositon of the table and the butttons vbox = QtGui.QVBoxLayout() hbox = QtGui.QHBoxLayout() hbox.addWidget(self.btn_add_row) hbox.addWidget(self.buttonRemove) vbox.addWidget(label) vbox.addLayout(hbox) vbox.addWidget(self.table) self.setLayout(vbox) def add_row(self): self.table.insertRow(self.table.rowCount()) def remove(self): self.table.removeRow(self.table.currentRow()) def get_keys(self): return list(str(self.table.item(index, 0).text()) for index in range(self.table.rowCount())) #Here we take all values from tables def getParam(self): for index in range(self.table.rowCount()): if not self.table.item == None: key = str(self.table.item(index, 0).text()) comment = str(self.table.item(index, 0).toolTip()) if index == 0: yield key, str(self.table.cellWidget(index, 1).currentText()), comment elif self.table.item(index, 1): if len(str(self.table.item(index, 1).text())) != 0 and self.table.item(index, 0).textColor() == QtGui.QColor('black'): yield key, str(self.table.item(index, 1).text()), comment #Here we put all values in tables def addData(self, cfg): for item in cfg: if item == 'type': box = self.table.cellWidget(0, 1) value = cfg[item].split(':') if len(value) > 1: box.setCurrentIndex(box.findText(value[1], QtCore.Qt.MatchFixedString)) else: box.setCurrentIndex(box.findText(cfg[item], QtCore.Qt.MatchFixedString)) elif item not in self.get_keys(): self.add_row() row = self.table.rowCount() for col in range(self.table.columnCount()): if col == 0: newitem = QtGui.QTableWidgetItem(item) self.table.setItem(row - 1, col, newitem) if col == 1: newitem2 = QtGui.QTableWidgetItem(cfg[item]) self.table.setItem(row - 1, col, newitem2) else: index = self.get_keys().index(item) self.table.item(index, 1).setText(cfg[item]) def addDataConf(self, options): keys = self.get_keys() newconfigs = dict((option[0], '') for option in options if option[0] not in keys) self.addData(newconfigs) names = list(option[0] for option in options) for index, key in enumerate(self.get_keys()): if str(key) in names: self.table.item(index, 0).setTextColor(QtGui.QColor('black')) self.table.item(index, 0).setToolTip(options[names.index(key)][1]) elif str(key) == 'type': self.table.item(index, 0).setTextColor(QtGui.QColor('black')) else: self.table.item(index, 0).setTextColor(QtGui.QColor('gray')) def add_to_combo(self, items): self.combobox.clear() self.combobox.addItems(items) #---------------------------------------------------------------------------------------------------- #-----------------------------------------CREATE CONFIG---------------------------------------------- class Conf_Tab(QtGui.QWidget): def __init__(self, parent=None): super(Conf_Tab, self).__init__() #we create 3 tables self.Dis = Table(QtGui.QLabel('Dispatcher :')) self.Inp = Table(QtGui.QLabel('Input :')) self.Pro = Table(QtGui.QLabel('Projection :')) self.select = QtGui.QComboBox() backends = list(backend.lower() for backend in binoculars.util.get_backends()) #we add the list of different backends on the select combobox self.select.addItems(QtCore.QStringList(backends)) self.add = QtGui.QPushButton('add') self.connect(self.add, QtCore.SIGNAL("clicked()"), self.AddCommand) self.scan = QtGui.QLineEdit() self.scan.setToolTip('scan selection example: 820 824') vbox = QtGui.QVBoxLayout() hbox = QtGui.QHBoxLayout() splitter = QtGui.QSplitter(QtCore.Qt.Horizontal) splitter.addWidget(self.Dis) splitter.addWidget(self.Inp) splitter.addWidget(self.Pro) hbox.addWidget(splitter) commandbox = QtGui.QHBoxLayout() commandbox.addWidget(self.add) commandbox.addWidget(self.scan) vbox.addWidget(self.select) vbox.addLayout(hbox) vbox.addLayout(commandbox) #the dispositon of all elements of the gui #Layout = QtGui.QGridLayout() #Layout.addWidget(label1,1,1,1,2) #Layout.addWidget(label2,1,0,1,2) #Layout.addWidget(label3,1,2,1,2) #Layout.addWidget(self.select,0,0) #Layout.addWidget(self.Dis,2,1) #Layout.addWidget(self.Inp,2,0) #Layout.addWidget(self.Pro,2,2) #Layout.addWidget(self.add,3,0) #Layout.addWidget(self.scan,3,1) self.setLayout(vbox) #Here we call all methods for selected an ellement on differents combobox self.Dis.add_to_combo(QtCore.QStringList(binoculars.util.get_dispatchers())) self.select.activated['QString'].connect(self.DataCombo) self.Inp.combobox.activated.connect(self.DataTableInp) self.Pro.combobox.activated.connect(self.DataTableInpPro) self.Dis.combobox.activated.connect(self.DataTableInpDis) def DataCombo(self, text): self.Inp.add_to_combo(QtCore.QStringList(binoculars.util.get_inputs(str(text)))) self.Pro.add_to_combo(QtCore.QStringList(binoculars.util.get_projections(str(text)))) self.DataTableInp() self.DataTableInpPro() self.DataTableInpDis() def DataTableInp(self): backend = str(self.select.currentText()) inp = binoculars.util.get_input_configkeys(backend, str(self.Inp.combobox.currentText())) self.Inp.addDataConf(inp) def DataTableInpPro(self): backend = str(self.select.currentText()) proj = binoculars.util.get_projection_configkeys(backend, str(self.Pro.combobox.currentText())) self.Pro.addDataConf(proj) def DataTableInpDis(self): backend = str(self.select.currentText()) disp = binoculars.util.get_dispatcher_configkeys(str(self.Dis.combobox.currentText())) self.Dis.addDataConf(disp) #The save method we take all ellements on tables and we put them in this format {0} = {1} #{2} def save(self, filename): with open(filename, 'w') as fp: fp.write('[dispatcher]\n') # cycles over the iterator object for key, value, comment in self.Dis.getParam(): fp.write('{0} = {1} #{2}\n'.format(key, value, comment)) fp.write('[input]\n') for key, value, comment in self.Inp.getParam(): if key == 'type': value = '{0}:{1}'.format(self.select.currentText(), value) fp.write('{0} = {1} #{2}\n'.format(key, value, comment)) fp.write('[projection]\n') for key, value, comment in self.Pro.getParam(): if key == 'type': value = '{0}:{1}'.format(self.select.currentText(), value) fp.write('{0} = {1} #{2}\n'.format(key, value, comment)) #This method take the name of objects and values for run the script def get_configobj(self): inInp = {} inDis = {} inPro = {} inDis = dict((key, value) for key, value, comment in self.Dis.getParam()) for key, value, comment in self.Inp.getParam(): if key == 'type': value = '{0}:{1}'.format(str(self.select.currentText()).strip(), value) inInp[key] = value for key, value, comment in self.Pro.getParam(): if key == 'type': value = '{0}:{1}'.format(str(self.select.currentText()).strip(), value) inPro[key] = value cfg = binoculars.util.ConfigFile('processgui {0}'.format(time.strftime('%d %b %Y %H:%M:%S', time.localtime()))) setattr(cfg, 'input', inInp) setattr(cfg, 'dispatcher', inDis) setattr(cfg, 'projection', inPro) return cfg #This method take elements on a text file or the binocular script and put them on tables def read_data(self, filename): cfg = binoculars.util.ConfigFile.fromtxtfile(str(filename)) input_type = cfg.input['type'] backend, value = input_type.strip(' ').split(':') self.select.setCurrentIndex(self.select.findText(backend, QtCore.Qt.MatchFixedString)) self.DataCombo(backend) self.Dis.addData(cfg.dispatcher) self.Inp.addData(cfg.input) self.Pro.addData(cfg.projection) #we add command on the DockWidget def AddCommand(self): scan = [str(self.scan.text())] cfg = self.get_configobj() commandconfig = (scan, cfg) self.emit(QtCore.SIGNAL('command'), commandconfig) if __name__ == '__main__': app = QtGui.QApplication(sys.argv) main = Window() main.show() sys.exit(app.exec_())