<filename>src/SecurePad.py
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QFont, QCloseEvent
from PyQt5.QtWidgets import *
from PyQt5 import uic
from sys import exit
import webbrowser
import json
import os
import random
import ctypes
import io


GUI_main = open("./configs/GUI/Main.ui", "r").read()

GUI_options = open("./configs/GUI/Options.ui", "r").read()


string = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890 !\"£$%&/=?^'@#.,:;_-|\*+<>()[]{}èéòç§ùà°"

def generate_encode_code():
    code = ""
    for i in range(len(string)):
        while True:
            x = random.choice(string)
            if not x in code:
                code += x
                break
    return code   

def load_key(string, code):
    i = 0
    my_encode = {"\n": "<-- br -->"}
    my_decode = {"<-- br -->": "\n"}
    for char in string:
        my_encode[char] = code[i]
        my_decode[code[i]] = char
        i += 1
    return my_encode, my_decode

def crypt(string, crypt_code):
    done = ""
    for char in string:
        try: done += crypt_code[char]
        except: done += char
    return done

def decrypt(string, decrypt_code):
    done = ""
    string = string.replace("<-- br -->", "\n")
    for char in string:
        if char != "\n":
            try: done += decrypt_code[char]
            except: done += char
        else: done += "\n"
    return done   

document = "Untitled.ct"
path = None
font = {"family": "Arial", "size": 12, "color": "white"}
cryptkey = "<KEY>"

APPDATA = os.getenv("appdata")

if not "SecurePad" in os.listdir(APPDATA):
    os.mkdir(f"{APPDATA}\\SecurePad")
    os.mkdir(f"{APPDATA}\\SecurePad\\Data")
    with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as cryptkey:
        cryptkey.write(f"#By changing the CryptKey all previously encrypted files may not work\n")
    with open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "w") as configs:
        configs.write(json.dumps(font))

try: open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "r")
except:
    with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as cryptkey:
        cryptkey.write(f"#By changing the CryptKey all previously encrypted files may not work\n")

try: open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "r")
except:
    with open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "w") as configs:
        configs.write(json.dumps(font))

try:
    cryptkey = open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "r").read().splitlines()[1]
except:
    cryptkey = generate_encode_code()
    with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as data:
        data.write(f"#By changing the CryptKey all previously encrypted files may not work\n{cryptkey}")

if len(cryptkey) != len(string):
    res = ctypes.windll.user32.MessageBoxW(0, u"Your key is invalid,\ndo you want to regenerate it?", u"Error", 3)
    if res == 2:
        exit()
    elif res == 6:
        cryptkey = generate_encode_code()
        with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as data:
            data.write(f"#By changing the CryptKey all previously encrypted files may not work\n{cryptkey}")
        encode = load_key(string, cryptkey)
        crypt_code = encode[0]
        decrypt_code = encode[1]  
    print(res)

try:
    encode = load_key(string, cryptkey)
    crypt_code = encode[0]
    decrypt_code = encode[1]  
except:
    res = ctypes.windll.user32.MessageBoxW(0, u"Your key is invalid,\ndo you want to regenerate it?", u"Error", 3)
    if res == 2:
        exit()
    elif res == 6:
        cryptkey = generate_encode_code()
        with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as data:
            data.write(f"#By changing the CryptKey all previously encrypted files may not work\n{cryptkey}")
        encode = load_key(string, cryptkey)
        crypt_code = encode[0]
        decrypt_code = encode[1]  
    print(res)

# 6 = si
# 7 = no
# 2 = annulla

font = json.loads(open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "r").read())



