# # Sam Hadow - Huffman-py # Copyright (C) 2023 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from PyQt5 import QtCore, QtGui, QtWidgets, QtSvg from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * import os, json, sys from huffman_py.gui.generate_graph import * from huffman_py.functions.decode import * from huffman_py.functions.encode import * from huffman_py.gui.InputDialog import * from huffman_py.functions.ifFileGetContent import * from huffman_py.gui.messageBox import * class Ui_MainWindow(QWidget): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") MainWindow.resize(800, 800) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName(u"gridLayout") # widget to attach graph/text self.widget = QWidget(self.centralwidget) self.widget.setObjectName(u"widget") self.widget.setMinimumSize(QSize(10, 10)) self.gridLayout.addWidget(self.widget, 1, 0, 1, 1) # widget_2 to attach buttons self.widget_2 = QWidget(self.centralwidget) self.widget_2.setObjectName(u"widget_2") self.widget_2.setMaximumSize(QSize(4000, 50)) self.gridLayout.addWidget(self.widget_2, 0, 0, 1, 1) ## MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) # text/svg widget grid self.gridLayout_main = QGridLayout(self.widget) self.gridLayout_main.setObjectName(u"gridLayout_main") # text/svg widgets ##### # svg (tree graph) self.viewer = QtSvg.QSvgWidget() self.gridLayout_main.addWidget(self.viewer,0, 0, 1, 1) ##### # text self.text = QTextEdit() self.text.setReadOnly(True) self.gridLayout_main.addWidget(self.text,1, 0, 1, 1) # hide widgets for now self.viewer.setVisible(False) self.text.setVisible(False) # grid2 # buttons ###################### self.gridLayout_2 = QGridLayout(self.widget_2) self.gridLayout_2.setObjectName(u"gridLayout_2") ##### # push button encoding self.pushButton_encode = QPushButton(self.widget_2) self.pushButton_encode.setObjectName(u"pushButton") self.gridLayout_2.addWidget(self.pushButton_encode, 1, 0, 1, 1) self.pushButton_encode.setText(QCoreApplication.translate("MainWindow", u"encode", None)) # button function self.pushButton_encode.clicked.connect(self.showDialogEncoder) ##### # push button decoding self.pushButton_decode = QPushButton(self.widget_2) self.pushButton_decode.setObjectName(u"pushButton_decode") self.gridLayout_2.addWidget(self.pushButton_decode, 1, 1, 1, 1) self.pushButton_decode.setText(QCoreApplication.translate("MainWindow", u"decode", None)) # button function self.pushButton_decode.clicked.connect(self.showDialogDecode) ##### # push button encode to file self.pushButton_encodeToFile = QPushButton(self.widget_2) self.pushButton_encodeToFile.setObjectName(u"pushButton_encodeToFile") self.gridLayout_2.addWidget(self.pushButton_encodeToFile, 1, 2, 1, 1) self.pushButton_encodeToFile.setText(QCoreApplication.translate("MainWindow", u"encode to file", None)) # button function self.pushButton_encodeToFile.clicked.connect(self.showDialogEncodeToFile) ##### #push button decode to file self.pushButton_decodeToFile = QPushButton(self.widget_2) self.pushButton_decodeToFile.setObjectName(u"pushButton_decodeToFile") self.gridLayout_2.addWidget(self.pushButton_decodeToFile, 1, 3, 1, 1) self.pushButton_decodeToFile.setText(QCoreApplication.translate("MainWindow", u"decode to file", None)) # button function self.pushButton_decodeToFile.clicked.connect(self.showDialogDecodeToFile) ##### end buttons # function on exit qApp.aboutToQuit.connect(self.closeEvent) ###### # button functions def showDialogEncoder(self): '''dialog to encode a text, path to file allowed, will show a tree''' text_input, ok = QInputDialog.getText(self, 'Input', 'Text to encode') text = ifFileGetContent(text_input) if ok and len(text) > 0: the_data = (str(text)) print(the_data) encoding, root, _ = huffman_encode(the_data) print("Encoded output", encoding) print("Decoded Output", huffman_decode(encoding, root)) # generate tree svg generate_graph(root) # refresh output self.viewer.load('tree.svg') self.viewer.update() # show tree (and encoded text in a small box) self.viewer.setVisible(True) self.text.setText(encoding) self.text.setMaximumSize(QSize(4000, 50)) self.text.setVisible(True) def showDialogDecode(self): '''dialog to decode a text with its dictionary, will show decoded text, path to files allowed''' dialog = InputDialog("binary","Dict {char:code} JSON-formatted") if dialog.exec(): data = dialog.getInputs() binary = ifFileGetContent(data[0]) if len(binary)>0 and len(data[1])>0: try: dict = json.loads(ifFileGetContent(data[1])) except ValueError: create_msg_box("Can't read dictionary, is it JSON-formatted?","Invalid dictionary") return 0 try: text = decode_from_dict(binary, dict) except ValueError: create_msg_box("Can't decode text, is it the right dictionary?","decoding error") return 0 except TypeError: create_msg_box("Can't use text in input, is it a binary?","Input error") return 0 # replace text widget content with decoded text self.text.setText(text) self.text.setMaximumSize(QSize(4000, 4000)) # show text widget (and hide tree) self.viewer.setVisible(False) self.text.setVisible(True) def showDialogEncodeToFile(self): '''Dialog to encode a text (path allowed), create a path.raw file with encoded text and a path.json file with corresponding dictionary''' dialog = InputDialog("text","path to file") if dialog.exec(): data = dialog.getInputs() text = ifFileGetContent(data[0]) if len(data[1])>0 and len(text)>0: try: with open(data[1]+'.raw','w') as fd_bin, open(data[1]+'.json','w') as fd_dic: encoding, _, dict = huffman_encode(text) json.dump(dict,fd_dic) fd_bin.write(encoding) except FileNotFoundError: create_msg_box("Invalid path, does this directory exist?","Input error") def showDialogDecodeToFile(self): '''Dialog to decode a binary (paths accepted for both dictionary and binary) and create a file with decoded text''' dialog = InputDialog("text","Dict {lettre:code} JSON-formatted", text3 = "path to file", thirdBox = True) if dialog.exec(): data = dialog.getInputs() binary = ifFileGetContent(data[0]) if len(binary)>0 and len(data[1])>0: try: dict = json.loads(ifFileGetContent(data[1])) except ValueError: create_msg_box("Can't read dictionary, is it JSON-formatted?","Invalid dictionary") return 0 try: text = decode_from_dict(binary, dict) except ValueError: create_msg_box("Can't decode text, is it the right dictionary?","decoding error") return 0 except TypeError: create_msg_box("Can't use text in input, is it a binary?","Input error") return 0 try: with open(data[2],'w') as fd: fd.write(text) except FileNotFoundError: create_msg_box("Invalid path, does this directory exist?","Input error") ##### end button functions def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QCoreApplication.translate("Huffman.py", u"Huffman.py", None)) def closeEvent(self): # delete graph files before exiting try: os.unlink('./tree.gv') os.unlink('./tree.svg') except: # if user didn't generate a tree pass print('exit') sys.exit(0)