class SelectPlayersWindow(QDialog): def __init__(self, parent=None): super(SelectPlayersWindow, self).__init__(parent) self.parent = parent self.setModal(True) self.setWindowTitle("Torna résztvevők") self.resize(520, 600) self.layout = QVBoxLayout() self.setLayout(self.layout) self.read_config() self.create_torna_selection() self.nevek_layout = QHBoxLayout() self.layout.addLayout(self.nevek_layout) self.show_saved_players() self.show_torna_players() self.gomb_nev_layout = QVBoxLayout() self.nevek_layout.addLayout(self.gomb_nev_layout) self.show_current_players() self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonbox.clicked.connect(self.buttonbox_click) self.layout.addWidget(self.buttonbox) def create_torna_selection(self): self.tournaments = QComboBox() self.tournaments.setModelColumn(0) self.tournaments.currentIndexChanged.connect(self.torna_valasztas) self.layout.addWidget(self.tournaments) self.load_torna() def load_torna(self): torna = QSqlQueryModel() query = QSqlQuery("select * from torna_settings where aktiv=2") torna.setQuery(query) if torna.record(0).value(0): for i in range(torna.rowCount()): self.tournaments.addItem( torna.record(i).value(1), torna.record(i).value(0)) # a value(0) a torna_id else: print("Nincs aktív torna") def show_saved_players(self): self.saved_players = QListWidget() self.saved_players.setFixedHeight(500) self.saved_players.setFixedWidth(150) self.saved_players.setSortingEnabled(True) self.saved_players.itemDoubleClicked.connect(self.add_resztvevo) self.load_saved_players() self.nevek_layout.addWidget(self.saved_players) def show_torna_players(self): self.torna_players = QListWidget() self.torna_players.setFixedHeight(500) self.torna_players.setFixedWidth(150) self.torna_players.setSortingEnabled(True) self.torna_players.itemDoubleClicked.connect(self.add_resztvevo) self.load_torna_players() self.nevek_layout.addWidget(self.torna_players) def load_saved_players(self): players = QSqlQueryModel() players_query = QSqlQuery("select * from players where aktiv=1") players.setQuery(players_query) self.saved_players.clear() for i in range(players.rowCount()): item = QListWidgetItem(players.record(i).value(1)) item.setData(Qt.UserRole, players.record(i).value(0)) self.saved_players.addItem(item) def load_torna_players(self): players = QSqlQueryModel() players_query = QSqlQuery( "select * from torna_resztvevok where 1 group by player_id, player_name" ) players.setQuery(players_query) self.torna_players.clear() for i in range(players.rowCount()): item = QListWidgetItem(players.record(i).value(1)) item.setData(Qt.UserRole, players.record(i).value(0)) self.torna_players.addItem(item) def add_resztvevo(self, item): new_item = QListWidgetItem(item) new_item.setData(Qt.UserRole, item.data(Qt.UserRole)) self.current_players.addItem(new_item) query = QSqlQuery( f"insert into torna_resztvevok (player_id, player_name, torna_id) values ({new_item.data(Qt.UserRole)}, '{new_item.text()}', {self.torna_id})" ) query.exec_() def show_current_players(self): query = QSqlQuery("select max(player_id) from torna_resztvevok") query.exec_() while query.next(): self.first_new_id = int(query.value(0)) + 1 print(self.first_new_id) self.add_new = QPushButton("Új") self.add_new.clicked.connect(self.uj_ember) self.current_players = QListWidget() self.current_players.setFixedHeight(470) self.current_players.setFixedWidth(150) self.current_players.setSortingEnabled(True) self.gomb_nev_layout.addWidget(self.add_new) self.current_players.itemDoubleClicked.connect(self.remove_resztvevo) self.gomb_nev_layout.addWidget(self.current_players) def uj_ember(self): ujember, ok = QInputDialog.getText( self, "Új versenyző", '<html style="font-size: 15px;">Írd be a versenyző nevét!</html>') if ok and len(ujember): item = QListWidgetItem(ujember) item.setData(Qt.UserRole, self.first_new_id) self.current_players.addItem(item) self.first_new_id += 1 query = QSqlQuery( f"insert into torna_resztvevok (player_id, player_name, torna_id) values ({item.data(Qt.UserRole)}, '{item.text()}', {self.torna_id})" ) query.exec_() def remove_resztvevo(self, item): self.current_players.takeItem( self.current_players.row(self.current_players.selectedItems()[0])) # print(item.data(Qt.UserRole), item.text()) query = QSqlQuery( f"delete from torna_resztvevok where player_id={item.data(Qt.UserRole)} and torna_id={self.torna_id}" ) query.exec_() def torna_valasztas(self, i): self.torna_id = self.tournaments.itemData(i) players = QSqlQueryModel() players_query = QSqlQuery( f"select * from torna_resztvevok where torna_id={self.torna_id}") players.setQuery(players_query) self.current_players.clear() for i in range(players.rowCount()): item = QListWidgetItem(players.record(i).value(1)) item.setData(Qt.UserRole, players.record(i).value(0)) self.current_players.addItem(item) def buttonbox_click(self, b): if b.text() == "OK": self.accept() elif b.text() == "Cancel": self.reject() def accept(self): # for i in range(self.current_players.count()): # item = self.current_players.item(i) # print(self.torna_id, item.data(Qt.UserRole), item.text()) # itt vannak a beszúrandó adatok super().accept() # INSERT INTO `torna_resztvevok` (`player_id`, `player_name`, `torna_id`) # VALUES ('1111', 'teszt_user2', '8892') ON DUPLICATE KEY UPDATE player_name='teszt_user2'; def read_config(self): if os.path.exists('config.ini'): # Van config.ini, ki kell értékelni config.read('config.ini') self.station_id = config['DEFAULT'].get('station id') self.secret = config['DEFAULT'].get('secret key') # todo módosítani kell a torna_match táblát, hogy tartalmazza a tabla mellett a hozzá tartozó secret-et is else: # Nincs config.ini, alapértékekkel inicializálni msg = QMessageBox(self) msg.setStyleSheet("fonz-size: 20px") msg.setWindowTitle("Hiányzó beállítás file!") msg.setText( '<html style="font-size: 14px; color: red">Nem tudtam beolvasni a konfigurációt!<br></html>' + '<html style="font-size: 16px">Kérem módosítsa a beállításokat!</html>' ) msg.exec_() sys.exit(1)
class MyWindow(QWidget): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle( 'Graphical utility for destroying, zeroing, and deleting files') self.label_donate = QLabel( 'Copyright (c) 2021, Aleksandr Suvorov | Donate: 4048 0250 0089 5923' ) self.label_donate.setAlignment(Qt.AlignCenter) self.label_logo = QLabel(f'Smart Cleaner<sup> {VERSION}</sup>') self.label_logo.setAlignment(Qt.AlignCenter) self.label_logo.setStyleSheet('font-size: 48px;') self.label_files = QLabel('Files') self.label_files.setStyleSheet("color: rgb(84, 180, 40);") self.label_dirs = QLabel('Folders') self.label_dirs.setStyleSheet("color: rgb(177, 98, 42);") self.label_errors = QLabel('Errors') self.label_errors.setStyleSheet("color: rgb(255, 68, 44);") self.lcd_files = QLCDNumber() self.lcd_files.setSegmentStyle(QLCDNumber.Flat) self.lcd_files.setStyleSheet("color: rgb(84, 180, 40);") self.lcd_dirs = QLCDNumber() self.lcd_dirs.setSegmentStyle(QLCDNumber.Flat) self.lcd_dirs.setStyleSheet("color: rgb(177, 98, 42);") self.lcd_errors = QLCDNumber() self.lcd_errors.setSegmentStyle(QLCDNumber.Flat) self.lcd_errors.setMinimumHeight(30) self.lcd_errors.setStyleSheet("color: rgb(255, 68, 44);") self.lcd_files.setDigitCount(15) self.lcd_dirs.setDigitCount(15) self.lcd_errors.setDigitCount(15) self.h_box1 = QHBoxLayout() self.h_box1.addWidget(self.label_dirs) self.h_box1.addWidget(self.label_files) self.h_box1.addWidget(self.label_errors) self.h_box2 = QHBoxLayout() self.h_box2.addWidget(self.lcd_dirs) self.h_box2.addWidget(self.lcd_files) self.h_box2.addWidget(self.lcd_errors) self.label_cons = QLabel('Information console:') self.text_browser = QTextBrowser() self.text_browser.setText( f'Smart Cleaner v{VERSION} \nUtility for overwriting, zeroing, and deleting files\n' f'https://github.com/mysmarthub') self.btn_console_clear = QPushButton('Reset') self.btn_donate = QPushButton('Donate | Visa: 4048 0250 0089 5923') self.btn_donate.setToolTip( 'We will be grateful for any financial support.\nThis will help the program ' 'develop and remain free.\nThanks!') self.btn_exit = QPushButton('Exit') self.h_box3 = QHBoxLayout() self.h_box3.addWidget(self.btn_donate) self.h_box3.addStretch(1) self.h_box3.addWidget(self.btn_console_clear) self.chb_del_dirs = QCheckBox('Delete folders') self.chb_del_dirs.setChecked(True) self.label_shred = QLabel('Rewrite:') self.spin_box = QSpinBox() self.spin_box.setMinimum(1) self.spin_box.setMaximum(1000) self.spin_box.setValue(30) self.h_box4 = QHBoxLayout() self.h_box4.addWidget(self.chb_del_dirs) self.h_box4.addWidget(self.label_shred) self.h_box4.addWidget(self.spin_box) self.h_box4.addStretch(1) self.list_widget = QListWidget() self.list_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.btn_add_folder = QPushButton('+ Folder') self.btn_add_files = QPushButton('+ Files') self.btn_remove_item = QPushButton('- Remove') self.btn_zero_files = QPushButton('Zeroing') self.btn_shred_files = QPushButton('Erasing') self.btn_del_files = QPushButton('Delete') self.h_box5 = QHBoxLayout() self.h_box5.addWidget(self.btn_add_folder) self.h_box5.addWidget(self.btn_add_files) self.h_box5.addWidget(self.btn_remove_item) self.h_box5.addStretch(1) self.h_box5.addWidget(self.btn_shred_files) self.h_box5.addWidget(self.btn_zero_files) self.h_box5.addWidget(self.btn_del_files) self.h_box5.addWidget(self.btn_exit) self.v_box = QVBoxLayout() self.v_box.addWidget(self.label_logo) self.v_box.addLayout(self.h_box1) self.v_box.addLayout(self.h_box2) self.v_box.addWidget(self.label_cons) self.v_box.addWidget(self.text_browser) self.v_box.addLayout(self.h_box3) self.v_box.addLayout(self.h_box4) self.v_box.addWidget(self.list_widget) self.v_box.addLayout(self.h_box5) self.v_box.addWidget(self.label_donate) self.setLayout(self.v_box) self.smart_cleaner = SmartCleaner() self.btn_donate.clicked.connect( lambda: webbrowser.open('https://yoomoney.ru/to/4100115206129186')) self.btn_console_clear.clicked.connect(self.clear_console) self.btn_add_folder.clicked.connect(self.add_dir) self.btn_add_files.clicked.connect(self.add_files) self.btn_remove_item.clicked.connect(self.remove_items) self.btn_shred_files.clicked.connect(self.shred_start) self.btn_zero_files.clicked.connect(self.zeroing_start) self.btn_del_files.clicked.connect(self.delete_start) self.btn_exit.clicked.connect(self.close) self.smart_cleaner.signal.connect(self.update_information) self.smart_cleaner.started.connect(self.at_start) self.smart_cleaner.finished.connect(self.at_finish) def clear_console(self): self.lcd_dirs.display(0) self.lcd_files.display(0) self.lcd_errors.display(0) self.text_browser.setText( f'Smart Cleaner v{VERSION} \nUtility for overwriting, zeroing, and deleting files\n' f'https://github.com/mysmarthub') def add_dir(self) -> None: path = QFileDialog.getExistingDirectory(self, 'Select the folder to add: ') self._add_path(path) def add_files(self) -> None: path_tuple = QFileDialog.getOpenFileNames(self, 'Select files to add: ') for path in path_tuple[0]: self._add_path(path) def add_item(self, item: str) -> None: self.list_widget.addItem(item) def remove_items(self) -> None: for SelectedItem in self.list_widget.selectedItems(): self.list_widget.takeItem(self.list_widget.row(SelectedItem)) self.smart_cleaner.path_data.del_path(SelectedItem.text()) self.text_browser.append( f'{SelectedItem.text()}\nThe path was successfully deleted!!!') def _add_path(self, path: str) -> None: if path: if self.smart_cleaner.path_data.add_path(path): self.add_item(path) self.text_browser.append( f'{path}\nThe path was added successfully!') else: self.text_browser.append( f'Error when adding or the path was added earlier!!!') def shred_start(self): self.start(method='shred') def zeroing_start(self): self.start(method='zero') def delete_start(self): self.start(method='del') def start(self, method='shred'): if not self.smart_cleaner.path_data.is_any_data: self.show_msg('Warning!', 'There is no data for mashing!!!') else: reply = QMessageBox.question( self, 'Warning!', 'The data will be destroyed, are you sure?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: if method == 'zero': self.text_browser.append('Files are reset to zero.') elif method == 'shred': self.text_browser.append('File mashing is started.') elif method == 'del': self.text_browser.append('File deletion started.') self.smart_cleaner.work_method = method self.smart_cleaner.shreds = self.spin_box.value() self.smart_cleaner.delete_a_folder = self.chb_del_dirs.isChecked( ) self.smart_cleaner.start() def update_information(self, s: str) -> None: self.text_browser.append(s) self.update_lcd() def update_lcd(self) -> None: self.lcd_dirs.display(str(self.smart_cleaner.cleaner.count_del_dirs)) self.lcd_files.display(str(self.smart_cleaner.cleaner.count_del_files)) self.lcd_errors.display(str(self.smart_cleaner.num_errors)) def at_start(self): self.from_disable(True) def at_finish(self) -> None: if self.smart_cleaner.work_method != 'zero': self.list_widget.clear() self.update_lcd() self.from_disable(False) self.finish_msg() def finish_msg(self) -> None: if self.smart_cleaner.work_method == 'zero': msg = ('Reset', 'Reset files: ') count = self.smart_cleaner.cleaner.count_zero_files elif self.smart_cleaner.work_method == 'shred': msg = ('Mashing', 'Passageways: ') count = self.smart_cleaner.cleaner.count_del_files else: msg = ('Delete', 'Deleted files: ') count = self.smart_cleaner.cleaner.count_del_files self.show_msg( 'Warning!', f'{msg[0]} completed successfully!!!\n' f' {msg[1]} {count}\n ' f'Deleted folders: {self.smart_cleaner.cleaner.count_del_dirs}\n ' f'Errors: {self.smart_cleaner.num_errors}') def from_disable(self, status: bool) -> None: self.btn_zero_files.setDisabled(status) self.btn_remove_item.setDisabled(status) self.btn_add_folder.setDisabled(status) self.btn_shred_files.setDisabled(status) self.btn_console_clear.setDisabled(status) self.btn_add_files.setDisabled(status) self.btn_del_files.setDisabled(status) self.chb_del_dirs.setDisabled(status) self.spin_box.setDisabled(status) self.list_widget.setDisabled(status) def show_msg(self, title: str = 'Warning!', msg: str = 'Message...') -> None: QMessageBox.about(self, title, msg) def closeEvent(self, event) -> None: reply = QMessageBox.question( self, 'Exit', 'Are you sure you want to terminate the program?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.hide() self.smart_cleaner.wait(3000) event.accept() else: event.ignore()
class OutputWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, None) self.layout = QGridLayout() self.label = QLabel("Files selected:") self.layout.addWidget(self.label, 0, 0, 1, 4) self.file_list = QListWidget() self.select_all = QListWidgetItem("(De)select all") self.select_all.setFlags(self.select_all.flags() | Qt.ItemIsUserCheckable) self.select_all.setCheckState(Qt.Unchecked) self.file_list.addItem(self.select_all) self.layout.addWidget(self.file_list, 1, 0, 1, 4) self.layout.addWidget(QLabel("First line:"), 2, 0) self.first_line = QLineEdit("", self) self.first_line.setValidator(QIntValidator(1, 100000)) self.layout.addWidget(self.first_line, 2, 1) self.layout.addWidget(QLabel("Last line:"), 2, 2) self.last_line = QLineEdit("", self) self.last_line.setValidator(QIntValidator(1, 100000)) self.layout.addWidget(self.last_line, 2, 3) self.convert_button = QPushButton("EXPORT") self.convert_button.clicked.connect(parent.on_convert) self.convert_button.setStyleSheet("background-color: green") self.layout.addWidget(self.convert_button, 3, 0, 1, 4) self.setLayout(self.layout) self.list_items = {} self.file_list.itemChanged.connect(self.on_item_changed) def add_to_list(self, file): if (self.list_items.get(file)): return False list_item = QListWidgetItem(file) list_item.setFlags(list_item.flags() | Qt.ItemIsUserCheckable) list_item.setCheckState(Qt.Checked) self.file_list.addItem(list_item) self.list_items[file] = list_item return True def remove_from_list(self, file): list_item = self.list_items.pop(file, None) if (not list_item): return False self.file_list.takeItem(self.file_list.row(list_item)) if (len(self.list_items) == 0): self.select_all.setCheckState(Qt.Unchecked) return True def output_info(self): res = { "files": self.files_selected(), "first_line": (0 if not self.last_line.text() else int(self.first_line.text())), "last_line": (0 if not self.last_line.text() else int(self.last_line.text())) } return res def on_item_changed(self, item): if (item is self.select_all): for list_item in self.list_items.values(): list_item.setCheckState(self.select_all.checkState()) def files_selected(self): res = [] for list_item in self.list_items.values(): if (list_item.checkState() == Qt.Checked): res.append(list_item.text()) return res
class CreateSequenceWindow(QDialog): """ Window for creating a new sequence """ def __init__(self, motors={}, listOfSequenceHandler=None, sequence=None, modifySequence=False): """ Initializtion of the window for creating a new sequence :param motors: The dictionary of all the motors :param listOfSequenceHandler: The handler of the list of sequence """ QDialog.__init__(self) # Set the window icon appIcon = QIcon(icon) self.setWindowIcon(appIcon) ## Flag if the sequence is a modified one or a new one self.__modifySequence = modifySequence ## The handler of the list of sequence self.__listOfSequenceHandler = listOfSequenceHandler ## The dictionary of all the motors self.__motors = motors ## The new sequence self.__sequence = sequence ## A dictionary of the positions of the new sequence self.__wantedPositions = {} ## The layout of the create sequence window self.__layout = QVBoxLayout(self) ## The widget for the name of the sequenc self.nameEntry = QLineEdit() self.nameEntry.setText(self.__sequence.getName()) ## The label for the widget in which the name of the sequence is written self.__nameLabel = QLabel("Sequence Name") ## The list of the different moves that forms the sequence self.__listOfMoveLabels = QListWidget() moveNumber = 1 for move in self.__sequence.getMoves(): # Set text for the move label labelText = "move " + str(moveNumber) + ": " moveNumber += 1 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " + \ str(move.getMotorPosition(self.__motors[motor].getName())) + ", " label = moveLabel(move, labelText, self.__motors) # insert label to the head of the list self.__listOfMoveLabels.insertItem(0, label) # Put the sliders of the create sequence window in a list ## List of sliders in the create sequence window self.listOfSliders = [] dictOfSlider = dict() for motor in self.__motors: dictOfSlider[motor] = QSlider(Qt.Horizontal) dictOfSlider[motor].setMaximum(4095) dictOfSlider[motor].setValue( self.__motors[motor].getCurrentPosition()) dictOfSlider[motor].sliderMoved.connect( self.__motors[motor].setGoalPosition) self.listOfSliders.append(dictOfSlider[motor]) ## Message to make the user put a name to the sequence self.__noNameMessage = QMessageBox() self.__noNameMessage.setIcon(QMessageBox.Warning) self.__noNameMessage.setWindowIcon(appIcon) self.__noNameMessage.setText( "Please name your sequence before saving it") self.__noNameMessage.setStandardButtons(QMessageBox.Ok) # Renable the create sequence window and closes the message self.__noNameMessage.accepted.connect(self.enableWindow) ## Warning message to make sure the user doen't want to save the sequence self.__warningMessage = QMessageBox() self.__warningMessage.setIcon(QMessageBox.Warning) self.__warningMessage.setWindowIcon(appIcon) self.__warningMessage.setText( "Are you sure you want to close this window? Your sequence will not be saved" ) self.__warningMessage.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) # Close the create sequence window and the message self.__warningMessage.accepted.connect(self.reject) # Renable the create sequence window and closes the message self.__warningMessage.rejected.connect(self.enableWindow) # Set the text for the labels ## Labels for the motors in the UI self.__motorLabels = [] for motorNumber in range(0, len(motors)): self.__motorLabels.append( QLabel("Motor " + str(motorNumber + 1) + " position")) ## Button to add a move to the sequence and procede to the next move self.nextMoveButton = QPushButton("Save Move") ## Buttons to accept or cancel the creation of a sequence self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # If ok pressed add the sequence to the list self.buttonBox.accepted.connect( lambda: self.addSequenceToList(self.__modifySequence)) # If cancel pressed close the create sequence window self.buttonBox.rejected.connect(self.__warningMessage.exec) # Renable the main window when the create sequence closes self.rejected.connect(self.__listOfSequenceHandler.enableUi) self.accepted.connect(self.__listOfSequenceHandler.enableUi) self.nextMoveButton.clicked.connect(self.addMovetoSequence) self.__listOfMoveLabels.itemDoubleClicked.connect( self.moveDoubleClicked) # Build the vertical layout with the different widgets self.__layout.addWidget(self.__nameLabel) self.__layout.addWidget(self.nameEntry) self.__layout.addWidget(self.__listOfMoveLabels) for motorNumber in range(len(self.__motors)): self.__layout.addWidget(self.__motorLabels[motorNumber]) self.__layout.addWidget(self.listOfSliders[motorNumber]) self.__layout.addWidget(self.nextMoveButton) self.__layout.addWidget(self.buttonBox) # Connect the qwidgetlist to the custom right click menu self.__listOfMoveLabels.setContextMenuPolicy(Qt.CustomContextMenu) self.__listOfMoveLabels.customContextMenuRequested.connect( self.rightClickMenu) def setName(self, name): """ Sets the name of the sequence with the user input :param name: The name of the sequence :return: No return """ self.__sequence.setName(name) def getSequence(self): """ Accessor of the sequence (for tests) :return: the sequence """ return self.__sequence def getListofMoveLabels(self): """ Accessor of the list of move labels (for tests) :return: the list of move labels """ return self.__listOfMoveLabels def addSequenceToList(self, modifySequence=False): """ Add the sequence to the list of sequence :param modifySequence: bool, if true there's a selected sequence that needs to be modified if false it's a new sequence :return: No return """ # TODO: look to move this method to the list of sequence handler # TODO: don't let the user enter a sequence that has the same name as an old one self.setName(self.nameEntry.text()) if self.__sequence.getName() != "": # Load previously saved sequences try: with open('SaveSequence.json') as save: savedListOfSequences = json.load(save) except FileNotFoundError: savedListOfSequences = [] if modifySequence: # Get the item that needs to be modified # selectedSequence = self.__listOfSequenceHandler.getSelectedItems() # Find the selected sequence in the list of saved ones for sequence in savedListOfSequences: if self.__sequence.getName() in sequence: indexOfTheSequence = savedListOfSequences.index( sequence) # remove the unmodified sequence to insert the modified sequence savedListOfSequences.remove(sequence) self.__listOfSequenceHandler.addItem(self.__sequence) # Make the sequence json seriable newSequence = dict() newSequence[self.__sequence.getName()] = [] for moveNumber in range(len( self.__sequence.getMoves())): newSequence[self.__sequence.getName()].append( self.__sequence.getMoves() [moveNumber].getMovePositions()) # Append new sequence to the old ones savedListOfSequences.insert(indexOfTheSequence, newSequence) # Write the sequences to the file with open('SaveSequence.json', 'w') as outfile: json.dump(savedListOfSequences, outfile) self.accept() else: self.__listOfSequenceHandler.addItem(self.__sequence) # Make the sequence json seriable newSequence = dict() newSequence[self.__sequence.getName()] = [] for moveNumber in range(len(self.__sequence.getMoves())): newSequence[self.__sequence.getName()].append( self.__sequence.getMoves() [moveNumber].getMovePositions()) # Append new sequence to the old ones savedListOfSequences.append(newSequence) # Write the sequences to the file with open('SaveSequence.json', 'w') as outfile: json.dump(savedListOfSequences, outfile) self.accept() else: self.setEnabled(False) self.__noNameMessage.exec_() def addMovetoSequence(self): """ Add the last move to the sequence :return: No return """ move = None labelToModify = None # Check if there's a move in modifying state for row in range(self.__listOfMoveLabels.count()): if not self.__listOfMoveLabels.item(row).getMove().isNew: move = self.__listOfMoveLabels.item(row).getMove() labelToModify = self.__listOfMoveLabels.item(row) break # verify if the move is a new one if move is None: # Create the new move and set his positions move = Move(self.__motors) i = 0 for motorName in self.__motors: move.setMotorPosition(motorName, self.listOfSliders[i].value()) i += 1 self.__sequence.addMove(move) # Set text for the move label labelText = "move " + str( self.__sequence.getNumberofMoves()) + ": " i = 0 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " +\ str(self.listOfSliders[i].value()) + ", " i += 1 label = moveLabel(move, labelText, self.__motors) # insert label to the head of the list self.__listOfMoveLabels.insertItem(0, label) else: # modify the move i = 0 for motorName in self.__motors: move.setMotorPosition(motorName, self.listOfSliders[i].value()) i += 1 # modify the label of the move textToEdit = labelToModify.text() listOfTextToEdit = textToEdit.split(' ') labelText = listOfTextToEdit[0] + " " + listOfTextToEdit[1] + " " i = 0 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " + \ str(self.listOfSliders[i].value()) + ", " i += 1 labelToModify.setText(labelText) labelToModify.setSelected(False) labelToModify.setBackground(Qt.white) # reset the state of the move move.isNew = True # Access the move positions when double clicked on def moveDoubleClicked(self, moveItem): """ Called when a move in the sequence is double clicked :param moveItem: the move that was double clicked :return: No return """ moveItem.goToMoveOfTheLabel() self.updateSlidersPositions() def updateSlidersPositions(self): counterMotors = 0 for motor in self.__motors: self.listOfSliders[counterMotors].setValue( self.__motors[motor].getGoalPosition()) counterMotors += 1 def enableWindow(self): """ Enable the create sequence window :return: """ self.setEnabled(True) def rightClickMenu(self, event): """ The right click menu of the move list :param event: The event (here right click) that makes the menu come up :return: No return """ menu = QMenu() # Add a button in the menu that when clicked, it puts a move in modifying state menu.addAction( "Modify Move", lambda: self.modifyMove(self.__listOfMoveLabels. selectedItems()[0])) # Add a button in the menu that when clicked, it deletes a move in the list menu.addAction( "Delete Move", lambda: self.deleteMove(self.__listOfMoveLabels. selectedItems()[0])) menu.exec_(self.__listOfMoveLabels.mapToGlobal(event)) def deleteMove(self, label): """ Delete a move and its label of the sequence :param label: label of the move :return: No return """ # remove the label from the list self.__listOfMoveLabels.takeItem(self.__listOfMoveLabels.row(label)) # remove the move from the sequence self.__sequence.deleteMove(label.getMove()) # rename the labels in the list of moves for index in range(self.__sequence.getNumberofMoves() - 1, -1, -1): labelToModify = self.__listOfMoveLabels.item(index) textToEdit = labelToModify.text() listOfTextToEdit = textToEdit.split(' ') listOfTextToEdit[1] = str(self.__sequence.getNumberofMoves() - index) + ':' textToEdit = ' '.join(listOfTextToEdit) self.__listOfMoveLabels.item(index).setText(textToEdit) def modifyMove(self, label): """ Put a move to a modified state :param label: label of the move :return: No return """ # Check if there's a move in modifying state for row in range(self.__listOfMoveLabels.count()): if not self.__listOfMoveLabels.item(row).getMove().isNew: self.__listOfMoveLabels.item(row).getMove().isNew = True self.__listOfMoveLabels.item(row).setBackground( QBrush(Qt.white)) moveToModify = label.getMove() moveToModify.isNew = False label.setBackground(QBrush(Qt.darkCyan)) label.goToMoveOfTheLabel() self.updateSlidersPositions()
class ExerciseWindow(QWidget): closed = Signal() def __init__(self, nursery, exercise): super().__init__() self.log = logging.getLogger("Test qt lean") self.server = ServerInterface(nursery) self.exercise = exercise self.statements = self.exercise.course.statements self._initUI() # Link signals self.server.proof_state_change.connect(self.proof_state_update) # Start waiter task self.server.nursery.start_soon(self.server_task) # Update initial proof state #self.proof_state_update(self.server.proof_state) async def server_task(self): await self.server.start() await self.server.exercise_set(self.exercise) async with qtrio.enter_emissions_channel( signals=[self.closed, self.send.clicked, self.undo.clicked ]) as emissions: async for emission in emissions.channel: if emission.is_from(self.closed): break elif emission.is_from(self.send.clicked): await self.go_send() elif emission.is_from(self.undo.clicked): await self.go_undo() self.server.stop() async def go_send(self): self.log.info("Send file to lean") self.freeze(True) txt = self.edit.toPlainText() try: await self.server.code_set("add", txt) except exceptions.FailedRequestError as ex: msg = QMessageBox(self) msg.setIcon(QMessageBox.Critical) msg.setWindowTitle("Failed lean request") msg.setText("I am broken :'(") detailed = "" for err in ex.errors: detailed += f"* at {err.pos_line} : {err.text}\n" msg.setDetailedText(detailed) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() self.freeze(False) async def go_undo(self): self.log.info("Undo") self.freeze(True) await self.server.history_undo() self.edit.setPlainText(self.server.lean_file.inner_contents) self.freeze(False) def closeEvent(self, ev): super().closeEvent(ev) self.closed.emit() def _initUI(self): # Create widgets self.objects = PropobjList() self.properties = PropobjList() self.goal = Goal("TODO") self.edit = QPlainTextEdit() self.send = QPushButton("Send to lean") self.undo = QPushButton("Undo") self.deflist = QListWidget() # --> Build deflist for st in self.statements: self.deflist.addItem(st.pretty_name) # --> Link signal self.deflist.itemClicked.connect(self.add_statement_name) # Create layouts goal_layout = QHBoxLayout() main_layout = QVBoxLayout() workspace_layout = QHBoxLayout() propobj_layout = QVBoxLayout() tools_layout = QVBoxLayout() btns_layout = QHBoxLayout() # Create QGroupBox to have titles propobj_gb = QGroupBox('Properties and objects') self.tools_gb = QGroupBox('Lean code') # Put widgets in layouts and group boxes goal_layout.addStretch() goal_layout.addWidget(self.goal) goal_layout.addStretch() # Add space below goal goal_layout.setContentsMargins(0, 10, 0, 30) #LTRB # Build propobj layout propobj_layout.addWidget(self.objects) propobj_layout.addWidget(self.properties) propobj_gb.setLayout(propobj_layout) # Build tools layout btns_layout.addWidget(self.send) btns_layout.addWidget(self.undo) tools_layout.addWidget(self.deflist) tools_layout.addWidget(self.edit) tools_layout.addLayout(btns_layout) self.tools_gb.setLayout(tools_layout) # Build workspace layout workspace_layout.addWidget(propobj_gb) workspace_layout.addWidget(self.tools_gb) # Don't forget me main_layout.addLayout(goal_layout) main_layout.addLayout(workspace_layout) self.setWindowTitle("d∃∀duction") self.setLayout(main_layout) self.show() def freeze(self, state: bool): self.tools_gb.setEnabled(not state) @Slot(QListWidgetItem) def add_statement_name(self, item): st = self.statements[self.deflist.row(item)] self.edit.insertPlainText(st.lean_name) @Slot(ProofState) def proof_state_update(self, po: ProofState): # Update goal # log.debug("Updating goal") goal = po.goals[0] target = goal.target.math_type.format_as_utf8() self.goal.setText(target) # Update properties and objects self.properties.clear() self.objects.clear() for type_, instances in goal.math_types: utf8 = type_.format_as_utf8(is_math_type=True) for obj in instances: txt = f"{obj.format_as_utf8()} : {utf8}" if obj.is_prop(): self.properties.addItem(txt) else: self.objects.addItem(txt)