class Main(QMainWindow):
    def __init__(self):
        super(Main, self).__init__()
        f = io.StringIO(GUI_main)
        uic.loadUi(f, self)
        
        self.Text.setStyleSheet("background-color: #16213E; border: none; font-family: " + font["family"] + "; font-size: "+ str(font["size"]) + "pt; color: " + font["color"] + ";")

        global document

        #File
        self.actionOption.triggered.connect(self.toOption)
        self.actionNew.triggered.connect(self.NewFile)
        self.actionOpen.triggered.connect(self.openEvent)
        self.actionSave.triggered.connect(self.Save)
        self.actionSave_as.triggered.connect(self.SaveAs)
        self.actionClose.triggered.connect(self.closeEvent)

        self.Text.textChanged.connect(self.SaveTip)
                
        #Edit
        self.actionUndo.triggered.connect(self.Text.undo)
        self.actionRedo.triggered.connect(self.Text.redo)
        self.actionCopy.triggered.connect(self.Text.copy)
        self.actionPaste.triggered.connect(self.Text.paste)
        self.actionCut.triggered.connect(self.Text.cut)
        self.actionSelectAll.triggered.connect(self.Text.selectAll)
        self.actionClear.triggered.connect(self.Text.clear)

        #Zoom
        self.actionZoom_in.setShortcut("Ctrl++")
        self.actionZoom_out.setShortcut("Ctrl+-")

        self.actionZoom_in.triggered.connect(self.Text.zoomIn)
        self.actionZoom_out.triggered.connect(self.Text.zoomOut)


    def closeEvent(self):
	    reply = QMessageBox.question(self, 'Save', 'Unsaved work will be lost, continue?',
			QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
	    if reply == QMessageBox.Yes:
		    exit()
	    else:
		    pass
    
    def openEvent(self):
	    reply = QMessageBox.question(self, 'Save', 'Unsaved work will be lost, continue?',
			QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
	    if reply == QMessageBox.Yes:
		    self.OpenFile()
	    else:
		    pass





    #Option
    def toOption(self):
        widget.addWidget(Options())
        widget.setCurrentIndex(widget.currentIndex()+1)
    
    #File
    def SaveTip(self):
        global document
        widget.setWindowTitle(f"*{document} - SecurePad")

    def NewFile(self):
        global path
        path = None
        self.Text.clear()
    
    def OpenFile(self):
        global document, path, decrypt_code
        fileName, _ = QFileDialog.getOpenFileName(self,"OpenFile - SecurePad", "", "All Files (*);; Crypted Files (.ct);;")
        if fileName:
            path = fileName
            splittedFileName = fileName.split("/")
            document = splittedFileName[len(splittedFileName)-1]
            widget.setWindowTitle(f"{document} - SecurePad")
            with open(fileName, "r") as f:
                try: text = decrypt(f.read(), decrypt_code)
                except: text = f.read()
                self.Text.setPlainText(text)
                self.StatusBar.setText(f"Open {document}")

    def Save(self):
        global path, crypt_code
        if path:
            widget.setWindowTitle(f"{document} - SecurePad")
            with open(path, "w") as f:
                try: 
                    f.write(crypt(self.Text.toPlainText(), crypt_code))
                    self.StatusBar.setText(f"Saved")
                except Exception as e:
                    ctypes.windll.user32.MessageBoxW(0, str(e), u"Error", 0)
        else:
            self.SaveAs()

    def SaveAs(self):
        global document, path, crypt_code
        widget.setWindowTitle(f"{document} - SecurePad")
        fileName, _ = QFileDialog.getSaveFileName(self, "SaveFile - SecurePad", "Untitled.ct")
        if fileName:
            path = fileName
            splittedFileName = fileName.split("/")
            document = splittedFileName[len(splittedFileName)-1]
            with open(fileName, "w") as f:
                try:
                    f.write(crypt(self.Text.toPlainText(), crypt_code))
                    self.StatusBar.setText(f"Saved {document}")
                except Exception as e:
                    ctypes.windll.user32.MessageBoxW(0, str(e), u"Error", 0)




class Options(QMainWindow):
    def __init__(self):
        super(Options, self).__init__()
        f = io.StringIO(GUI_options)
        uic.loadUi(f, self)

        self.BackButton.clicked.connect(self.toHome)


        #Font
        self.fontComboBox.setCurrentText(font["family"])
        self.ColorFont.setCurrentText(font["color"])
        self.FontSize.setValue(font["size"])

        self.FontChange.clicked.connect(self.ChangeFont)

        #Cryptkey
        self.CryptKeyEdit.setText(cryptkey)

        self.CryptKeyChange.clicked.connect(self.UpdateCryptKey)
        self.RegenerateButton.clicked.connect(self.RegenerateKey)

        #Credits
        self.DarkGUI.clicked.connect(lambda: webbrowser.open("https://github.com/DarkGUI-project/"))
        self.Lorix.clicked.connect(lambda: webbrowser.open("https://github.com/Loricsi/"))
        self.JProgrammer.clicked.connect(lambda: webbrowser.open("https://github.com/jprogrammer-it/"))

    def RegenerateKey(self):
        new_key = generate_encode_code()
        self.CryptKeyEdit.setText(new_key)

    def toHome(self):
        widget.addWidget(Main())
        widget.setCurrentIndex(widget.currentIndex()+1)
    
    def ChangeFont(self):
        global font
        font["family"] = self.fontComboBox.currentFont().family()
        font["size"] = self.FontSize.value()
        font["color"] = self.ColorFont.currentText()

        open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "w").write(json.dumps(font))
    
    def UpdateCryptKey(self):
        crypt_code = self.CryptKeyEdit.text()
        open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w").write("#By changing the CryptKey all previously encrypted files may not work\n" + crypt_code)
        reply = QMessageBox.question(self, 'Alert', 'to apply the changes you have to restart the software, do you want to close it now?',
        	QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            exit()


#Main
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
app = QApplication([])
widget = QStackedWidget()
widget.addWidget(Main())
widget.setFixedSize(875, 450)
widget.setWindowTitle(f"{document} - SecurePad")
widget.show()

app.exec_()

<filename>src/SecurePad.py
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QFont, QCloseEvent
from PyQt5.QtWidgets import *
from PyQt5 import uic
from sys import exit
import webbrowser
import json
import os
import random
import ctypes
import io


GUI_main = open("./configs/GUI/Main.ui", "r").read()

GUI_options = open("./configs/GUI/Options.ui", "r").read()


string = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890 !\"£$%&/=?^'@#.,:;_-|\*+<>()[]{}èéòç§ùà°"

def generate_encode_code():
    code = ""
    for i in range(len(string)):
        while True:
            x = random.choice(string)
            if not x in code:
                code += x
                break
    return code   

def load_key(string, code):
    i = 0
    my_encode = {"\n": "<-- br -->"}
    my_decode = {"<-- br -->": "\n"}
    for char in string:
        my_encode[char] = code[i]
        my_decode[code[i]] = char
        i += 1
    return my_encode, my_decode

def crypt(string, crypt_code):
    done = ""
    for char in string:
        try: done += crypt_code[char]
        except: done += char
    return done

def decrypt(string, decrypt_code):
    done = ""
    string = string.replace("<-- br -->", "\n")
    for char in string:
        if char != "\n":
            try: done += decrypt_code[char]
            except: done += char
        else: done += "\n"
    return done   

document = "Untitled.ct"
path = None
font = {"family": "Arial", "size": 12, "color": "white"}
cryptkey = "<KEY>"

APPDATA = os.getenv("appdata")

if not "SecurePad" in os.listdir(APPDATA):
    os.mkdir(f"{APPDATA}\\SecurePad")
    os.mkdir(f"{APPDATA}\\SecurePad\\Data")
    with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as cryptkey:
        cryptkey.write(f"#By changing the CryptKey all previously encrypted files may not work\n")
    with open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "w") as configs:
        configs.write(json.dumps(font))

try: open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "r")
except:
    with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as cryptkey:
        cryptkey.write(f"#By changing the CryptKey all previously encrypted files may not work\n")

