-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfileManagement.py
221 lines (169 loc) · 9.18 KB
/
fileManagement.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# ███████╗██╗██╗░░░░░███████╗ ███╗░░░███╗░█████╗░███╗░░██╗░█████╗░░██████╗░███████╗███╗░░░███╗███████╗███╗░░██╗████████╗
# ██╔════╝██║██║░░░░░██╔════╝ ████╗░████║██╔══██╗████╗░██║██╔══██╗██╔════╝░██╔════╝████╗░████║██╔════╝████╗░██║╚══██╔══╝
# █████╗░░██║██║░░░░░█████╗░░ ██╔████╔██║███████║██╔██╗██║███████║██║░░██╗░█████╗░░██╔████╔██║█████╗░░██╔██╗██║░░░██║░░░
# ██╔══╝░░██║██║░░░░░██╔══╝░░ ██║╚██╔╝██║██╔══██║██║╚████║██╔══██║██║░░╚██╗██╔══╝░░██║╚██╔╝██║██╔══╝░░██║╚████║░░░██║░░░
# ██║░░░░░██║███████╗███████╗ ██║░╚═╝░██║██║░░██║██║░╚███║██║░░██║╚██████╔╝███████╗██║░╚═╝░██║███████╗██║░╚███║░░░██║░░░
# ╚═╝░░░░░╚═╝╚══════╝╚══════╝ ╚═╝░░░░░╚═╝╚═╝░░╚═╝╚═╝░░╚══╝╚═╝░░╚═╝░╚═════╝░╚══════╝╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚══╝░░░╚═╝░░░
from __future__ import annotations # Type Hinting
from typehinting import startProgram, dataLayout # Type Hinting
import sqlite3
import os
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from miscFunctions import miscFunctions
# Fixing python to not be shit
true = True;
false = False;
class fileManager():
def __init__(this, self: startProgram) -> None:
this.self = self
this.functions = miscFunctions(self);
this._version = "1.1";
this._fileName = None;
this._database = None;
this.data: dataLayout;
this.data = {
"characters": [],
"world": []
};
def new(this) -> None:
# Gonna just wipe everything, close window and re-open?
# Also ask to confirm
pass
# End of function
def _saveAs(this) -> bool | str:
"""
Extra function to save a file with a specific filename
Returns:
bool | str: Returns false if there were no errors, otherwise returns the error code
"""
# Get the new save location
fileLocation = QFileDialog.getSaveFileUrl(this.self, "Save File", QtCore.QUrl(""), "Character Tracker (*.chtr)", "Character Tracker (*.chtr)");
if(fileLocation[0].toString() != ''): # If the user clicked cancel/ closed the dialog
fileLocation = fileLocation[0].toString();
else:
return 1;
fileLocation = fileLocation.replace("file:///", ""); # Remove the file related weirdness from QT
fileArray = fileLocation.split("/");
fileName = fileArray.pop(); # Get the filename from the last item in the array
pathToFile = "/".join(fileArray); # Rejoin the path to file
filePath = os.path.join(pathToFile, fileName); # Get the OS's version of the path to the file
errorCode = "SAV000"; # Error code for making directory
try:
if(not os.path.exists(pathToFile)): # If the path to the given directory doesn't exist
os.makedirs(pathToFile); # We make the path a thing
errorCode = "SAV001"; # Error code for creating/ opening/ saving file
file = open(filePath, "w"); # Create or open a file
file.write(""); # Overwrite everything in the file to be empty
file.close(); # And then save it
errorCode = "SQL000"; # Error code for connecting to the SQL
this._database = sqlite3.connect(filePath); # Now we turn it into a database
errorCode = "SQL001"; # Error code for creating the SQL Schema
this._createSchema(); # And create the SQL Schema
this._fileName = filePath; # Assuming nothing went wrong, we can now set our fileName variable
return false; # Return false, cause there were no errors
except:
return errorCode; # Something went wrong, so we return the code
# End of function
def save(this, saveAs: bool, data: dataLayout) -> None:
"""
Function to save a file
Args:
saveAs (bool): Whether or not to call _saveAs()
data (dataLayout): The data to save
"""
if(not this._fileName or saveAs): # If the fileName has not been set, or saveAs is true
errorCode = this._saveAs(); # We go through 'Save As'
if(errorCode): # If there was an error
if(errorCode == 1):
return;
else:
print(f"An error occured: {errorCode})");
return this._errorMessage(f"An error occured while saving the file (Error code: {errorCode})");
print("Saving Changes...");
errorCode = "SAV102"; # Error code for record deletion
this._deleteRecords(); # Delete everything from our database
errorCode = "SAV103"; # Error code for post deletion, pre character data - if you get this your data is fucked
try:
for person in data["characters"]:
sql = this._database.cursor();
sql.execute("INSERT INTO characters (id, name, title, age, gender, species, isdead, information, relationships) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", person);
this._database.commit();
errorCode = "SAV104"; # Error code for post character data, pre world data
for worldItem in data["world"]:
sql = this._database.cursor();
sql.execute("INSERT INTO worldBuilding (text, notUsed) VALUES (?, ?)", worldItem);
this._database.commit();
return print("Save Complete!"); # Console message for saving success
except:
print(f"An error occured: {errorCode})");
return this._errorMessage(f"An error occured while saving the file (Error code: {errorCode})");
# End of function
def _deleteRecords(this) -> None:
try:
sql = this._database.cursor();
sql.execute("DELETE FROM characters");
this._database.commit();
sql.execute("DELETE FROM worldBuilding");
this._database.commit();
except:
this._errorMessage("An error occured while saving the file (Error code: SAV000)"); # Error Code for during deleting data
# End of function
def open(this) -> None:
"""
Opens an sqlite database
Args:
file (str): The URL to the file
"""
self = this.self;
fileName = QFileDialog.getOpenFileName(self, "Choose File", "", "Character Tracker (*.chtr);;All Files (*)")[0];
if(not fileName): # If the user clicked cancel/ closed the dialog
return;
code = "OPN000"; # Not valid SQL
try:
this._database = sqlite3.connect(fileName);
sql = this._database.cursor();
code = "OPN001"; # No version table
sql.execute("SELECT * from version");
versionData = sql.fetchall();
if(versionData[0][0] < this._version):
this._updateSchema();
code = "OPN002"; # No characters table
sql.execute("SELECT * FROM characters");
this.data["characters"] = sql.fetchall();
this.functions.populateList(self.ui.characterList, "characters");
code = "OPN003"; # No worldbuilding table
sql.execute("SELECT * FROM worldBuilding");
this.data["world"] = sql.fetchall();
this.functions.populateList(self.ui.worldBuildingList, "world");
this._fileName = fileName;
except:
this._errorMessage(f"An error occured while opening the file (Error code: {code}");
self.data = this.data;
this.functions.populateList(self.ui.characterList, "characters");
this.functions.populateList(self.ui.worldBuildingList, "world");
# End of function
def _createSchema(this) -> None:
"""
Creates the tables required in the sql spreadsheet
"""
if(not this._database):
return;
# Data storage
sql = this._database.cursor();
sql.execute('CREATE TABLE "characters" ("id" INTEGER, "name" TEXT, "title" INTEGER, "age" INTEGER, "gender" INTEGER, "species" TEXT, "isdead" INTEGER, "information" TEXT, "relationships" TEXT)');
this._database.commit();
sql.execute('CREATE TABLE "worldBuilding" ("text" TEXT, "notUsed" INTEGER);');
this._database.commit();
# Versioning control system
sql.execute('CREATE TABLE "version" ("currentVersion" TEXT, "notUsed", INTEGER)');
this._database.commit();
sql.execute('INSERT INTO version (currentVersion, notUsed) VALUES (?, ?)', (this._version, 0));
this._database.commit();
# End of function
def _updateSchema(this) -> None:
pass;
# End of function
def _errorMessage(this, message: str) -> None:
QMessageBox.critical(this.self, "Error", message);
# End of function