diff --git a/src/model/Study.py b/src/model/Study.py index 5379ed9653aef8639040d70bb15ff79cd994112e..06a6c2caf07624e231ee444b6264945da9088a5a 100644 --- a/src/model/Study.py +++ b/src/model/Study.py @@ -5,22 +5,31 @@ from datetime import datetime from model.Serializable import Serializable class Study(Serializable): - def __init__(self, name, filename, data): + def __init__(self): # Serialization information - super(Study, self).__init__(filename) - self.filename = filename + super(Study, self).__init__("") + self.filename = "" # Study general information - self.name = name - self.comment = "" + self.name = "" + self.description = "" + self.solver = "" self.creation_date = datetime.now() self.last_modification_date = datetime.now() self.last_save_date = datetime.now() # Study data - self.data = data + self.data = {} @classmethod - def new(cls, name, filename): - return cls(name, filename, {}) + def new(cls): + return cls() + + @classmethod + def new(cls, name, description, solver): + me = cls() + me.name = name + me.description = description + me.solver = solver + return me diff --git a/src/view/ASubWindow.py b/src/view/ASubWindow.py index 3f01e02c56d9de77e3fc097ce958cd554a651ae4..5ef00fca08e59e8df7140821375fc43af5cc2cfc 100644 --- a/src/view/ASubWindow.py +++ b/src/view/ASubWindow.py @@ -6,7 +6,8 @@ from PyQt5.QtWidgets import ( QMainWindow, QApplication, QDesktopWidget, QMdiArea, QMdiSubWindow, QDialog, QPushButton, QLineEdit, QCheckBox, - QTimeEdit, QSpinBox + QTimeEdit, QSpinBox, QTextEdit, + QRadioButton, ) from PyQt5.QtCore import ( QTime, @@ -65,6 +66,29 @@ class ASubWindow(QDialog): """ return self.find(QLineEdit, name).text() + def set_text_edit_text(self, name:str, text:str): + """Set text of text edit component + + Args: + text_edit: The text edit component name + text: The text + + Returns: + Nothing + """ + self.find(QTextEdit, name).setText(text) + + def get_text_edit_text(self, name:str): + """Get text of text edit component + + Args: + text_edit: The text edit component name + + Returns: + Text + """ + return self.find(QTextEdit, name).toHtml() + def set_check_box(self, name:str, checked:bool): """Set status of checkbox component @@ -135,3 +159,26 @@ class ASubWindow(QDialog): The value of spin box """ return self.find(QSpinBox, name).value() + + def set_radio_button(self, name:str, checked:bool): + """Set value of spinbox component + + Args: + name: The spinbox component name + value: The new value + + Returns: + Nothing + """ + self.find(QRadioButton, name).setChecked(checked) + + def get_radio_button(self, name:str): + """Get status of radio button + + Args: + name: The radio button component name + + Returns: + The status of radio button + """ + return self.find(QRadioButton, name).isChecked() diff --git a/src/view/ConfigureWindow.py b/src/view/ConfigureWindow.py index c633c2ce3376a0cac36c51dc05671ab6a7b6751b..ebb083ffb255c8ce1b0a597b136be59515db9b22 100644 --- a/src/view/ConfigureWindow.py +++ b/src/view/ConfigureWindow.py @@ -76,6 +76,7 @@ class ConfigureWindow(ASubWindow): def file_dialog(self, line_edit, select_file): dialog = QFileDialog(self) + if select_file: mode = QFileDialog.FileMode.ExistingFile else: diff --git a/src/view/MainWindow.py b/src/view/MainWindow.py index b13bebf0fd1e9a469622f52c4be8cbcfdf922aeb..640caef84521f13f9fa5d5f16e098bdd3a881765 100644 --- a/src/view/MainWindow.py +++ b/src/view/MainWindow.py @@ -5,12 +5,14 @@ import os from PyQt5 import QtGui from PyQt5.QtWidgets import ( QMainWindow, QApplication, QAction, + QFileDialog, ) from PyQt5.uic import loadUi from view.ListedSubWindow import ListedSubWindow from view.DummyWindow import DummyWindow from view.ConfigureWindow import ConfigureWindow +from view.NewStudyWindow import NewStudyWindow from view.AboutWindow import AboutWindow from model.Study import Study @@ -83,10 +85,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow): # Menu action "actionA_propos": self.open_about, "actionConfiguration_de_Pamhyr": self.open_configure, + "actionR_seau": self.open_new_study, + "actionEnregistrer_2": self.save_study, + "actionEnregistrer_sous": self.save_as_study, # ToolBar action "actionquitter_application": self.close, - "actionOuvrir_une_tude": self.dummy_model, - "actionenregistrer_etude_en_cours": self.open_dummy, + "actionOuvrir_une_tude": self.open_model, + "actionenregistrer_etude_en_cours": self.save_study, "actionfermer_etude_en_cours": self.close_model, "actionlancer_solveur": self.open_dummy, "actioninterrompt_simulation_en_cours": self.open_dummy, @@ -153,6 +158,49 @@ class ApplicationWindow(QMainWindow, ListedSubWindow): for action in model_action: self.enable_actions(action, not no_model) + ############ + # FEATURES # + ############ + + def save_study(self): + """Save current study + + Save current study, if study as no associate file, open a + file dialog. + + Returns: + Nothing + """ + if self.model.filename == "": + file_name, _ = QFileDialog.getSaveFileName( + self, "Save File", + "", "Pamhyr(*.pkl)") + if file_name[-4:] == ".pkl": + self.model.filename = file_name + else: + self.model.filename = file_name + ".pkl" + + self.model.save() + + def save_as_study(self): + """Save current study as new file + + Save current study as new file, if study as no associate file, + open a file dialog. + + Returns: + Nothing + """ + file_name, _ = QFileDialog.getSaveFileName( + self, "Save File", + "", "Pamhyr(*.pkl)") + if file_name[-4:] == ".pkl": + self.model.filename = file_name + else: + self.model.filename = file_name + ".pkl" + + self.model.save() + ############# # SUBWINDOW # ############# @@ -179,6 +227,34 @@ class ApplicationWindow(QMainWindow, ListedSubWindow): self.about = AboutWindow(parent=self) self.about.show() + def open_model(self): + """Open file dialog to select saved model + + Returns: + Nothing + """ + if self.model is None: + dialog = QFileDialog(self) + dialog.setFileMode(QFileDialog.FileMode.ExistingFile) + dialog.setDefaultSuffix(".pkl") + #dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden) + dialog.setNameFilters(['PKL (*.pkl)']) + + if dialog.exec_(): + file_name = dialog.selectedFiles() + self.set_model(Study.open(file_name[0])) + print(f"[MainWindow] Open Study : {self.model.name}") + + def open_new_study(self): + """Open dialog to set new study + + Returns: + Nothing + """ + if self.model is None: + self.new_study = NewStudyWindow(parent=self) + self.new_study.show() + # TODO: Delete me ! ############### # DUMMY STUFF # diff --git a/src/view/NewStudyWindow.py b/src/view/NewStudyWindow.py new file mode 100644 index 0000000000000000000000000000000000000000..28719fa4b62a662c1dd690746abd9315778ca0d2 --- /dev/null +++ b/src/view/NewStudyWindow.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from model.Study import Study +from view.ASubWindow import ASubWindow + +class NewStudyWindow(ASubWindow): + def __init__(self, title="New Study", parent=None): + super(NewStudyWindow, self).__init__(name=title, ui="NewStudy", parent=parent) + self.ui.setWindowTitle(title) + + self.parent = parent + + def accept(self): + name = self.get_line_edit_text("lineEdit_name") + description = self.get_text_edit_text("textEdit_description") + if self.get_radio_button("radioButton_mage"): + solver = "mage" + else: + solver = "rubarbe" + + self.parent.set_model(Study.new(name, description, solver)) + self.close() diff --git a/src/view/ui/NewStudy.ui b/src/view/ui/NewStudy.ui new file mode 100644 index 0000000000000000000000000000000000000000..254d51c334b954c29c7db192eed6ad98cd02cf3c --- /dev/null +++ b/src/view/ui/NewStudy.ui @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>560</width> + <height>350</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <widget class="QWidget" name=""> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>541</width> + <height>331</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Name</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QTextEdit" name="textEdit_description"> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="tabChangesFocus"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Description</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEdit_name"> + <property name="text"> + <string>MyNewStudy</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Solver</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QRadioButton" name="radioButton_mage"> + <property name="text"> + <string>Mage</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButton_rubarbe"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Rubarbe</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Dialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Dialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>