try: open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "r")
except:
    with open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "w") as configs:
        configs.write(json.dumps(font))

try:
    cryptkey = open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "r").read().splitlines()[1]
except:
    cryptkey = generate_encode_code()
    with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as data:
        data.write(f"#By changing the CryptKey all previously encrypted files may not work\n{cryptkey}")

if len(cryptkey) != len(string):
    res = ctypes.windll.user32.MessageBoxW(0, u"Your key is invalid,\ndo you want to regenerate it?", u"Error", 3)
    if res == 2:
        exit()
    elif res == 6:
        cryptkey = generate_encode_code()
        with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as data:
            data.write(f"#By changing the CryptKey all previously encrypted files may not work\n{cryptkey}")
        encode = load_key(string, cryptkey)
        crypt_code = encode[0]
        decrypt_code = encode[1]  
    print(res)

try:
    encode = load_key(string, cryptkey)
    crypt_code = encode[0]
    decrypt_code = encode[1]  
except:
    res = ctypes.windll.user32.MessageBoxW(0, u"Your key is invalid,\ndo you want to regenerate it?", u"Error", 3)
    if res == 2:
        exit()
    elif res == 6:
        cryptkey = generate_encode_code()
        with open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w") as data:
            data.write(f"#By changing the CryptKey all previously encrypted files may not work\n{cryptkey}")
        encode = load_key(string, cryptkey)
        crypt_code = encode[0]
        decrypt_code = encode[1]  
    print(res)

