class TestDialog(QDialog): def __init__(self, nlist_0, nlist_1): super(TestDialog, self).__init__() self.emsg = QErrorMessage(self) self.emsg.setWindowModality(Qt.WindowModal) self.emsg.children()[2].setVisible(False) data0 = self.dir_scan(nlist_0, "*.f90") nl_1 = deepcopy(data0) data1 = self.namelist_scan(nlist_1, nl_1) # TODO: need to make sure that all nam_block entries have same nam_items cols = ["col0", "col1"] # Copy input data for manipulation self.data = {} self.data["col0"] = deepcopy(data0) self.data["col1"] = deepcopy(data1) # TreeView for each data set self.tree = {} for col in cols: self.tree[col] = QTreeView() # Layout btOk = QPushButton("OK") btCancel = QPushButton("Cancel") btSearch = QPushButton("Search") self.searchInput = QLineEdit() # Search Box self.searchInput.setText( QCoreApplication.translate("Find a nam_block or nam_item", "Enter search text here")) btSearch.setToolTip( QCoreApplication.translate( "Find a nam_block or nam_item", "Enter search text here, press ENTER again to go to next match!", )) btSearch.clicked.connect(self.searchItem) # First row hbox1 = QHBoxLayout() hbox1.addStretch(1) hbox1.addWidget(btSearch, 100) # self.connect(self.btSearch, SIGNAL("returnPressed()"), self.searchItem) hbox1.addWidget(self.searchInput) # hbox1.addWidget(btSearch) hbox1.addWidget(btOk) hbox1.addWidget(btCancel) # self.button.clicked.connect(self.handleButton) # Second row hbox2 = QHBoxLayout() # hbox2.addStretch(1) for col in ["col0", "col1"]: hbox2.addWidget(self.tree[col]) # Wrap both columns in a container vbox = QVBoxLayout() vbox.addLayout(hbox1) vbox.addLayout(hbox2) # vbox.addWidget(self.tree1) self.setLayout(vbox) self.setGeometry(300, 300, 800, 400) # Button signals btCancel.clicked.connect(self.reject) btOk.clicked.connect(self.accept) # Tree view for col in cols: col_next = cols[1 - cols.index(col)] self.tree[col].setModel(QStandardItemModel()) self.tree[col].setAlternatingRowColors(True) # self.tree[col].model().setData(self.tree[col].model().index(1, 1), # QtGui.QBrush(QtGui.QColor(255, 0, 0)), QtCore.Qt.BackgroundRole) self.tree[col].setSortingEnabled(True) self.tree[col].setHeaderHidden(False) # self.tree[col].setColumnWidth(2, 30) # This does work! self.tree[col].setSelectionBehavior(QAbstractItemView.SelectItems) self.tree[col].model().setHorizontalHeaderLabels( ["Parameter", "Value", "Update"]) self.tree[col].header().setSectionResizeMode( 0, QHeaderView.Stretch) self.tree[col].header().setSectionResizeMode( 1, QHeaderView.Stretch) self.tree[col].header().resizeSection(2, 50) self.tree[col].header().setSectionResizeMode(2, QHeaderView.Fixed) self.tree[col].header().setStretchLastSection(False) if col != "col0": # self.tree[col].model().setHorizontalHeaderLabels(['Update', i # 'Parameter', 'Value']) self.tree[col].header().moveSection(2, 0) # self.tree1.model().horizontalHeader().setSectionResizeMode(2, # QHeaderView.ResizeToContents) for col in cols: for x in self.data[col]: if not self.data[col][x]: # why did I write this in?? continue self._add_nam_block(x, col) for col in cols: col_next = cols[1 - cols.index(col)] # self.tree[col].model().itemChanged.connect(partial(self.handleItemChanged # , col)) self.tree[col].expanded.connect( partial(self.handleExpanded, col, col_next)) self.tree[col].collapsed.connect( partial(self.handleCollapsed, col, col_next)) self.tree["col0"].verticalScrollBar().valueChanged.connect( self.tree["col1"].verticalScrollBar().setValue) self.tree["col1"].verticalScrollBar().valueChanged.connect( self.tree["col0"].verticalScrollBar().setValue) for col in cols: self.tree[col].model().itemChanged.connect( partial(self.handleItemChanged, col)) # for col in cols: # other = self.tree[col].model().findItems('nambdy', # QtCore.Qt.MatchFixedString) # newIndex=self.tree[col].model().indexFromItem(other[0]) # self.tree[col].scrollTo(newIndex, 3) # Centre # msg = QtWidgets.QMessageBox() # msg.setWindowModality(QtCore.Qt.WindowModal) # msg.setIcon(QtWidgets.QMessageBox.Critical) # msg.setText("Error") # msg.setInformativeText('More information') # msg.setWindowTitle("Error") # msg.exec_() # emsg.showMessage('Message: ') def _add_nam_block(self, nam_block, col): # TODO: run initial check on all the data to see if correct type # Set constants color_diff = QColor(205, 92, 92) color_miss = QColor(92, 92, 205) # Which namelist are we dealing with if col == "col0": col_alt = "col1" arrow = 4 else: col_alt = "col0" arrow = 3 # Local variables tree = self.tree[col] model = tree.model() nambk0 = self.data[col][nam_block] if nam_block in self.data[col_alt]: nambk1 = self.data[col_alt][nam_block] else: nambk1 = False # Add namelist block parent0 = QStandardItem(nam_block) # Namelist header parent1 = QStandardItem() # Not used parent2 = QStandardItem() # Placeholder for QToolButton parent0.setFlags(Qt.NoItemFlags) parent1.setFlags(Qt.NoItemFlags) # Add row model.appendRow([parent0, parent1, parent2]) parind0 = parent0.index() parind2 = parent2.index() # Add widget to handle the transfer of nam_block if not nambk1 or (nambk0 != nambk1): q_btn = QToolButton() # q_btn.setText(arrow) q_btn.setArrowType(arrow) q_btn.clicked.connect(partial(self.pass_block, parind0, col)) tree.setIndexWidget(parind2, q_btn) if not nambk1: model.setData(parind0, color_miss, Qt.ForegroundRole) elif nambk0 != nambk1: model.setData(parind0, color_diff, Qt.ForegroundRole) # parent_item.setData("this is a parent", QtCore.Qt.ToolTipRole) # Add namelist item within block for nam_item in nambk0: # Retrieve value of namelist variable nam_val0 = nambk0[nam_item] # If nam_block exists in other namelist if nambk1: # TODO: temp fix is item isn't present if nam_item in nambk1: nam_val1 = nambk1[nam_item] else: nam_val1 = None child0 = QStandardItem(nam_item) child1 = QStandardItem(str(nam_val0)) # TODO: rm quotes from cn_ child2 = QStandardItem() # child0.setFlags(QtCore.Qt.NoItemFlags | # QtCore.Qt.ItemIsEnabled) child0.setFlags(Qt.NoItemFlags) child1.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable | ~Qt.ItemIsSelectable) parent0.appendRow([child0, child1, child2]) chiind0 = child0.index() chiind1 = child1.index() chiind2 = child2.index() # If bool then replace box with drop down if nam_item[0:2] == "ln": c_box = QComboBox() c_box.addItem("None") c_box.addItem(".true.") c_box.addItem(".false.") ind = c_box.findText(str(nam_val0), Qt.MatchFixedString) c_box.setCurrentIndex(ind) tree.setIndexWidget(chiind1, c_box) # TODO: maybe add arrows to all, just toggle visibility if nambk1 and (nam_val0 != nam_val1): q_btn = QToolButton() # q_btn.setText(arrow) q_btn.clicked.connect( partial(self.pass_entry, col, nam_block, nam_item)) q_btn.setArrowType(arrow) # q_btn.setEnabled(True) tree.setIndexWidget(chiind2, q_btn) model.setData(chiind0, color_diff, Qt.ForegroundRole) elif not nambk1: model.setData(chiind0, color_miss, Qt.ForegroundRole) else: q_btn = QToolButton() # q_btn.setText(arrow) q_btn.clicked.connect( partial(self.pass_entry, col, nam_block, nam_item)) q_btn.setArrowType(0) q_btn.setEnabled(False) tree.setIndexWidget(chiind2, q_btn) def handleItemChanged(self, col, item): # if col == "col0": # col_alt = "col1" # else: # col_alt = "col0" # tree = self.tree[col] # model = tree.model() # print(help(model.match)) print("here****************** item changed") if item.parent() is None: print("Parent") else: # parent = self.data[col][item.parent().text()] # p2 = self.data[col_alt][item.parent().text()] nam_block = item.parent().text() nam_item = item.parent().child(item.row(), 0).text() # item_type = nam_block[0:2] item_val = item.text() # same a nam_item! print(type(item_val)) # app = QtWidgets.QApplication([]) # error_dialog = QtWidgets.QErrorMessage() # error_dialog.showMessage('Oh no!') # app.exec_() print("headline " + nam_block + " " + nam_item + " " + item_val + " ") # TODO check item.text is right type or None # if it is do # parent[nam_block] = type(item.text())(item.text()) # else keep the original value and flag somehow # color_chng = QColor(0, 0, 0) # color_chn1 = QColor(176, 176, 176) # Index = model.indexFromItem(item) # color_diff = QColor(205, 92, 92) # color_test = QColor(100, 0, 92) print("whos the daddy" + item.parent().text()) if (nam_item != item_val ): # need to work out how/why to stop the itemchanged call # when colors are updated self.data[col][nam_block][nam_item] = item_val self.color_update(col, nam_block, nam_item) # TODO error check with pop up if the value isn't compatible with the key def handleExpanded(self, col, col_next, idx): item = self.tree[col].model().itemFromIndex(idx) text = item.text() for other in self.tree[col_next].model().findItems( text, Qt.MatchFixedString): newIndex = self.tree[col_next].model().indexFromItem(other) self.tree[col_next].setExpanded(newIndex, True) def handleCollapsed(self, col, col_next, idx): item = self.tree[col].model().itemFromIndex(idx) text = item.text() for other in self.tree[col_next].model().findItems( text, Qt.MatchFixedString): newIndex = self.tree[col_next].model().indexFromItem(other) self.tree[col_next].setExpanded(newIndex, False) def get_data1(self): return self.data1 def get_data2(self): return self.data2 def pass_block(self, ind, col, idx): if col == "col0": col_alt = "col1" else: col_alt = "col0" tree = self.tree[col] model = tree.model() # item = model.itemFromIndex(idx) # nam_block = item.parent().child(item.row(), 0).text() # print(ind, idx) nam_block = model.itemFromIndex(ind).text() print(model.itemFromIndex(ind).text()) # Map changes in the data self.data[col_alt][nam_block] = self.data[col][nam_block] for other in (self.tree[col_alt].model().findItems( nam_block, Qt.MatchFixedString | Qt.MatchRecursive)): for cnt in range(other.rowCount()): nam_item = other.child(cnt, 0).text() other.child(cnt, 1).setText( str(self.data[col][nam_block][nam_item])) # self.secondColumn.parameter.setText(self) # item = self.tree['col0'].model().itemFromIndex(idx) # text = item.text() # for other in self.tree2.model().findItems(text, QtCore.Qt.MatchFixedString): # newIndex=self.tree2.model().indexFromItem(other) # code to update value in column two def pass_entry(self, col, nam_block, nam_item, idx): # buttonClicked = self.sender() # postitionOfWidget = buttonClicked.pos() # print(postitionOfWidget) # print(dir(sending_button)) # print(str(sending_button.objectName())) if col == "col0": col_alt = "col1" else: col_alt = "col0" # tree = self.tree[col] # model = tree.model() # parent = self.data[col][nam_block] # p2 = self.data[col_alt][nam_block] # nam_block = item.parent().text() # nam_item = item.parent().child(item.row(), 0).text() # item_type = nam_block[0:2] # item_val = item.text() # same a nam_item! # sender = self.sender() print(col, nam_block, nam_item, idx) print(self.data[col_alt][nam_block][nam_item]) print(self.data[col][nam_block][nam_item]) self.data[col_alt][nam_block][nam_item] = self.data[col][nam_block][ nam_item] for other in (self.tree[col_alt].model().findItems( nam_block, Qt.MatchFixedString | Qt.MatchRecursive)): print("$$$$$$$$$$$$$$$$$$") print(other.child(0, 0).text()) print(range(other.rowCount())) print(nam_item) for cnt in range(other.rowCount()): blk = other.child(cnt, 0).text() if blk == nam_item: print("@@@@@@@@@@@@@@@@@ found it") print(other.child(cnt, 0)) print(other.child(cnt, 1)) other.child(cnt, 1).setText( str(self.data[col][nam_block][nam_item])) # item.parent().child(item.row(), 0).text() # print(other.takeRow(0)[0].text() ) # print(dir(other.takeRow(0)[0])) # TODO: do I need this as handleItemChanged maybe triggered anyway? self.color_update(col, nam_block, nam_item) def color_update(self, col, nam_block, nam_item): color_chng = QColor(0, 0, 0) color_chn1 = QColor(176, 176, 176) color_diff = QColor(205, 92, 92) # color_test = QColor(100, 0, 92) if col == "col0": col_alt = "col1" else: col_alt = "col0" # tree = self.tree[col] # model = tree.model() parent = self.data[col][nam_block] p2 = self.data[col_alt][nam_block] for other in (self.tree[col_alt].model().findItems( nam_item, Qt.MatchFixedString | Qt.MatchRecursive)): newIndex = self.tree[col_alt].model().indexFromItem(other) # print('NEWINDEX') # print(newIndex.row()) # print(newIndex.column()) # print(dir(newIndex)) # TODO: sort out indexing # self.tree[col_alt].model().setData(newIndex,str(self.data[col] # [nam_block][nam_item]),Qt.DisplayRole) if p2[nam_item] != parent[nam_item]: print("tttttttttttttttesting1a") print(p2[nam_item]) print(parent[nam_item]) print("****************Not equal1") self.tree[col_alt].model().setData(newIndex, color_diff, Qt.ForegroundRole) # TODO: insert arrow else: print("tttttttttttttttesting1b") print(p2[nam_item]) print(parent[nam_item]) print("****************equal1") self.tree[col_alt].model().setData(newIndex, color_chng, Qt.ForegroundRole) # TODO: remove arrow # q_btn = item.parent().child(item.row(), 2) # print(dir(item.parent())) # print(item.parent().text()) # print(dir(item.parent().child(item.row(), 2))) # print(item.parent().child(item.row(), 2).hasChildren()) # q_btn = item.parent().child(item.row(), 2) # q_btn.data.setArrowType(0) # q_btn.setEnabled(False) # TODO: probably don't need the following for block for other in (self.tree[col].model().findItems( nam_item, Qt.MatchFixedString | Qt.MatchRecursive)): newI = self.tree[col].model().indexFromItem(other) print("We're in Row") print(newI.row()) # other = self.tree['col1'].model().findItems(p2[nam_item], # Qt.MatchFixedString) # print(item) # newIndex=self.tree['col1'].model().indexFromItem(item) # if p2[nam_item] != parent[nam_item]: if p2[nam_item] != parent[nam_item]: print("tttttttttttttttesting2a") print(p2[nam_item]) print(parent[nam_item]) print("****************Not equal0") self.tree[col].model().setData(newI, color_diff, Qt.ForegroundRole) else: print("tttttttttttttttesting2b") print(p2[nam_item]) print(parent[nam_item]) print("****************equal0") self.tree[col].model().setData(newI, color_chng, Qt.ForegroundRole) # TODO: insert arrow pi0 = self.tree[col].model().findItems(nam_block, Qt.MatchFixedString) pi1 = self.tree[col_alt].model().findItems(nam_block, Qt.MatchFixedString) in0 = self.tree[col].model().indexFromItem(pi0[0]) in1 = self.tree[col_alt].model().indexFromItem(pi1[0]) if self.data[col][nam_block] != self.data[col_alt][nam_block]: self.tree[col].model().setData(in0, color_diff, Qt.ForegroundRole) self.tree[col_alt].model().setData(in1, color_diff, Qt.ForegroundRole) else: self.tree[col].model().setData(in0, color_chn1, Qt.ForegroundRole) self.tree[col_alt].model().setData(in1, color_chn1, Qt.ForegroundRole) # TODO check item.text is right type or None # if it is do # parent[key] = type(item.text())(item.text()) # self.secondColumn.parameter().setText(self) # item = self.tree1.model().itemFromIndex(idx) # text = item.text() # for other in self.tree2.model().findItems(text, QtCore.Qt.MatchFixedString): # newIndex=self.tree2.model().indexFromItem(other) # code to update value in column two def searchItem(self): """execute the search and highlight the (next) result""" txt = str(self.searchInput.text()) if txt != self.searchText: self.searchText = txt tmp = self.model.findItems( txt, Qt.MatchFixedString | Qt.MatchContains | Qt.MatchWildcard | Qt.MatchRecursive, ) self.searchList = [i.index() for i in tmp] if self.searchList: mi = self.searchList.pop() self.treeView.setCurrentIndex(mi) self.treeView.expand(mi) self.treeView.scrollTo(mi) else: QMessageBox.information( self, QCoreApplication.translate("DataStorageBrowser", "No (more) matches!"), QCoreApplication.translate( "DataStorageBrowser", "No (more) matches found! Change you search text and try again!", ), ) self.searchText = "" """ file picker call back for output file input field """ @pyqtSlot() def get_fname(self): # When you call getOpenFileName, a file picker dialog is created # and if the user selects a file, it's path is returned, and if not # (ie, the user cancels the operation) None is returned fname = QFileDialog.getSaveFileName(self, "Select output file", "", selectedFilter="*.ncml")[0] if fname: self.filename = fname # returns a QString self.top_outfile_name.setText(str(fname)) # print 'the output file is set to : ' + self.filename def dir_scan(self, bld_dir, ftype): pattern = re.compile("NAMELIST") nl = {} f90_files = glob.glob(bld_dir + "*.f90") # need to update to make recursive f90_files = glob.glob(bld_dir + "/**/*.[F,f]90", recursive=True) for fname in f90_files: for i, line in enumerate(open(fname, errors="ignore")): if re.search(pattern, line): # replace as NAMELIST only occurs once # print(pattern, line) nl_sub = collections.OrderedDict() if "&" in line: ln = line.rsplit("&")[0].strip() count = i + 1 while ln[-1] == ",": nxt = [ x for j, x in enumerate(open(fname)) if j in [ count, ] ][0] if nxt.count("&") >= 1 and nxt.strip()[0] == "&": ln = ln + " " + nxt.rsplit("&")[1].strip() elif nxt.count("&") == 1: ln = ln + " " + nxt.rsplit("&")[0].strip() else: ln = ln + " " + nxt.strip() # need to print('error') # proper handling of # errors please count += 1 nam_name = ln.rsplit("/")[1].strip() nam_items = ln.rsplit("/")[2].strip() nam_items = nam_items.rsplit("!")[0].strip() nam_items = nam_items.rsplit(",") for nam in range(len(nam_items)): nl_sub[nam_items[nam].strip()] = None # need a check in here to make sure that all identical i # namelists have the same number of entries? nl[nam_name] = nl_sub return nl def namelist_scan(self, namelist_in, nl_dict): nam_name = None nam_item = None pattern = re.compile("&nam") for i, line in enumerate(open(namelist_in)): if len(line.strip()) > 0: if re.search(pattern, line): nam_name = line.rsplit()[0].strip()[1:] elif line.strip()[0] != "!" and line.strip()[0] != "/": nam_item = line.rsplit()[0].strip() nam_val = line.rsplit()[2].strip() if nl_dict.get(nam_name) is not None and nam_item is not None: nl_dict[nam_name][ nam_item] = nam_val # remember we may be adding new nam_vals here # so need to check later # print 'A:'+nam_name+': '+nam_item+' : '+nam_val elif nam_name is not None and nam_item is not None: nl_dict[nam_name] = {} nl_dict[nam_name][nam_item] = nam_val # print 'B:'+nam_name+': '+nam_item+' : '+nam_val nam_item = None return nl_dict # def namelist_write(self, namelist_out): def item_type(self, i): item_switcher = { "ln": bool, "nn": int, "rn": float, "cn": str, "sn": str } return item_switcher.get(i, self.emsg.showMessage("Message:"))