def readContours(self): """Reads contours saved in xml format (Echoplaque compatible)""" if self.image == False: warning = QErrorMessage() warning.setWindowModality(Qt.WindowModal) warning.showMessage( 'Reading of contours failed. Images must be loaded prior to loading contours' ) warning.exec_() else: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getOpenFileName( self, "QFileDialog.getOpenFileName()", "", "XML file (*.xml)", options=options) self.lumen, self.plaque, self.stent, self.resolution, frames = read_xml.read( fileName) self.lumen = self.mapToList(self.lumen) self.plaque = self.mapToList(self.plaque) self.stent = self.mapToList(self.stent) self.contours = True self.resizeContours() self.wid.setData(self.lumen, self.plaque, self.images) self.hideBox.setChecked(False)
def display_error(err): app = QApplication.instance() window = app.activeWindow() dialog = QErrorMessage(window) dialog.setWindowModality(Qt.WindowModal) dialog.setWindowTitle("Error") dialog.showMessage(err)
def segment(self): """Segmentation and phenotyping of IVUS images""" warning = QErrorMessage() warning.setWindowModality(Qt.WindowModal) warning.showMessage( 'Warning: IVUS Phenotyping is currently only supported for 20MHz images. Interpret other images with extreme caution' ) warning.exec_()
def on_save_button_clicked(self): file_name, _ = QFileDialog.getSaveFileName(self, "Save Image", self.current_name + ".png", "Images (*.png)") if file_name != "": try: self.current_image.save(file_name) except: error = QErrorMessage(self) error.showMessage("Could not save file") error.setWindowModality(Qt.WindowModal)
def readContours(self): """Reads contours. Reads contours saved in xml format (Echoplaque compatible) and displays the contours in the graphics scene """ if not self.image: warning = QErrorMessage() warning.setWindowModality(Qt.WindowModal) warning.showMessage( 'Reading of contours failed. Images must be loaded prior to loading contours' ) warning.exec_() else: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getOpenFileName( self, "QFileDialog.getOpenFileName()", "", "XML file (*.xml)", options=options) if fileName: self.lumen, self.plaque, self.stent, self.resolution, frames = read_xml.read( fileName) if len(self.lumen[0]) != self.dicom.NumberOfFrames: warning = QErrorMessage() warning.setWindowModality(Qt.WindowModal) warning.showMessage( 'Reading of contours failed. File must contain the same number of frames as loaded dicom' ) warning.exec_() else: self.resolution = float(self.resolution[0]) self.lumen = self.mapToList(self.lumen) self.plaque = self.mapToList(self.plaque) self.stent = self.mapToList(self.stent) self.contours = True self.wid.setData(self.lumen, self.plaque, self.stent, self.images) self.hideBox.setChecked(False) gatedFrames = [ frame for frame in range(len(self.lumen[0])) if self.lumen[0][frame] or self.plaque[0][frame] ] self.gatedFrames = gatedFrames self.useGatedBox.setChecked(True) self.slider.addGatedFrames(self.gatedFrames)
def segment(self): """Segmentation and phenotyping of IVUS images""" save_path = os.path.join(os.getcwd(), 'model', 'saved_model.pb') save_path = os.path.join('/home/microway/Documents/IVUS', 'model_2021', 'saved_model.pb') if not os.path.isfile(save_path): message = "No saved weights have been found, segmentation will be unsuccessful, check that weights are saved in {}".format( os.path.join(os.getcwd(), 'model')) error = QMessageBox() error.setIcon(QMessageBox.Critical) error.setWindowTitle("Error") error.setModal(True) error.setWindowModality(Qt.WindowModal) error.setText(message) error.exec_() return -1 warning = QErrorMessage() warning.setWindowModality(Qt.WindowModal) warning.showMessage( 'Warning: IVUS Phenotyping is currently only supported for 20MHz images. Interpret other images with extreme caution' ) warning.exec_() image_dim = self.images.shape if self.useGatedBox.isChecked(): masks = np.zeros((self.numberOfFrames, image_dim[1], image_dim[2]), dtype=np.uint8) masks_gated = predict(self.images[self.gatedFrames, :, :]) masks[self.gatedFrames, :, :] = masks_gated else: masks = predict(self.images) # compute metrics such as plaque burden self.metrics = self.computeMetrics(masks) self.segmentation = True # convert masks to contours self.lumen, self.plaque = self.maskToContours(masks) self.contours = True # stent contours currently unsupported so create empty list self.stent = [[[] for i in range(image_dim[0])], [[] for i in range(image_dim[0])]] self.wid.setData(self.lumen, self.plaque, self.stent, self.images) self.hideBox.setChecked(False) self.successMessage('Segmentation')
def gate(self): """Extract end diastolic frames and stores in new variable""" self.gatedFrames = IVUS_gating(self.images, self.ivusPullbackRate, self.dicom.CineRate) if self.gatedFrames: self.slider.addGatedFrames(self.gatedFrames) self.useGatedBox.setChecked(True) self.successMessage( "Diastolic frame (change with up and down arrows) extraction") else: warning = QErrorMessage() warning.setWindowModality(Qt.WindowModal) warning.showMessage('Diastolic frame extraction was unsuccessful') warning.exec_()
def store_new_argument(self): wrong = self.ui.wrong.text() right = self.ui.right.text() lang = self.ui.languages.currentText() # Check argument is not circular if right == wrong: msg = QErrorMessage(self) msg.setWindowModality(QtCore.Qt.WindowModal) msg.showMessage( 'You can’t replace a word with itself. It will create a loop.') lang_path = self.script_path + lang + '.json' typo_data = open_typo_file(lang_path) typo_data[right].add(wrong) save_typo_data(lang_path, typo_data)
def logoFromUrlDialog(self, team): """Open dialog for team logo.""" url = "http://" regex = re.compile( r'^(?:http|ftp)s?://' # http:// or https:// # domain... r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+' r'(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' r'localhost|' # localhost... r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip r'(?::\d+)?' # optional port r'(?:/?|[/?]\S+)$', re.IGNORECASE) emsg = QErrorMessage(self) emsg.setWindowModality(Qt.WindowModal) while True: url, status = QInputDialog.getText(self, _("Logo from URL"), _("URL of Team Logo") + ":", QLineEdit.Normal, url) if status: if not regex.match(url): QMessageBox.critical( self, "Invalid URL", _('{} is not a valid URL.').format(url)) continue else: logo = LogoDownloader(self.controller, self, url).download() logo.refreshData() map = logo.provideQPixmap() if team == 1: self.controller.logoManager.setTeam1Logo(logo) self.team1_icon.setPixmap(map) self.refreshLastUsed() elif team == 2: self.controller.logoManager.setTeam2Logo(logo) self.team2_icon.setPixmap(map) self.refreshLastUsed() break else: break
def send_serial(self, command_string): #See what we plan on sending. print(bytes(command_string, 'ascii')) #Send the command as a bytes string try: self.ser.write(bytes(command_string + '\n', 'ascii')) #get some feedback that the command worked. rate = self.ser.readline().decode( 'ascii', 'ignore').strip() #remove whitespace self.slider_label.setText("Blink Rate: {} ms".format(rate)) except Exception as e: error_dialog = QErrorMessage(self) error_dialog.showMessage( repr(e) + "\nPlease reconnect the serial device.") error_dialog.setWindowModality(Qt.ApplicationModal) error_dialog.exec_()
class Messenger_Window(QMainWindow): # noinspection PyArgumentList def __init__(self): super().__init__() self.init_ui() def init_ui(self): myFont = QFont('Arial', pointSize=14, weight=400) self.font = myFont self.errorMessageDialog = QErrorMessage(self) self.errorMessageDialog.setWindowModality(Qt.WindowModal) self.chat_area = QTextEdit( 'В чат пока ничего не написали', readOnly=True, ) self.chat_area.setFont(myFont) self.chat_label = QLabel() self.chat_label.setFont(myFont) self.message_area = QTextEdit('Введите сообщение') self.message_area.setFont(myFont) self.message_area.setMaximumHeight(100) v_splitter = QSplitter(Qt.Vertical) v_splitter.addWidget(self.chat_label) v_splitter.addWidget(self.chat_area) v_splitter.addWidget(self.message_area) self.setCentralWidget(v_splitter) self.setGeometry(200, 50, 500, 900) self.create_actions() self.init_tool_bar() self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) app_icon = QIcon(os.path.join(IMAGES_PATH, 'worldwide.png')) self.setWindowIcon(app_icon) self.enable_actions(True) self.setWindowTitle('My awesome client') self.message_area.setFocus() self.statusBar().showMessage('Ready') # noinspection PyArgumentList def create_actions(self): send_icon = QIcon(os.path.join(IMAGES_PATH, 'paper-plane-1.png')) save_icon = QIcon(os.path.join(IMAGES_PATH, 'save.png')) profile_icon = QIcon(os.path.join(IMAGES_PATH, 'emoji.png')) bold_icon = QIcon(os.path.join(IMAGES_PATH, '012-bold.png')) italic_icon = QIcon(os.path.join(IMAGES_PATH, '057-italic.png')) underline_icon = QIcon(os.path.join(IMAGES_PATH, '093-underline.png')) smile_icon = QIcon(os.path.join(IMAGES_PATH, 'croco.png')) logon_icon = QIcon(os.path.join(IMAGES_PATH, 'key.png')) random_icon = QIcon(os.path.join(IMAGES_PATH, 'magic-wand.png')) exit_icon = QIcon(os.path.join(IMAGES_PATH, 'exit.png')) join_chat_icon = QIcon(os.path.join(IMAGES_PATH, 'users-1.png')) contact_user_icon = QIcon(os.path.join(IMAGES_PATH, 'user-4.png')) debug_icon = QIcon(os.path.join(IMAGES_PATH, 'settings-1')) self.save_action = QAction(save_icon, 'Save chat as...', self, shortcut='Ctrl+S', triggered=self.dialog_save) self.send_action = QAction(send_icon, 'Send message', self, shortcut='Ctrl+Enter', triggered=self.send) self.edit_profile_action = QAction(profile_icon, 'Edit profile', self, triggered=self.edit_profile) self.bold_action = QAction(bold_icon, 'Bold', self, shortcut='Ctrl+S', triggered=self.make_bold) self.italic_action = QAction(italic_icon, 'Italic', self, shortcut='Ctrl+Enter', triggered=self.make_italic) self.underline_action = QAction(underline_icon, 'Underlined', self, triggered=self.make_underline) self.smile_action = QAction(smile_icon, 'Smile!', self, triggered=self.insert_smile) self.logon_action = QAction(logon_icon, 'Logon', self, triggered=self.logon) self.random_action = QAction(random_icon, 'Random message!', self, triggered=self.random_message) self.exit_action = QAction(exit_icon, 'Exit', self, triggered=self.exit) self.join_chat_action = QAction(join_chat_icon, 'Select chat', self, triggered=self.dialog_join_chat) self.contact_user_action = QAction(contact_user_icon, 'Select user', self, triggered=self.dialog_contact_user) self.debug_action = QAction(debug_icon, 'Debug', self, triggered=self.debug) def exit(self): self.before_exit() qApp.quit() def init_tool_bar(self): toolbar = QToolBar() toolbar.setIconSize(QSize(30, 30)) toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon | Qt.AlignLeading) # <= Toolbuttonstyle self.addToolBar(Qt.LeftToolBarArea, toolbar) self.toolbar = toolbar self.toolbar.addAction(self.logon_action) self.toolbar.addSeparator() self.toolbar.addAction(self.join_chat_action) self.toolbar.addSeparator() self.toolbar.addAction(self.contact_user_action) self.toolbar.addSeparator() self.toolbar.addAction(self.edit_profile_action) self.toolbar.addSeparator() self.toolbar.addAction(self.save_action) self.toolbar.addSeparator() self.toolbar.addAction(self.send_action) self.toolbar.addAction(self.random_action) self.toolbar.addSeparator() self.toolbar.addAction(self.bold_action) self.toolbar.addAction(self.italic_action) self.toolbar.addAction(self.underline_action) self.toolbar.addAction(self.smile_action) self.toolbar.addAction(self.exit_action) self.toolbar.addSeparator() self.toolbar.addSeparator() self.toolbar.addSeparator() self.toolbar.addAction(self.debug_action) self.toolbar.setMovable(False) def enable_actions(self, state): for action in self.toolbar.actions(): action.setEnabled(state) def enable_server_buttons(self, state): self.send_action.setEnabled(state) self.edit_profile_action.setEnabled(state) self.join_chat_action.setEnabled(state) self.contact_user_action.setEnabled(state) def enable_communication_buttons(self, state): self.send_action.setEnabled(state) self.random_action.setEnabled(state) self.smile_action.setEnabled(state) self.bold_action.setEnabled(state) self.italic_action.setEnabled(state) self.underline_action.setEnabled(state) self.message_area.setEnabled(state) def insert_smile(self): # TODO insert smiles in unicode url = os.path.join(IMAGES_PATH, 'croco-small.png') self.message_area.insertHtml('<img src="%s" />' % url) def make_bold(self): self.font.setBold(True) self.message_area.setFont(self.font) def make_italic(self): self.font.setItalic(True) self.message_area.setFont(self.font) def make_underline(self): self.font.setUnderline(True) self.message_area.setFont(self.font) def dialog_save(self): fname = QFileDialog.getSaveFileName( self, 'Save as', os.path.expanduser(''), 'Html (*.html);;Txt (*.txt);;All files (*.*)')[0] if fname: self.statusBar().showMessage('Saved file as: {}'.format(fname)) print(fname) html_str = self.chat_area.toHtml() Html_file = open(fname, "w") Html_file.write(html_str) Html_file.close() def edit_profile(self): dlg = ProfileWindow() dlg.exec_()
def error_message(message): error_dialog = QErrorMessage() error_dialog.setWindowModality(Qt.WindowModal) error_dialog.showMessage(message) error_dialog.exec_()
class MyMainWindow(QMainWindow, Ui_MainWindow): closing = pyqtSignal() fileOptions = QFileDialog.Options() | QFileDialog.DontUseNativeDialog def __init__(self, parent=None): super(MyMainWindow, self).__init__(parent) qApp.installEventFilter(self) self.setupUi(self) self.data = ImageData() self.errorMsg = QErrorMessage(self) self.errorMsg.setWindowModality(Qt.WindowModal) self.pushButtonLoadWL.clicked.connect(self.loadWhite) self.pushButtonLoadSpectra.clicked.connect(self.loadSpectra) self.pushButtonLoad.clicked.connect(self.loadAnnotations) self.pushButtonSave.clicked.connect(self.saveAnnotations) self.pushButtonClear.clicked.connect(self.plot_visual.clearSelected) # self.comboBoxMethod.currentIndexChanged.connect() self.horizontalSliderWn.valueChanged.connect(self.wavenumberSlide) self.lineEditWn.editingFinished.connect(self.wavenumberEdit) self.comboBoxVisual.currentIndexChanged.connect(self.imageProjection) self.comboBoxCmaps.currentTextChanged.connect(self.plot_visual.setCmap) self.lineEditWn.setFormat("%.2f") # self.lineEditWavenumber.setRange(min=wmin, max=wmax, default=.5*(wmin+wmax)) self.comboBoxAnnotation.currentIndexChanged.connect( self.plot_visual.setAnnotation) self.plot_visual.addedPoint.connect(self.plot_whitelight.addPoint) self.plot_visual.removedPoint.connect(self.plot_whitelight.removePoint) self.plot_visual.alteredCounts.connect(self.updateCounts) self.plot_whitelight.clickedPoint.connect( self.plot_visual.clickOnePoint) def closeEvent(self, event): self.closing.emit() plt.close('all') self.deleteLater() qApp.quit() def loadSpectra(self): "Load a file or return (error message, traceback) from trying" fileName, _ = QFileDialog.getOpenFileName( self, "Load FTIR image", "", "Matlab files (*.mat);;All files (*)", options=MyMainWindow.fileOptions) self.data.readmat(fileName) self.plot_visual.setData(self.data.wavenumber, self.data.raw, self.data.wh) self.horizontalSliderWn.setMaximum(len(self.data.wavenumber) - 1) self.lineEditWn.setRange(self.data.wmin, self.data.wmax) self.imageProjection() self.plot_whitelight.load(os.path.splitext(fileName)[0] + '.jpg') def loadAnnotations(self): fileName, _ = QFileDialog.getOpenFileName( self, "Load annotation map", "", "Matlab files (*.mat);;All files (*)", options=MyMainWindow.fileOptions) if fileName: s = scipy.io.loadmat(fileName)['annotations'] self.plot_visual.setAnnotations(s) def saveAnnotations(self): fileName, _ = QFileDialog.getSaveFileName( self, "Save annotation map", "", "Matlab files (*.mat);;All files (*)", options=MyMainWindow.fileOptions) if fileName: scipy.io.savemat( fileName, {'annotations': self.plot_visual.getAnnotations()}) # Image visualization def loadWhite(self): fileName, _ = QFileDialog.getOpenFileName( self, "Load white light image", "", "Image files (*.jpg *.png);;All files (*)", options=MyMainWindow.fileOptions) if fileName: self.plot_whitelight.load(fileName) def imageProjection(self): meth = self.comboBoxVisual.currentIndex() iswn = meth == 2 self.lineEditWn.setEnabled(iswn) self.horizontalSliderWn.setEnabled(iswn) self.plot_visual.setProjection(meth, -1 - self.horizontalSliderWn.value()) def updateCounts(self, counts): for i in range(self.comboBoxAnnotation.count()): t = self.comboBoxAnnotation.itemText(i) p = t.rfind('(') t = t[:p] if p >= 0 else t + ' ' self.comboBoxAnnotation.setItemText(i, t + '(%d)' % counts[i]) def sliderToBox(self, slider, box, ixfinder): wn = self.plot_visual.getWavenumbers() if wn is not None: if (not box.hasAcceptableInput() or slider.value() != ixfinder(wn, box.value())): box.setValue(wn[-1 - slider.value()]) elif (not box.hasAcceptableInput() or slider.value() != int( round(slider.maximum() * (box.value() - self.wmin) / (self.wmax - self.wmin)))): box.setValue(self.wmin + (self.wmax - self.wmin) * slider.value() / slider.maximum()) def boxToSlider(self, slider, box, ixfinder): wn = self.plot_visual.getWavenumbers() if wn is not None: if box.hasAcceptableInput(): slider.setValue(ixfinder(wn, box.value())) else: box.setValue(wn[-1 - slider.value()]) else: slider.setValue( int( round(slider.maximum() * (box.value() - self.wmin) / (self.wmax - self.wmin)))) def wavenumberSlide(self): self.sliderToBox( self.horizontalSliderWn, self.lineEditWn, lambda wn, val: len(wn) - 1 - (np.abs(wn - val)).argmin()) self.plot_visual.setProjection(2, -1 - self.horizontalSliderWn.value()) def wavenumberEdit(self): self.boxToSlider( self.horizontalSliderWn, self.lineEditWn, lambda wn, val: len(wn) - 1 - (np.abs(wn - val)).argmin())
class OctavvsMainWindow(QMainWindow): fileOptions = QFileDialog.Options() | QFileDialog.DontUseNativeDialog octavvs_version = 'v0.1.2' def __init__(self, parent=None): super().__init__(parent) self.settings = QSettings('MICCS', 'OCTAVVS ' + self.program_name()) qApp.installEventFilter(self) self.setupUi(self) self.errorMsg = QErrorMessage(self) self.errorMsg.setWindowModality(Qt.WindowModal) def post_setup(self): "Called by children after setting up UI but before loading data etc" self.setWindowTitle('OCTAVVS %s %s' % (self.program_name(), self.octavvs_version)) ExceptionDialog.install(self) @classmethod def program_name(cls): "Return the name of the program that this main window represents" return cls.__name__ def showDetailedErrorMessage(self, err, details): "Show an error dialog with details" q = QMessageBox(self) q.setIcon(QMessageBox.Critical) q.setWindowTitle("Error") q.setText(err) q.setTextFormat(Qt.PlainText) q.setDetailedText(details) q.addButton('OK', QMessageBox.AcceptRole) return q.exec() def loadErrorBox(self, file, err): "Prepare an error dialog for failure to load a file" q = QMessageBox(self) q.setIcon(QMessageBox.Warning) q.setWindowTitle("Error loading file") q.setText("Failed to load '" + file + "':\n" + err[0]) q.setTextFormat(Qt.PlainText) q.setDetailedText(err[1]) return q def getLoadSaveFileName(self, title, filter=None, settingname=None, savesuffix=None, multiple=False, settingdefault=None): "Show a file dialog and select one or more files" setting = self.settings.value( settingname, settingdefault) if settingname is not None else None directory = setting if type(setting) is str else None dialog = QFileDialog(parent=self, caption=title, directory=directory, filter=filter) # if setting and type(setting) is not str: # dialog.restoreState(setting) dialog.setOption(QFileDialog.DontUseNativeDialog, True) if savesuffix is not None: dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setDefaultSuffix(savesuffix) elif multiple: dialog.setFileMode(QFileDialog.ExistingFiles) else: dialog.setFileMode(QFileDialog.ExistingFile) dialog.exec() files = dialog.selectedFiles() if not dialog.result() or not files: return None self.settings.setValue(settingname, os.path.dirname(files[0])) return files if multiple else files[0] def getSaveFileName(self, title, suffix='', **kwargs): "Show a file dialog and select an output file" return self.getLoadSaveFileName(title=title, savesuffix=suffix, **kwargs) def getLoadFileName(self, title, **kwargs): "Show a file dialog and select an input file" return self.getLoadSaveFileName(title=title, **kwargs) def getLoadFileNames(self, title, **kwargs): "Show a file dialog and select an input file" return self.getLoadSaveFileName(title=title, multiple=True, **kwargs) def getImageFileName(self, title, **kwargs): "Show a file dialog and select a single image file" return self.getLoadSaveFileName( title=title, filter= "Image files (*.jpg *.jpeg *.png *.tif *.tiff *.bmp *.gif);;All files (*)", **kwargs) def getDirectoryName(self, title, settingname=None, savesetting=True): "Show a file dialog and select a directory" directory = self.settings.value( settingname, None) if settingname is not None else None dialog = QFileDialog(parent=self, caption=title, directory=directory) dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setFileMode(QFileDialog.Directory) dialog.setOption(QFileDialog.DontUseNativeDialog, True) dialog.setOption(QFileDialog.ShowDirsOnly, True) dialog.exec() dirs = dialog.selectedFiles() if not dialog.result() or not dirs: return None if savesetting: self.settings.setValue(settingname, dirs[0]) return dirs[0] def updateWavenumberRange(self): "For derived classes, when the wn range is updated" pass def updateDimensions(self, wh): "For derived classes, when image width/height is updated" pass @classmethod def run_octavvs_application(windowclass, parser=None, parameters=[], isChild=False): res = 1 try: progver = 'OCTAVVS %s %s' % (windowclass.program_name(), OctavvsMainWindow.octavvs_version) windowparams = {} if parser is not None: parser.add_argument('--version', action='version', version=progver) parser.add_argument('--mpmethod') args = parser.parse_args() windowparams = {k: args.__dict__[k] for k in parameters} if args.mpmethod and multiprocessing.get_start_method( allow_none=True) is None: multiprocessing.set_start_method(args.mpmethod) app = QApplication.instance() if not app: app = QApplication(sys.argv) add_clipboard_to_figures() window = windowclass(**windowparams) window.show() if not isChild: qApp.lastWindowClosed.connect(qApp.quit) res = app.exec_() except Exception: traceback.print_exc() print('Press some key to quit') input() if not isChild: sys.exit(res)
class MainWindow(QMainWindow): def __init__(self): super().__init__() loadUi("./ui/main_window.ui",self) self.setWindowIcon(QIcon('./ui/icon.png')) self.emsg = QErrorMessage() self.emsg.setWindowModality(QtCore.Qt.WindowModal) self.emsg.setWindowFlag(QtCore.Qt.WindowStaysOnTopHint) self.initUI() self.char_window = CharWindow() self.selector_window = SelectorWindow() self.b_Edit_Characters.clicked.connect(self.edit_chars) self.b_clear_dyn.clicked.connect(self.clear_dynamics) self.b_rand_dyn_miss.clicked.connect(self.rand_dynamics_missing) self.b_rand_dyn_all.clicked.connect(self.rand_dynamics_all) self.b_rand_thr_all.clicked.connect(self.rand_throughlines_all) self.b_rand_abs_all.clicked.connect(self.rand_abstracts_all) self.b_rand_acts_all.clicked.connect(self.rand_acts_all) self.b_rand_EVERYTHING.clicked.connect(self.rand_EVERYTHING) self.b_Crucial_Element.clicked.connect(self.b_crucial_clicked) self.b_clear_thro.clicked.connect(self.b_clear_throughlines) self.b_clear_abstracts.clicked.connect(lambda: self.reset_button_layout(self.grid_abstracts)) self.b_clear_acts.clicked.connect(lambda: self.reset_button_layout(self.grid_acts)) def initUI(self): # Load colors from config file for branch in root.children: change_style_color(branch.text, BG_COLOURS[branch.text], TEXT_COLOURS[branch.text]) refresh_styles() self.actionNew.setShortcut('Ctrl+N') self.actionNew.setStatusTip('New document') self.actionNew.triggered.connect(self.newCall) self.actionOpen.setShortcut('Ctrl+O') self.actionOpen.setStatusTip('Open document') self.actionOpen.triggered.connect(self.openCall) self.actionSave.setShortcut('Ctrl+S') self.actionSave.setStatusTip('Save document') self.actionSave.triggered.connect(self.saveCall) self.actionExport_pdf.setShortcut('Ctrl+E') self.actionExport_pdf.setStatusTip('Export to .pdf') self.actionExport_pdf.triggered.connect(self.exportCall) self.update_char_layout() # Fill Throughline and Acts grids with buttons positions = [(i, j) for i in range(4) for j in range(4)] for i, pos in enumerate(positions): widget = QPushButton('th_'+str(i),self) widget.clicked.connect(self.b_throughline_clicked) widget.setText(BLANK_TEXT) self.grid_throughlines.addWidget(widget, *pos) widget = QPushButton('ac_'+str(i),self) widget.clicked.connect(self.b_acts_clicked) widget.setText(BLANK_TEXT) self.grid_acts.addWidget(widget,*pos) for i, button in enumerate(self.grid_abstracts.parentWidget().findChildren(QPushButton)): button.setText(BLANK_TEXT) button.clicked.connect(self.b_abstract_clicked) # GENERATE THE DYNAMICS TABLES WITH BUTTONS N SHIT positions = [(i, j) for i in range(8) for j in range(3)] for x in range(3): self.grid_c_dynamics.setColumnMinimumWidth(x,150) self.grid_p_dynamics.setColumnMinimumWidth(x,150) for position, name in zip (positions, c_dynamics): if name in dynamic_headings: widget = QLabel(name,self) widget.setFont(HEADING_FONT) widget.setAlignment(Qt.AlignCenter) else: widget = QPushButton(name,self) widget.setCheckable(True) widget.clicked.connect(self.opt_flip) widget.setObjectName(name) self.grid_c_dynamics.addWidget(widget, *position) for position, name in zip (positions, p_dynamics): if name in dynamic_headings: widget = QLabel(name,self) widget.setFont(HEADING_FONT) widget.setAlignment(Qt.AlignCenter) else: widget = QPushButton(name,self) widget.setCheckable(True) widget.clicked.connect(self.opt_flip) if self.findChild(QPushButton, name) == None: widget.setObjectName(name) else: widget.setObjectName(name+str(1)) self.grid_p_dynamics.addWidget(widget, *position) def set_node_button(self, button, text, style): button.setText(text) button.setStyleSheet(style) button.setToolTip(get_tooltip(text)) def b_clear_throughlines(self): self.reset_button_layout(self.grid_throughlines) self.set_node_button(self.b_Crucial_Element,BLANK_TEXT, "") def copy_throughline_extras(self): crucial_text = self.grid_throughlines.itemAtPosition(1,3).widget().text() if crucial_text != BLANK_TEXT: crucial_node = self.find_node(crucial_text, self.grid_throughlines.itemAtPosition(1,0).widget().text()) self.set_node_button(self.b_Crucial_Element,crucial_node.text, crucial_node.style) self.set_node_button(self.grid_throughlines.itemAtPosition(0,3).widget(),crucial_node.text, crucial_node.style) def b_throughline_clicked(self, button=None): if not button: button = self.sender() else: print('prog exec') layout = button.parent().layout() idx = layout.indexOf(button) pos = layout.getItemPosition(idx) siblings = [] cousins = [] if pos[1] == 0: # if its a root branch cousins = root.children selected = [] for y in range(4): text = layout.itemAtPosition(y,0).widget().text() if self.find_node(text): selected.append(self.find_node(text)) for branch in cousins: if branch not in selected: siblings.append(branch) else: branch_text = layout.itemAtPosition(pos[0],0).widget().text() parent_text = layout.itemAtPosition(pos[0],pos[1]-1).widget().text() try: parent_node = self.find_node(parent_text, branch_text, pos[1]-1) siblings.extend(parent_node.children) cousins = self.find_cousins(parent_node) except: print('exception') return try: self.toggle_selector(button, layout, idx, pos, cousins, siblings, self.chk_Legal_Only_Thro.checkState()) except: return def b_crucial_clicked(self): layout = self.grid_throughlines branch_node_text = layout.itemAtPosition(1,0).widget().text() branch_node = self.find_node(branch_node_text) mc_problem_text = layout.itemAtPosition(1,3).widget().text() mc_problem_node = self.find_node(mc_problem_text, branch_node_text, 3) parent_node_text = layout.itemAtPosition(1,2).widget().text() if parent_node_text != BLANK_TEXT: try: siblings = [] cousins = [] parent_node = self.find_node(parent_node_text, branch_node_text, 2) siblings.append(mc_problem_node) cousins = self.find_cousins(parent_node) self.toggle_selector(self.sender(), layout, None, None, cousins, siblings, self.chk_Legal_Only_Thro.checkState()) except: print('exception') return def b_abstract_clicked(self): button = self.sender() options_all = copy.copy(types) selected = [] for b in self.grid_abstracts.parentWidget().findChildren(QPushButton): if b.text() != BLANK_TEXT: selected.append(self.find_node(b.text())) legal_options = [] for o in options_all: if o in selected: continue legal_options.append(o) self.toggle_selector(button, self.grid_abstracts, None, None, options_all, legal_options, self.chk_Legal_Only_Abstracts.checkState()) def b_acts_clicked(self, button=None): if not button: button = self.sender() else: print('prog exec') layout = button.parent().layout() idx = layout.indexOf(button) pos = layout.getItemPosition(idx) branch_text = self.grid_throughlines.itemAtPosition(pos[0],0).widget().text() branch = self.find_node(branch_text) if not branch: return acts_all = [] acts_all.extend(branch.children) acts_picked = [] for x in range(4): if x == pos[1]: continue picked_text = layout.itemAtPosition(pos[0],x).widget().text() if picked_text != BLANK_TEXT: acts_picked.append(self.find_node(picked_text)) acts_legal = [] for act in acts_all: if act not in acts_picked: acts_legal.append(act) try: self.toggle_selector(button, layout, idx, pos, acts_all, acts_legal, self.chk_Legal_Only_Acts.checkState()) except: return def toggle_selector(self, button=None, layout=None, idx=None, pos=None, cousins=None, siblings=None, bool_legal_only=False): global selector_node global selector_button if self.selector_window.isVisible(): self.set_node_button(selector_button, selector_node.text, selector_node.style) self.selector_window.hide() self.setEnabled(True) selector_button_layout = selector_button.parent().layout() if selector_button_layout == self.grid_throughlines: idx = selector_button_layout.indexOf(selector_button) pos = selector_button_layout.getItemPosition(idx) for x in range(pos[1]+1,4): b = selector_button_layout.itemAtPosition(pos[0],x).widget() self.set_node_button(b, BLANK_TEXT, "") else: selector_button = button self.selector_window.show() self.selector_window.update_buttons(cousins, siblings, bool_legal_only) self.setEnabled(False) def find_cousins(self, parent_node): cousins = [] if parent_node.level == 0: cousins.extend(parent_node.children) else: for gp_node in node_levels[parent_node.level-1]: for p_node in gp_node.children: if p_node == parent_node: grandparent = gp_node break for au in grandparent.children: for c in au.children: cousins.append(c) return cousins def find_chars(self, trait): data = [] for c in characters: if trait in c.traits: data.append(c.name) return data def edit_chars(self): if self.char_window.isVisible(): self.char_window.hide() self.show() self.setEnabled(True) else: self.char_window.show() self.hide() self.setEnabled(False) self.char_window.update_char_list() def update_char_layout(self): global characters # Clear the layouts of any existing labels for label in self.layout_chars.parentWidget().findChildren(QLabel): label.setParent(None) for label in self.layout_traits.parentWidget().findChildren(QLabel): label.setParent(None) max_col = 3 cur_col = 0 cur_row = 0 c_names = [] c_traits = [] for c in characters: c_names.append(c.name) c_traits.append((", ").join(c.traits)) for i, c in enumerate(c_names): c_widget = QLabel(c,self) c_widget.setFont(HEADING_FONT) c_widget.setAlignment(Qt.AlignCenter) c_widget.setText(c) c_widget.setFrameStyle(1) c_widget.setFrameShape(QFrame.Box) c_widget.setFrameShadow(QFrame.Plain) c_widget.setStyleSheet(COLOR_HEADING_BACKGROUND) t_widget = QLabel(c_traits[i],self) t_widget.setAlignment(Qt.AlignCenter) t_widget.setText(c_traits[i]) t_widget.setFrameStyle(1) t_widget.setFrameShape(QFrame.Box) t_widget.setFrameShadow(QFrame.Plain) t_widget.setWordWrap(True) # t_widget.setMinimumSize(t_widget.sizeHint()) self.layout_chars.addWidget(c_widget,cur_row,cur_col) self.layout_chars.addWidget(t_widget,cur_row+1,cur_col) if cur_col < max_col: cur_col += 1 else: cur_col = 0 cur_row += 2 cur_col = 0 cur_row = 0 for trait in traits: t_widget = QLabel(trait,self) t_widget.setFont(HEADING_FONT) t_widget.setAlignment(Qt.AlignCenter) t_widget.setText(trait) t_widget.setFrameStyle(1) t_widget.setFrameShape(QFrame.Box) t_widget.setFrameShadow(QFrame.Plain) t_widget.setStyleSheet(COLOR_HEADING_BACKGROUND) t_widget.setToolTip(get_tooltip(trait)) chars_w_trait = [] for c in characters: if trait in c.traits: chars_w_trait.append(c.name) continue c_widget = QLabel(trait,self) c_widget.setAlignment(Qt.AlignCenter) c_widget.setText((", ").join(chars_w_trait)) c_widget.setFrameStyle(1) c_widget.setFrameShape(QFrame.Box) c_widget.setFrameShadow(QFrame.Plain) c_widget.setWordWrap(True) self.layout_traits.addWidget(t_widget,cur_row,cur_col) self.layout_traits.addWidget(c_widget,cur_row+1,cur_col) if cur_col < max_col: cur_col += 1 else: cur_col = 0 cur_row += 2 def rand_EVERYTHING(self): self.char_window.Randomize_Traits() self.update_char_layout() self.rand_dynamics_all() self.rand_throughlines_all() self.rand_abstracts_all() self.rand_acts_all() # ========================== DYNAMICS ============================ def opt_flip(self): #TURN THE OPPOSITE CLICKED BUTTON OFF. selected = self.sender().objectName() for options in dynamics.values(): if selected in options: if options[0] == selected: opposite = options[1] else: opposite = options[0] self.findChild(QPushButton, opposite).setChecked(False) def get_dyn_buttons(self): #GET LIST OF BUTTONS IN THE DYNAMICS GRID FORMS c = [] p = [] for i in range(self.grid_c_dynamics.count()): if isinstance(self.grid_c_dynamics.itemAt(i).widget(), QPushButton): c.append(self.grid_c_dynamics.itemAt(i).widget()) if isinstance(self.grid_p_dynamics.itemAt(i).widget(), QPushButton): p.append(self.grid_p_dynamics.itemAt(i).widget()) c.extend(p) return c def read_dynamics_state(self): dyn_buttons = self.get_dyn_buttons() selections = dict.fromkeys(dynamics.keys()) for key, options in dynamics.items(): for item in dyn_buttons: if item.objectName() in options and item.isChecked(): selections[key] = item.objectName() return selections def clear_dynamics(self): dyn_buttons = self.get_dyn_buttons() for b in dyn_buttons: b.setChecked(False) def rand_dynamics_missing(self): selections = self.read_dynamics_state() dyn_buttons = self.get_dyn_buttons() for key, options in dynamics.items(): if selections[key] == None: self.findChild(QPushButton, random.choice(options)).setChecked(True) def rand_dynamics_all(self): dyn_buttons = self.get_dyn_buttons() for b in dyn_buttons: b.setChecked(False) for key, options in dynamics.items(): self.findChild(QPushButton, random.choice(options)).setChecked(True) # ======================== THROUGHLINES ========================== def gen_throughline(self, start_node): thro = [] thro.append(random.choice(start_node.children)) for i in range(1,3): pick = random.choice(thro[i-1].children) thro.append(pick) return thro def rand_throughlines_all(self): roots = [] choices = list(root.children) # Initialize the throughline classes roots.append(random.choice(choices)) roots.append(self.find_node(opposites[roots[0].text])) choices.remove(roots[0]) choices.remove(roots[1]) random.shuffle(choices) roots.extend(choices) # Reorder classes as Subjective Story needs to be last roots.append(roots.pop(roots.index(roots[1]))) # Generate 4 random throughlines with the above as seeds cb_throughlines = [] for x in range(4): cb_throughlines.append(roots[x]) cb_throughlines.extend(self.gen_throughline(roots[x])) # Overall Story problem is supposed to match the Main Character Problem try: cb_throughlines[3] = self.find_node(cb_throughlines[7].text, cb_throughlines[0].text) except: cb_throughlines[3] = cb_throughlines[7] for i, button in enumerate(self.grid_throughlines.parentWidget() .findChildren(QPushButton)): self.set_node_button(button, cb_throughlines[i].text, cb_throughlines[i].style) self.set_node_button(self.b_Crucial_Element,cb_throughlines[7].text, cb_throughlines[7].style) def find_node(self, string, branch=None, level=None): found = [] if string == BLANK_TEXT: return for cl in root.children: if branch: if cl.text != branch: continue if cl.text == string: found.append(cl) for ty in cl.children: if ty.text == string: found.append(ty) for var in ty.children: if var.text == string: found.append(var) for elem in var.children: if elem.text == string: found.append(elem) # error checking for multiple results. if level and found: for node in found: if node.level == level: found = [node] return found[0] def read_throughlines_state(self): content = [] for i, button in enumerate(self.grid_throughlines.parentWidget() .findChildren(QPushButton)): content.append(button.text()) return content # ========================= ABSTRACTS ============================ def rand_abstracts_all(self): choices = list(types) random.shuffle(choices) for i, button in enumerate(self.grid_abstracts.parentWidget() .findChildren(QPushButton)): self.set_node_button(button, choices[i].text, choices[i].style) def read_abstracts_state(self): content = [] for i, button in enumerate(self.grid_abstracts.parentWidget() .findChildren(QPushButton)): content.append(button.text()) return content # =========================== ACTS =============================== def update_acts(self): thro = self.read_throughlines_state() branches = thro[0::4] def rand_acts_all(self): try: thro = self.read_throughlines_state() branch_names = thro[0::4] branch_nodes = [] for name in branch_names: branch_nodes.append(self.find_node(name)) acts = [] for b in branch_nodes: choices = [] for child in b.children: choices.append(child) random.shuffle(choices) acts.extend(choices) for i, button in enumerate(self.grid_acts.parentWidget() .findChildren(QPushButton)): self.set_node_button(button, acts[i].text, acts[i].style) except: return def read_acts_state(self): content = [] for i, button in enumerate(self.grid_acts.parentWidget() .findChildren(QPushButton)): content.append(button.text()) return content # =========================== SAVE =============================== def read_total_state(self): _data = {} _data['characters'] = [] _data['character_names'] = [] _data['character_traits'] = [] _data['dynamics'] = [] _data['throughlines'] = [] _data['abstracts'] = [] _data['acts'] = [] try: for c in characters: _data['characters'].append(jsonpickle.encode(c)) _data['character_names'].append(c.name) _data['character_traits'].append(c.traits) for k, dyn in self.read_dynamics_state().items(): _data['dynamics'].append(dyn) _data['throughlines'] = self.read_throughlines_state() _data['abstracts'] = self.read_abstracts_state() _data['acts'] = self.read_acts_state() return _data except: pass def saveCall(self): global FILE_PATH save_data = self.read_total_state() if FILE_PATH == "": save_path = QFileDialog.getSaveFileName(self, 'Save File', "","JSON (*.json)") else: save_path = QFileDialog.getSaveFileName(self, 'Save File', FILE_PATH,"JSON (*.json)") if save_path[0]: with open(save_path[0], 'w') as outfile: json.dump(save_data,outfile) FILE_PATH = save_path[0] self.setWindowTitle("Story Randomizer - " + FILE_PATH) else: return def reset_button_layout(self,layout): try: for i, button in enumerate(layout.parentWidget() .findChildren(QPushButton)): self.set_node_button(button,BLANK_TEXT, "") except: return def newCall(self): global characters characters = [] self.update_char_layout() for button in self.layout_dynamics.parentWidget().findChildren(QPushButton): button.setChecked(False) layouts = [self.grid_throughlines, self.grid_abstracts, self.grid_acts] for layout in layouts: self.reset_button_layout(layout) self.set_node_button(self.b_Crucial_Element, BLANK_TEXT, "") def openCall(self): global characters global FILE_PATH open_path = QFileDialog.getOpenFileName(self, 'Open File', '',"JSON (*.json)") if open_path[0]: with open(open_path[0]) as json_file: in_data = json.load(json_file) else: return FILE_PATH = open_path[0] self.setWindowTitle("Story Randomizer - " + FILE_PATH) characters = [] for c in in_data['characters']: characters.append(jsonpickle.decode(c)) self.update_char_layout() for button in self.layout_dynamics.parentWidget().findChildren(QPushButton): button.setChecked(False) if button.text() in in_data['dynamics']: button.setChecked(True) for i, button in enumerate(self.grid_throughlines.parentWidget() .findChildren(QPushButton)): try: if i % 4 == 0: branch = self.find_node(in_data['throughlines'][i]) node = self.find_node(in_data['throughlines'][i],branch.text) self.set_node_button(button, node.text, node.style) if i == 7: self.set_node_button(self.b_Crucial_Element, node.text, node.style) except: print("Error loading throughlines, save may be corrupted") for i, button in enumerate(self.grid_abstracts.parentWidget() .findChildren(QPushButton)): try: node = self.find_node(in_data['abstracts'][i]) self.set_node_button(button, node.text, node.style) except: print("Error loading abstracts, save may be corrupted") for i, button in enumerate(self.grid_acts.parentWidget() .findChildren(QPushButton)): try: node = self.find_node(in_data['acts'][i]) self.set_node_button(button, node.text, node.style) except: print("Error loading acts, save may be corrupted") def exportCall(self): try: out_data = self.read_total_state() save_path = QFileDialog.getSaveFileName(self, 'Save File', "","PDF (*.pdf)") if not save_path[0]: return with open('dump.json', 'w') as outfile: json.dump(out_data,outfile) pdf_report.save('dump.json', save_path) except: self.error_message('Export to pdf failed.') def error_message(self, text): self.emsg.setWindowTitle('Error') self.emsg.showMessage(text)
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:"))
class Example(QWidget): def __init__(self): super().__init__() self.error_message = QErrorMessage(self) self.error_message.setWindowModality(Qt.WindowModal) self.gui_dictionary = {key: None for key in default_values} self.initUI() def initUI(self): self.grid = QGridLayout() self.grid.setSpacing(10) for idx, (key, value) in enumerate(sorted(default_values.items())): text_label = key.replace('_', ' ').title() value_str = str(value) label = QLabel(text_label) text_box = QLineEdit(value_str) text_box.setAlignment(Qt.AlignCenter) self.grid.addWidget(label, idx + 1, 0) self.grid.addWidget(text_box, idx + 1, 1) self.gui_dictionary[key] = text_box self.create_video_button = QPushButton('Create Simulation') self.add_molecule_type = QPushButton('Add Molecule') self.molecules_table_model = MoleculeTableModel() self.molecules_table = self.molecules_table_model.table_widget self.create_video_button.clicked.connect(self.run_button_clicked) self.add_molecule_type.clicked.connect(self.add_molecule) self.grid.addWidget(self.add_molecule_type, len(default_values) + 1, 0, 2, 1) self.grid.addWidget(self.molecules_table, len(default_values) + 1, 1, 2, 1) self.grid.addWidget(self.create_video_button, len(default_values) + 3, 0, 1, 2) self.progress_bar = QProgressBar() self.status_label = QLabel(STATUS_LABEL_INITAL_VALUE) self.grid.addWidget(self.progress_bar, len(default_values) + 4, 1, 1, 1) self.grid.addWidget(self.status_label, len(default_values) + 4, 0, 1, 1) self.setLayout(self.grid) self.setGeometry(ORIGINAL_POSITION_X, ORIGINAL_POSITION_Y, WINDOW_WIDTH, WINDOW_HEIGHT) self.setWindowTitle('Molecule Magic Mixer') self.show() @pyqtSlot() def add_molecule(self): self.molecules_table_model.add_row() @pyqtSlot() def run_button_clicked(self): self.molecules_table_model.update_data() molecules_dictionaries = self.molecules_table_model.get_molecules(self) if molecules_dictionaries is None: """ An Error Occurred """ return setup_dictionary = self.create_setup_dictionary() if setup_dictionary is None: return options = QFileDialog.Options() filename, _ = QFileDialog.getSaveFileName( self, "QFileDialog.getSaveFileName()", "", "Tiff Files (*.tif)", options=options) if not filename: return self.init_progress_bar(len(molecules_dictionaries)) self.set_enable_status(False) def worker(): self.set_status_label("Running Simulations") simulations = [] for index, molecule_dict in enumerate(molecules_dictionaries): simulation_dictionary = dict(setup_dictionary) simulation_dictionary.update(molecule_dict) simulation = Simulation(simulation_dictionary) simulation.run() simulations.append(simulation) self.progress_bar.setValue(index) multispecies_simulation = MultiSpeciesSimulation(*simulations) self.progress_bar.setValue(self.progress_bar.value() + 1) self.set_status_label("Creating Frames") multispecies_simulation.create_frames() self.progress_bar.setValue(self.progress_bar.value() + 1) self.set_status_label("Saving to file") multispecies_simulation.save_frames_to_file(filename) self.save_setup(setup_dictionary, molecules_dictionaries, simulations, filename) # self.progress_bar.setValue(self.progress_bar.value() + 1) self.finish_progress_bar() self.set_status_label("Done!") self.set_enable_status(True) t = threading.Thread(target=worker) treads.append(t) t.start() def show_error(self, message): self.error_message.showMessage(message) self.set_enable_status(True) def set_enable_status(self, status): # for value in for widget in self.gui_dictionary.values(): widget.setEnabled(status) self.molecules_table_model.table_widget.setEnabled(status) self.create_video_button.setEnabled(status) self.add_molecule_type.setEnabled(status) def init_progress_bar(self, number_of_molecules): self.progress_bar.setValue(0) self.progress_bar.setMinimum(0) self.progress_bar.setMaximum(number_of_molecules + NUMBER_OF_ANIMATION_STEPS) def finish_progress_bar(self): self.progress_bar.setMinimum(0) self.progress_bar.setMaximum(1) self.progress_bar.setValue(1) def set_status_label(self, text): self.status_label.setText(text) def create_setup_dictionary(self): setup_dictionary = {} for key, text_box in self.gui_dictionary.items(): try: setup_dictionary[key] = types_dictionary[key](text_box.text()) except Exception as e: self.show_error("Problem parsing {}, \n {}".format( key, str(e))) return return setup_dictionary def create_simulation_dictionary(self, setup_dictionary, molecules_dictionaries, simulations): d = dict(setup_dictionary) molecules_dictionaries = list( [dict(d) for d in molecules_dictionaries]) for molecule_dict, simulation in zip(molecules_dictionaries, simulations): molecule_dict[MOLECULES_KEY] = simulation.to_dict()[MOLECULES_KEY] d[MOLECULES_DICTIONARY_KEY] = molecules_dictionaries return d def save_setup(self, setup_dictionary, molecules_dictionaries, simulations, filename): with open(filename + ".json", "w") as f: f.write( json.dumps( self.create_simulation_dictionary(setup_dictionary, molecules_dictionaries, simulations)))