# 6 = si
# 7 = no
# 2 = annulla

font = json.loads(open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "r").read())



class Main(QMainWindow):
    def __init__(self):
        super(Main, self).__init__()
        f = io.StringIO(GUI_main)
        uic.loadUi(f, self)
        
        self.Text.setStyleSheet("background-color: #16213E; border: none; font-family: " + font["family"] + "; font-size: "+ str(font["size"]) + "pt; color: " + font["color"] + ";")

        global document

        #File
        self.actionOption.triggered.connect(self.toOption)
        self.actionNew.triggered.connect(self.NewFile)
        self.actionOpen.triggered.connect(self.openEvent)
        self.actionSave.triggered.connect(self.Save)
        self.actionSave_as.triggered.connect(self.SaveAs)
        self.actionClose.triggered.connect(self.closeEvent)

        self.Text.textChanged.connect(self.SaveTip)
                
        #Edit
        self.actionUndo.triggered.connect(self.Text.undo)
        self.actionRedo.triggered.connect(self.Text.redo)
        self.actionCopy.triggered.connect(self.Text.copy)
        self.actionPaste.triggered.connect(self.Text.paste)
        self.actionCut.triggered.connect(self.Text.cut)
        self.actionSelectAll.triggered.connect(self.Text.selectAll)
        self.actionClear.triggered.connect(self.Text.clear)

        #Zoom
        self.actionZoom_in.setShortcut("Ctrl++")
        self.actionZoom_out.setShortcut("Ctrl+-")

        self.actionZoom_in.triggered.connect(self.Text.zoomIn)
        self.actionZoom_out.triggered.connect(self.Text.zoomOut)


    def closeEvent(self):
	    reply = QMessageBox.question(self, 'Save', 'Unsaved work will be lost, continue?',
			QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
	    if reply == QMessageBox.Yes:
		    exit()
	    else:
		    pass
    
    def openEvent(self):
	    reply = QMessageBox.question(self, 'Save', 'Unsaved work will be lost, continue?',
			QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
	    if reply == QMessageBox.Yes:
		    self.OpenFile()
	    else:
		    pass





    #Option
    def toOption(self):
        widget.addWidget(Options())
        widget.setCurrentIndex(widget.currentIndex()+1)
    
    #File
    def SaveTip(self):
        global document
        widget.setWindowTitle(f"*{document} - SecurePad")

    def NewFile(self):
        global path
        path = None
        self.Text.clear()
    
    def OpenFile(self):
        global document, path, decrypt_code
        fileName, _ = QFileDialog.getOpenFileName(self,"OpenFile - SecurePad", "", "All Files (*);; Crypted Files (.ct);;")
        if fileName:
            path = fileName
            splittedFileName = fileName.split("/")
            document = splittedFileName[len(splittedFileName)-1]
            widget.setWindowTitle(f"{document} - SecurePad")
            with open(fileName, "r") as f:
                try: text = decrypt(f.read(), decrypt_code)
                except: text = f.read()
                self.Text.setPlainText(text)
                self.StatusBar.setText(f"Open {document}")

    def Save(self):
        global path, crypt_code
        if path:
            widget.setWindowTitle(f"{document} - SecurePad")
            with open(path, "w") as f:
                try: 
                    f.write(crypt(self.Text.toPlainText(), crypt_code))
                    self.StatusBar.setText(f"Saved")
                except Exception as e:
                    ctypes.windll.user32.MessageBoxW(0, str(e), u"Error", 0)
        else:
            self.SaveAs()

    def SaveAs(self):
        global document, path, crypt_code
        widget.setWindowTitle(f"{document} - SecurePad")
        fileName, _ = QFileDialog.getSaveFileName(self, "SaveFile - SecurePad", "Untitled.ct")
        if fileName:
            path = fileName
            splittedFileName = fileName.split("/")
            document = splittedFileName[len(splittedFileName)-1]
            with open(fileName, "w") as f:
                try:
                    f.write(crypt(self.Text.toPlainText(), crypt_code))
                    self.StatusBar.setText(f"Saved {document}")
                except Exception as e:
                    ctypes.windll.user32.MessageBoxW(0, str(e), u"Error", 0)




class Options(QMainWindow):
    def __init__(self):
        super(Options, self).__init__()
        f = io.StringIO(GUI_options)
        uic.loadUi(f, self)

        self.BackButton.clicked.connect(self.toHome)


        #Font
        self.fontComboBox.setCurrentText(font["family"])
        self.ColorFont.setCurrentText(font["color"])
        self.FontSize.setValue(font["size"])

        self.FontChange.clicked.connect(self.ChangeFont)

        #Cryptkey
        self.CryptKeyEdit.setText(cryptkey)

        self.CryptKeyChange.clicked.connect(self.UpdateCryptKey)
        self.RegenerateButton.clicked.connect(self.RegenerateKey)

        #Credits
        self.DarkGUI.clicked.connect(lambda: webbrowser.open("https://github.com/DarkGUI-project/"))
        self.Lorix.clicked.connect(lambda: webbrowser.open("https://github.com/Loricsi/"))
        self.JProgrammer.clicked.connect(lambda: webbrowser.open("https://github.com/jprogrammer-it/"))

    def RegenerateKey(self):
        new_key = generate_encode_code()
        self.CryptKeyEdit.setText(new_key)

    def toHome(self):
        widget.addWidget(Main())
        widget.setCurrentIndex(widget.currentIndex()+1)
    
    def ChangeFont(self):
        global font
        font["family"] = self.fontComboBox.currentFont().family()
        font["size"] = self.FontSize.value()
        font["color"] = self.ColorFont.currentText()

        open(f"{APPDATA}\\SecurePad\\Data\\FontOption.json", "w").write(json.dumps(font))
    
    def UpdateCryptKey(self):
        crypt_code = self.CryptKeyEdit.text()
        open(f"{APPDATA}\\SecurePad\\Data\\CryptKey.data", "w").write("#By changing the CryptKey all previously encrypted files may not work\n" + crypt_code)
        reply = QMessageBox.question(self, 'Alert', 'to apply the changes you have to restart the software, do you want to close it now?',
        	QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            exit()


#Main
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
app = QApplication([])
widget = QStackedWidget()
widget.addWidget(Main())
widget.setFixedSize(875, 450)
widget.setWindowTitle(f"{document} - SecurePad")
widget.show()

app.exec_()

#.,:;_-|\*+<>()[]{}èéòç§ùà°" # 6 = si # 7 = no # 2 = annulla #16213E; border: none; font-family: " + font["family"] + "; font-size: "+ str(font["size"]) + "pt; color: " + font["color"] + ";") #File #Edit #Zoom #Option #File #Font #Cryptkey #Credits #Main