From e228a59537b02c33e0d12a1e3b2223eb32a91f51 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby <pierre-antoine.rouby@inrae.fr> Date: Wed, 5 Apr 2023 10:28:40 +0200 Subject: [PATCH] subwindow, geomerty: Split ASubWindow into two classes and add missing file. --- src/Model/Geometry/ProfileXYZ.py | 3 +- src/View/ASubWindow.py | 101 ++-- src/View/ConfigureWindow.py | 4 +- src/View/Geometry/qtableview_profile.py | 5 +- src/View/Geometry/window_profileXYZ.py | 686 ++++++++++++++++++++++++ src/View/GeometryWindow.py | 7 +- src/View/MainWindow.py | 8 +- 7 files changed, 757 insertions(+), 57 deletions(-) create mode 100644 src/View/Geometry/window_profileXYZ.py diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index fcf3b62c..237ef6e3 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -5,6 +5,7 @@ import pandas as pd from typing import List from Model.Geometry.Profile import Profile +from Model.Geometry.PointXYZ import PointXYZ class ProfileXYZ(Profile): def __init__(self, num: int = 0, code1: int = 0, code2: int = 0, @@ -24,7 +25,7 @@ class ProfileXYZ(Profile): """ super(ProfileXYZ, self).__init__( num = num, - name = name + name = name, kp = kp, ) diff --git a/src/View/ASubWindow.py b/src/View/ASubWindow.py index 5133c997..f4fb1dd3 100644 --- a/src/View/ASubWindow.py +++ b/src/View/ASubWindow.py @@ -17,7 +17,58 @@ from PyQt5.QtCore import ( ) from PyQt5.uic import loadUi -class ASubWindow(QDialog): +class WindowToolKit(object): + def __init__(self, parent=None): + super(WindowToolKit, self).__init__() + + def file_dialog(self, select_file=True, callback=lambda x: None): + """Open a new file dialog and send result to callback function + + Args: + select_file: Select a file if True, else select a dir + callback: The callback function with one arguments, files + selection list + + Returns: + The returns of callback + """ + dialog = QFileDialog(self) + + if select_file: + mode = QFileDialog.FileMode.ExistingFile + else: + mode = QFileDialog.FileMode.Directory + + dialog.setFileMode(mode) + + if dialog.exec_(): + file_names = dialog.selectedFiles() + return callback(file_names) + + def message_box(self, text: str, + informative_text: str, + window_title: str = "Warning"): + """Open a new message box + + Args: + text: Short text string + informative_text: Verbose text string + window_title: Title of message box window + + Returns: + Nothing + """ + msg = QMessageBox() + + msg.setIcon(QMessageBox.Warning) + msg.setText(text) + msg.setInformativeText(informative_text) + msg.setWindowTitle(window_title) + + msg.exec_() + + +class ASubWindow(QDialog, WindowToolKit): def __init__(self, name="", ui="dummy", parent=None): super(ASubWindow, self).__init__(parent=parent) self.ui = loadUi( @@ -66,7 +117,6 @@ class ASubWindow(QDialog): self.find(QLineEdit, name).setText(text) except AttributeError as e: print(e) - print(f"{name}") def get_line_edit_text(self, name:str): """Get text of line edit component @@ -253,50 +303,3 @@ class ASubWindow(QDialog): Current text """ return self.find(QComboBox, name).currentText() - - - # Custom dialog - def file_dialog(self, select_file=True, callback=lambda x: None): - """Open a new file dialog and send result to callback function - - Args: - select_file: Select a file if True, else select a dir - callback: The callback function - - Returns: - Nothing - """ - dialog = QFileDialog(self) - - if select_file: - mode = QFileDialog.FileMode.ExistingFile - else: - mode = QFileDialog.FileMode.Directory - - dialog.setFileMode(mode) - - if dialog.exec_(): - file_names = dialog.selectedFiles() - callback(file_names) - - def message_box(self, text: str, - informative_text: str, - window_title: str = "Warning"): - """Open a new message box - - Args: - text: Short text string - informative_text: Verbose text string - window_title: Title of message box window - - Returns: - Nothing - """ - msg = QMessageBox() - - msg.setIcon(QMessageBox.Warning) - msg.setText(text) - msg.setInformativeText(informative_text) - msg.setWindowTitle(window_title) - - msg.exec_() diff --git a/src/View/ConfigureWindow.py b/src/View/ConfigureWindow.py index ff3f1b94..dbc37604 100644 --- a/src/View/ConfigureWindow.py +++ b/src/View/ConfigureWindow.py @@ -58,7 +58,9 @@ class SolverTableModel(QAbstractTableModel): class ConfigureWindow(ASubWindow, ListedSubWindow): def __init__(self, conf=None, title="Configure", parent=None): - super(ConfigureWindow, self).__init__(name=title, ui="ConfigureDialog", parent=parent) + super(ConfigureWindow, self).__init__( + name=title, ui="ConfigureDialog", parent=parent + ) self.ui.setWindowTitle(title) if conf is None: diff --git a/src/View/Geometry/qtableview_profile.py b/src/View/Geometry/qtableview_profile.py index 7f59e1bf..267d8862 100644 --- a/src/View/Geometry/qtableview_profile.py +++ b/src/View/Geometry/qtableview_profile.py @@ -5,8 +5,9 @@ from PyQt5.QtGui import QFont from PyQt5.QtWidgets import QMessageBox from PyQt5 import QtWidgets, QtGui from PyQt5.QtCore import QModelIndex, Qt, QAbstractTableModel, QVariant, QCoreApplication -from ProfileXYZ import ProfileXYZ -import projection_pointXYZ + +from Model.Geometry.ProfileXYZ import ProfileXYZ +from Model.Geometry.projection_pointXYZ import * _translate = QCoreApplication.translate diff --git a/src/View/Geometry/window_profileXYZ.py b/src/View/Geometry/window_profileXYZ.py new file mode 100644 index 00000000..9bf46c41 --- /dev/null +++ b/src/View/Geometry/window_profileXYZ.py @@ -0,0 +1,686 @@ +import copy +import sys +import csv +from time import time + +from PyQt5 import QtWidgets, QtGui +from PyQt5.QtCore import QModelIndex, Qt, QEvent, QCoreApplication +from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QCheckBox + +from View.Geometry.mainwindow_ui_profile import Ui_MainWindow + +from Model.Geometry.Reach import Reach +from View.Geometry.qtableview_profile import * + +from View.Plot.mpl_canvas_onpick_event import OnpickEvent + +_translate = QCoreApplication.translate + + +class View(QMainWindow): + + def __init__(self, profile_selected_num: int = 1, profile=None, pk=None, profile_name=None, parent=None): + self.parent = parent + + super(View, self).__init__(self.parent) + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + self.tableView = self.ui.tableView + self.my_canvas = self.ui.my_canvas + self.profile_selected_num = profile_selected_num + + self.pk = pk + self.profile_name = profile_name + + self.profile_selected = profile + self.window_title(self.pk, self.profile_name, self.profile_selected_num) + + self.setup_model() + self.setup_connections() + self.graph() + + self.model.dataChanged.connect(self.graph) + self.filters = "CSV files (*.csv)" + self.fileName = None + + self.tableView.installEventFilter(self) + self.status_change_tableview = False + + self.model.dataChanged.connect(self.tableview_is_modified) + + self.reference_data = None + self.ui.btn_go_back.setEnabled(False) + self.ui.btn_check.setEnabled(False) + self.model.dataChanged.connect(self.set_enable_cancel_btn) + self.model.dataChanged.connect(self.set_enable_validate_changes_btn) + self.ui.btn_reset.setEnabled(False) + self.model.dataChanged.connect(self.set_enable_go_back_initial_state_btn) + + def window_title(self, pk, profile_name=None, profile_selected_num=None): + if profile_name is None or profile_name == "": + profile_name = _translate("MainWindowProfile", "(sans nom)") + self.setWindowTitle(_translate("MainWindowProfile", f"Profil Pk = {pk} \t Section {profile_name} " + f"N°: {profile_selected_num + 1} (selon " + f"l'ordre du tableau)")) + + def tableview_is_modified(self): + self.status_change_tableview = True + print("tableview_is_modified... :", self.status_change_tableview) + + def setup_connections(self): + self.ui.btn_sort_asc_x.clicked.connect(self.sort_X_ascending) + self.ui.btn_sort_desc_x.clicked.connect(self.sort_X_descending) + self.ui.btn_sort_asc_y.clicked.connect(self.sort_Y_ascending) + self.ui.btn_sort_desc_y.clicked.connect(self.sort_Y_descending) + self.ui.btn_move_up.clicked.connect(self.move_row_up) + self.ui.btn_move_down.clicked.connect(self.move_row_down) + self.ui.btn_export.clicked.connect(self.handleSave) + self.ui.btn_add.clicked.connect(self.insert_row) + self.ui.btn_delete.clicked.connect(self.delete_row) + self.ui.btn_copy.clicked.connect(self.copyTable) + self.ui.btn_paste.clicked.connect(self.pasteTable) + self.ui.btn_check.clicked.connect(self.validate_changes) + + # self.button_moveUp.clicked.connect(self.graph) + # self.button_moveDown.clicked.connect(self.graph) + # self.button_moveUp.clicked.connect(self.myslot) + self.ui.btn_go_back.clicked.connect(self.cancel_validate_changes) + self.ui.btn_reset.clicked.connect(self.go_back_to_initial_state) + + def setup_model(self): + t0 = time() + if self.profile_selected is None: + # chemin = os.path.abspath(os.pardir) + # print(chemin) + # chemin = os.path.dirname(chemin) + # print(chemin) + # bief = reach.Bief(f"{chemin}/resources/Fichier_ST/Saar.ST") + bief = reach.Bief("../../resources/Fichier_ST/Saar.ST") + # bief = reach.Bief("PamHyrPyQt5/resources/Fichier_ST/test_Pamhyr.st") + # bief = reach.Bief("/home/sylvain.coulibaly/Bureau/testpamhyr/test_Pamhyr.st") + # bief = reach.Bief("C:/Users/csylv/Fichiers-ST/Saar.ST") + # bief = reach.Bief("C:/Users/csylv/Fichiers-ST/testpamhyr/test_Pamhyr.st") + print("** Debut création du modèle **") + profile_num = 0 + self.profile_default = bief.profile[profile_num] + self.window_title(bief.profile[0].pk, bief.profile[0].name, profile_num + 1) + self.model = qtableview_profile.PandasModelEditable(self.profile_default) + # self._last_saved_model_data = copy.deepcopy(self.profile_default) + # self._last_saved_model_data = copy.deepcopy(self.model.model_data) + # + # self.reference_data = copy.deepcopy(self.profile_default) + + else: + self.model = qtableview_profile.PandasModelEditable(self.profile_selected) + # self._last_saved_model_data = copy.deepcopy(self.profile_selected) + # self.reference_data = copy.deepcopy(self.profile_selected) + self._last_saved_model_data = copy.deepcopy(self.model.model_data) + self.__initial_model_data = copy.deepcopy(self.model.model_data) + + self.tableView.setModel(self.model) + self.tableView.setItemDelegate(qtableview_profile.Delegate()) + print(" ==> Modèle créé au bout de :", time() - t0, "s") + + def graph(self): + """ + Returns: Le tracé de la cote z en fonction de l'abscisse (calculée). + """ + x = self.model.station # abscisse en travers + y = self.model.z # cote z + ld = self.model.name # nom des points + x_carto = self.model.x # x 'cartographique' + y_carto = self.model.y # y 'cartographique' + + if len(self.model.x) >= 3 and len(self.model.y) >= 3 and len(self.model.station) >= 3: + + self.my_canvas.axes.cla() + self.my_canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5) + self.profile_line2D, = self.my_canvas.axes.plot(x, y, color='r', lw=1.5, markersize=7, marker='+', + picker=30) + # pickradius=5) + # print("type", type(self.profile_line2D)) + # self.my_canvas.axes.plot(self.model.profile.iloc[:, 4], self.model.profile.iloc[:, 2], vertical_slider_label='y(x)', color='r', + # lw=1.5, markersize=7, marker='+') + self.my_canvas.axes.set_xlabel(_translate("MainWindowProfile", "Abscisse en travers (m)"), color='black', + fontsize=10) + self.my_canvas.axes.set_ylabel(_translate("MainWindowProfile", "Cote (m)"), color='black', fontsize=10) + + # Ajout des étiquettes sur le graphe + self.annotation = [] + for i, txt in enumerate(list(ld)): + annotation = self.my_canvas.axes.annotate(txt, (x[i], y[i]), horizontalalignment='left', + verticalalignment='top', annotation_clip=True, fontsize=10, + color='black') + annotation.set_position((x[i], y[i])) + annotation.set_color("black") + self.annotation.append(annotation) + + al = 8. # arrow length in points + arrowprops = dict(clip_on=True, # plotting outside axes on purpose + # frac=1., # make end arrowhead the whole size of arrow + headwidth=5., # in points + facecolor='k') + kwargs = dict( + xycoords='axes fraction', + textcoords='offset points', + arrowprops=arrowprops, + ) + self.my_canvas.axes.annotate("", (1, 0), xytext=(-al, 0), **kwargs) + self.my_canvas.axes.annotate("", (0, 1), xytext=(0, -al), **kwargs) # left spin arrow + # self.my_canvas.axes.spines[['top', 'right']].set_visible( + # False) # pour enlever le 'cadre' en haut et à droite de la figure + self.my_canvas.axes.spines[['top', 'right']].set_color('none') + self.my_canvas.axes.yaxis.tick_left() # enlève les traits de graduation sur le côté gauche du graphique + self.my_canvas.axes.xaxis.tick_bottom() # enlève les traits de graduation sur la partie supérieure du graphique + self.my_canvas.axes.set_facecolor('#F9F9F9') # '#E0FFFF') + self.my_canvas.figure.patch.set_facecolor('white') + try: + self.onpick_event = OnpickEvent(self.my_canvas.axes, x, y, x_carto, y_carto, self.tableView) + self.my_canvas.figure.canvas.mpl_connect('pick_event', self.onpick_event.onpick) + + self.onclick_event = OnpickEvent(self.my_canvas.axes, x, y, x_carto, y_carto, self.tableView) + self.my_canvas.figure.canvas.mpl_connect('button_press_event', self.onclick_event.onclick) + except: + print("pas assez de points pour calculer la ligne d'eau") + self.my_canvas.figure.tight_layout() + + self.my_canvas.figure.canvas.draw_idle() + else: + self.my_canvas.axes.cla() + self.my_canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5) + + # def update_graphic(self): + # self.profile_line2D.set_data(self.model.station, self.model.z) + # print(self.annotation) + # for i, txt in enumerate(list(self.model.name)): + # self.annotation[i].set_text(txt) + # self.annotation[i].set_position((self.model.station[i] + 0.5, self.model.z[i])) + # # self.onpick_event = OnpickEvent(self.my_canvas.axes, self.model.station, self.model.z, self.model.x, self.model.y, + # # self.tableView) + # self.my_canvas.figure.canvas.mpl_connect('pick_event', self.onpick_event.onpick) + # + # # self.onclick_event = OnpickEvent(self.my_canvas.axes, self.model.station, self.model.z, self.model.x, + # # self.model.y, self.tableView) + # self.my_canvas.figure.canvas.mpl_connect('button_press_event', self.onclick_event.onclick) + # + # self.my_canvas.figure.canvas.draw_idle() + + def insert_row(self): + if len(self.tableView.selectedIndexes()) == 0: + self.model.insertRows(self.model.rowCount(), 1) + else: + rows = list(set([index.row() for index in self.tableView.selectedIndexes()])) + for row in rows: # [::-1]: + self.model.insertRows(row + 1, 1) + try: + self.graph() # mise à jour du graphique + except: + pass + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + def delete_row(self): + rows = list(set([index.row() for index in self.tableView.selectedIndexes()])) + # for row in rows:#[::-1]: + # self.model.removeRows(row, 1) + # + # self.graph() # mise à jour du graphique + + if len(rows) > 0: + self.model.remove_rows(rows) + + try: + self.graph() # mise à jour du graphique + except: + print("Plus rien à afficher") + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + def sort_X_ascending(self): + self.model.sort(0, order=Qt.AscendingOrder) + self.graph() + print("self.status_change_tableview ", self.status_change_tableview) + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + def sort_X_descending(self): + self.model.sort(0, order=Qt.DescendingOrder) + self.graph() + print("initial_state_model", self._last_saved_model_data) + print("self.status_change_tableview ", self.status_change_tableview) + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + def sort_Y_ascending(self): + self.model.sort(1, order=Qt.AscendingOrder) + self.graph() + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + def sort_Y_descending(self): + self.model.sort(1, order=Qt.DescendingOrder) + self.graph() + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + def move_row_down(self): + rows = list(set([index.row() for index in self.tableView.selectedIndexes()])) + for row in rows: + if row < self.model.rowCount() - 1: # on s'arrête à la dernière ligne du tableau + self.model.moveRowDown(row) + self.graph() + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + # print("profile.x ", self.model.profile.x) + + def move_row_up(self): + rows = list(set([index.row() for index in self.tableView.selectedIndexes()])) + for row in rows: + if 0 < row: # on s'arrête lorsqu'on est à l'index 0 ie la première ligne + self.model.moveRowUp(row) + self.graph() + print("status_change_tableview", self.status_change_tableview) + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + def eventFilter(self, source, event): + if event.type() == QEvent.KeyPress: + if event == QtGui.QKeySequence.Copy: + # self.copySelection() + self.copyTable() + print("copie") + return True + elif event == QtGui.QKeySequence.Paste: + # self.pasteSelection() + self.pasteTable() + return True + elif event.type() == QEvent.ContextMenu: + + # a context icons for the copy/paste operations + menu = QtWidgets.QMenu() + copyAction = menu.addAction('Copy') + # copyAction.triggered.connect(self.copySelection) + # self.button_copy.triggered.connect(self.copyTable) + pasteAction = menu.addAction('Paste') + # pasteAction.triggered.connect(self.pasteSelection) + # self.button_paste.triggered.connect(self.pasteTable) + if not self.tableView.selectedIndexes(): + pass + # no selection available, both copy and paste are disabled + # copyAction.setEnabled(False) + + # if not self.clipboard: + # pass + # # no clipboard contents, paste is disabled + # pasteAction.setEnabled(False) + # self.button_paste.setEnabled(False) + # icons.exec(event.globalPos()) + # icons.exec(event.globalPos()) + return True + # self.button_copy.setEnabled(False) + # self.button_paste.setEnabled(False) + return super(View, self).eventFilter(source, event) + + def copySelection(self): + # clear the current contents of the clipboard + self.clipboard.clear() + selected = self.tableView.selectedIndexes() + rows = [] + columns = [] + # cycle all selected items to get the minimum row and column, so that the + # reference will always be [0, 0] + for index in selected: + rows.append(index.row()) + columns.append(index.column()) + minRow = min(rows) + minCol = min(columns) + print(minCol) + print(minRow, columns) + for index in selected: + # append the profile of each selected index + self.clipboard.append((index.row() - minRow, index.column() - minCol, index.data_frame())) + # self.clipboard.append((index.row(), index.column() , index.profile())) + + def pasteSelection(self): + if not self.clipboard: + return + current = self.tableView.currentIndex() + if not current.isValid(): + # in the rare case that there is no current index, use the first row + # and column as target + current = self.model.index(0, 0) + + firstRow = current.row() + firstColumn = current.column() + + # optional: get the selection model so that pasted indexes will be + # automatically selected at the end + selection = self.tableView.selectionModel() + print(self.clipboard) + for row, column, data in self.clipboard: + # get the index, with rows and columns relative to the current + # index = self.model.index(firstRow + row, firstColumn + column) + index = self.model.index(firstRow, column) + + # set the profile for the index + self.model.setData(index, data, Qt.EditRole) # Qt.DisplayRole) + # add the index to the selection + selection.select(index, selection.Select) + + # apply the selection model + self.tableView.setSelectionModel(selection) + + def copyTable(self): + if len(self.tableView.selectedIndexes()) == 0: + self.model.copyTable(0, self.model.rowCount()) + else: + rows = list(set([index.row() for index in self.tableView.selectedIndexes()])) + rows.sort() # pour trier la liste afin de respecter l'ordre des lignes sélectionnées en collant + print(rows) + df = self.model.model_data.loc[rows, :] + df.to_clipboard(header=None, index=False, excel=True, sep='\t') + + def pasteTable(self): + # self.tableView.clearSelection() + if len(self.tableView.selectedIndexes()) == 0: + + self.model.pasteTable(self.model.rowCount()) + else: + rows = list(set([index.row() for index in self.tableView.selectedIndexes()])) + # rows.sort() # pour trier la liste afin de respecter l'ordre des lignes sélectionnées en collant + for row in rows: + try: + self.model.pasteTable(row + 1) + except: + print("Le collage n'est pas réussi") + print(rows) + self.graph() + self.status_change_tableview = True + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + self.ui.btn_reset.setEnabled(True) + + # try: + # self.model.pasteTable() + # self.graph() + # print(" Collage réussi !") + # except: + # pass + # print("Le collage n'a pas été effectué. Vérifier que vous avez copié depuis un presse-papier au format " + # "tabulé") + + def handleSave(self): + print("handleSave") + if self.fileName is None or self.fileName == '': + self.fileName, self.filters = QFileDialog.getSaveFileName(self, filter=self.filters) + if self.fileName != '': + with open(self.fileName, 'w') as stream: + csvout = csv.writer(stream, delimiter='\t', quotechar=' ', escapechar=None, + quoting=csv.QUOTE_NONNUMERIC, lineterminator='\n') + # csvout.writerow(self.headers) + for row in range(self.model.rowCount(QModelIndex())): + print(self.model.rowCount(QModelIndex())) + rowdata = [] + for column in range(self.model.columnCount(QModelIndex())): + item = self.model.index(row, column, QModelIndex()).data(Qt.DisplayRole) + # if column == 0: + # rowdata.append('') + # continue + + if item is not None: + rowdata.append(item) + if item == 'nan': + rowdata.remove(item) + else: + pass # rowdata.append('') + csvout.writerow(rowdata) + print(rowdata) + + def handleOpen(self): + print("handleOpen") + self.fileName, self.filterName = QFileDialog.getOpenFileName(self) + + if self.fileName != '': + with open(self.fileName, 'r') as f: + reader = csv.reader(f, delimiter='\t') + header = next(reader) + buf = [] + for row in reader: + row[0] = QCheckBox("-") + buf.append(row) + + self.model = None + self.model = qtableview_profile.PandasModelEditable(buf) + self.tableView.setModel(self.model) + self.fileName = '' + + def cancel_validate_changes(self): + # if self.profile_selected is None: + # self._last_saved_model_data = copy.deepcopy(self.profile_default) + # else: + # self._last_saved_model_data = copy.deepcopy(self.profile_selected) + # data = pd.DataFrame({"x": self._last_saved_model_data.x, "y": self._last_saved_model_data.y, + # "z": self._last_saved_model_data.z, "ld": self._last_saved_model_data.ld, + # "abs": projection_pointXYZ.get_station(self._last_saved_model_data) + # + # }) + # self._data = data + # self.model.model_data = data + + self.model.model_data = copy.deepcopy(self._last_saved_model_data) + print(self.model.model_data) + + # print(data) + self.graph() + self.ui.btn_go_back.setEnabled(False) + + # self.button_cancel_validate.setEnabled(False) + # self.status_change_tableview = True + + def validate_changes(self): + # self.model.validate_changes() + self.remove_duplicates_point_names() + # self.model.delete_empty_rows() + self.delete_empty_rows() + + # if self.profile_selected is None: + # #self._last_saved_model_data = copy.deepcopy(self.profile_default) + # self._last_saved_model_data = copy.deepcopy(self.model.model_data) + # + # # self.profile_selected == copy.deepcopy( + # else: + # #self._last_saved_model_data = copy.deepcopy(self.profile_selected) + # self._last_saved_model_data = copy.deepcopy(self.model.profile) + self._last_saved_model_data = copy.deepcopy(self.model.model_data) + # self._last_saved_model_data = copy.deepcopy(self.model.model_data) + self.ui.btn_check.setEnabled(False) + self.ui.btn_go_back.setEnabled(False) + self.status_change_tableview = False + self.graph() + self.model.valide_all_changes() + self.parent.update_graphic_2() + self.parent.update_graphic_1() + self.selected_row = list(set([index.row() for index in self.parent.tableView.selectedIndexes()])) + self.parent.update_graphic_3(self.selected_row[0]) + + # self._last_saved_model_data = copy.deepcopy(self.model.profile) + + def set_enable_validate_changes_btn(self): + self.ui.btn_check.setEnabled(True) + + def set_enable_cancel_btn(self): + self.ui.btn_go_back.setEnabled(True) + + def set_enable_go_back_initial_state_btn(self): + self.ui.btn_reset.setEnabled(True) + + # self._last_saved_model_data = copy.deepcopy(self.profile_default) + + def delete_empty_rows(self): + if self.model.data_contains_nan(): + buttonReply = QtWidgets.QMessageBox.question(self, _translate("MainWindowProfile", "Suppression les lignes " + "incomplètes"), + _translate("MainWindowProfile", "Supprimer les" + " lignes des cellules non " + "renseignées ?"), + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) + print(int(buttonReply)) + + if buttonReply == QtWidgets.QMessageBox.Yes: + print('Yes clicked.') + self.model.delete_empty_rows() + # self._last_saved_model_data = copy.deepcopy(self.model.model_data) + if buttonReply == QtWidgets.QMessageBox.No: + # self._last_saved_model_data = copy.deepcopy(self.model.model_data) + print(self.model.model_data) + pass + + def remove_duplicates_point_names(self): + counter_list = [] + list_deleted_names = [] + # is_removed = False + for ind, name_point in enumerate(self.model.name): + if name_point not in counter_list: + counter_list.append(name_point) + + elif len(name_point.strip()) > 0 and name_point in counter_list: + # is_removed = True + # self.msg_question(self.model.get_data(), ind) + # self._data.iat[ind, 3] = "" + # self._remove_duplicates_names() + if name_point not in list_deleted_names: + list_deleted_names.append(name_point) + print("mon indddddd", ind) + if list_deleted_names: + self.msg_box_check_duplication_names(list_deleted_names) + + def go_back_to_initial_state(self): + + reply = QtWidgets.QMessageBox.question(self, _translate("MainWindowProfile", "Retour à l'état initial "), + _translate("MainWindowProfile", "Voulez-vous vraiment annuler toutes " + "les modifications?\n\n " + "\tOui : Revenir à l'état initial\n" + "\tNon : Garder l'état actuel des " + "données du profil"), + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) + + if reply == QtWidgets.QMessageBox.Yes: + self.model.model_data = copy.deepcopy(self.__initial_model_data) + self.model.valide_all_changes() + self.graph() + self.ui.btn_reset.setEnabled(False) + self.ui.btn_check.setEnabled(False) + self.ui.btn_go_back.setEnabled(False) + if reply == QtWidgets.QMessageBox.No: + pass + + def closeEvent(self, event): + # self.vrai =True + if self.status_change_tableview: + reply = QtWidgets.QMessageBox.question(self, + _translate("MainWindowProfile", "Terminer l'édition du profil "), + _translate("MainWindowProfile", "Voulez-vous vraiment quitter " + "?\n Oui : Valider et quitter\n" + "Non : Annuler"), + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) + + if reply == QtWidgets.QMessageBox.Yes: + self.validate_changes() + self.graph() + event.accept() + else: + # data = pd.DataFrame({"a": self._last_saved_model_data.x, "b": self._last_saved_model_data.y, + # "c": self._last_saved_model_data.z, "d": self._last_saved_model_data.ld, + # "e": projection_pointXYZ.get_station(self._last_saved_model_data) + # + # }) + # # self._data = data + # self.model.model_data = data + # + event.ignore() + self.ui.btn_check.setEnabled(True) + self.ui.btn_go_back.setEnabled(True) + + def msg_box_check_duplication_names(self, list_deleted_names): # name_point,list_deleted_names,counter_list): + if len(list_deleted_names) == 1: + text = _translate("MainWindowProfile", "Le nom ''{}'' est dupliqué." + " \n\nYes : Ne garder que la première occurrence. \nNo :" + " Annuler la suppression.".format(list_deleted_names[0])) + else: + text = _translate("MainWindowProfile", "Les noms suivants : \n{} sont dupliqués" + " \n\nYes : Ne garder que la première occurrence de " + "chaque nom. \nNo : Annuler la suppression.".format(list_deleted_names)) + buttonReply = QtWidgets.QMessageBox.question(self, _translate("MainWindowProfile", + "Suppression des noms répétés"), + text, + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) + print(int(buttonReply)) + + if buttonReply == QtWidgets.QMessageBox.Yes: + print('Yes clicked.') + self.model.remove_duplicates_names() + if buttonReply == QtWidgets.QMessageBox.No: + print('No clicked.') + # if buttonReply == QtWidgets.QMessageBox.Cancel: + # print('Cancel') + + # def showDialog(self): + # msgBox = QtWidgets.QMessageBox() + # msgBox.setIcon(QtWidgets.QMessageBox.Information) + # msgBox.setText("Message box pop up window") + # msgBox.setWindowTitle("QMessageBox Example") + # msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) + # msgBox.buttonClicked.connect(self.msgButtonClick) + # + # returnValue = msgBox.exec() + # if returnValue == QtWidgets.QMessageBox.Ok: + # print('OK clicked') + # self.model._remove_duplicates_names() + + def msg_button_click(self, i): + print("Button clicked is:", i.text()) + + def ask_quit(self): + choice = QtWidgets.QMessageBox.question(self, _translate("MainWindowProfile", "Quittez ?"), + _translate("MainWindowProfile", "Etes-vous sûr de vouloir quitter ?"), + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) + return choice == QtWidgets.QMessageBox.Yes + + def initial_state_model(self, profile_initial_state): + # profile_initial_state = self.profile_selected + return profile_initial_state + + +if __name__ == '__main__': + # http://www.xavierdupre.fr/blog/2014-04-12_nojs.html + # import cProfile + # import re + + app = QApplication(sys.argv) + app.setStyle("Fusion") # 'Breeze', 'Oxygen', 'QtCurve', 'Windows', 'Fusion' + table = View() + table.show() + # cProfile.run('View()') + # translator = QtCore.QTranslator(app) + # locale = QtCore.QLocale.system().name() + # path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath) + # translator.load('qt_%s' % locale, path) + # app.installTranslator(translator) + sys.exit(app.exec_()) diff --git a/src/View/GeometryWindow.py b/src/View/GeometryWindow.py index f6dfba24..c39d24da 100644 --- a/src/View/GeometryWindow.py +++ b/src/View/GeometryWindow.py @@ -16,13 +16,14 @@ from PyQt5.QtWidgets import ( from View.Geometry.mainwindow_ui_reach import Ui_MainWindow from View.Geometry import qtableview_reach from View.Geometry import window_profileXYZ +from View.ASubWindow import WindowToolKit _translate = QCoreApplication.translate -class GeomatryWindow(ASubWindow): +class GeometryWindow(QMainWindow, WindowToolKit): def __init__(self, parent=None): self.parent = parent - super(MainReach, self).__init__() + super(GeometryWindow, self).__init__(parent=parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) @@ -57,7 +58,7 @@ class GeomatryWindow(ASubWindow): def open_file_dialog(self): options = QFileDialog.Options() DEFAULT_DIRECTORY = '/home/' - settings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'MyOrg', ) # application='MyApp', ) + settings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'MyOrg', ) current_dir = settings.value('current_directory', DEFAULT_DIRECTORY, type=str) options |= QFileDialog.DontUseNativeDialog self.filename, _ = QtWidgets.QFileDialog.getOpenFileName( diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index 1a4af585..01e09bee 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -18,6 +18,7 @@ from View.DummyWindow import DummyWindow from View.ConfigureWindow import ConfigureWindow from View.NewStudyWindow import NewStudyWindow from View.NetworkWindow import NetworkWindow +from View.GeometryWindow import GeometryWindow from View.AboutWindow import AboutWindow from Model.Study import Study @@ -107,7 +108,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow): "action_toolBar_listing": self.open_dummy, ## Current actions "action_toolBar_network": self.open_network, - "action_toolBar_geometry": lambda: self.open_dummy("Geomerty"), + "action_toolBar_geometry": self.open_geometry, "action_toolBar_mesh": lambda: self.open_dummy("Mesh"), "action_toolBar_run_meshing_tool": lambda: self.open_dummy("Lancement mailleur externe"), "action_toolBar_boundary_cond": lambda: self.open_dummy("Condition Limites"), @@ -291,6 +292,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow): self.network = NetworkWindow(model=self.model, parent=self) self.network.show() + def open_geometry(self): + if not self.model is None: + geometry = GeometryWindow(parent=self) + geometry.show() + # TODO: Delete me ! ############### # DUMMY STUFF # -- GitLab