diff options
| author | dam <dam@gudinoff> | 2022-04-06 22:52:14 +0000 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2022-04-06 22:52:14 +0000 |
| commit | 1fe674aec4bd6ce3fc666c8545dadb4f0614067d (patch) | |
| tree | 949a5ff1380bf82edaf387a5b4e04d0a4bf9d46a /logic | |
| parent | 0f1adc3bb1f41b5dd3490f176a5eee2c17007923 (diff) | |
| download | surgery-log-1fe674aec4bd6ce3fc666c8545dadb4f0614067d.tar.zst surgery-log-1fe674aec4bd6ce3fc666c8545dadb4f0614067d.zip | |
Improved file operations for database and option sets.
Added confirmation dialogs when importing database and option sets files.
Standardized the error print calls.
Fixed capitalization on menu entries.
Diffstat (limited to 'logic')
| -rw-r--r-- | logic/database.gd | 145 | ||||
| -rw-r--r-- | logic/database_entry.gd | 6 | ||||
| -rw-r--r-- | logic/popup.gd | 12 | ||||
| -rw-r--r-- | logic/stage.gd | 85 |
4 files changed, 167 insertions, 81 deletions
diff --git a/logic/database.gd b/logic/database.gd index 262a18a..8acf1b6 100644 --- a/logic/database.gd +++ b/logic/database.gd @@ -8,7 +8,7 @@ var db: Array var selected_idx: int var staged_idx: int -onready var stage := get_node("/root/main/stage") as Stage +onready var stage := get_node("/root/main/stage") # as Stage @DAM Commented to avoid cyclic dependency. onready var delete_button := get_node("actions/delete") as Button onready var edit_button := get_node("actions/edit") as Button onready var add_button := get_node("actions/add") as Button @@ -18,7 +18,6 @@ onready var dialog := get_node("/root/main/dialog") as Dialog func _init(): selected_idx = -1 staged_idx = -1 - load_database() func _ready(): @@ -32,10 +31,7 @@ func _ready(): stage.connect("save", self, "save_stage") stage.connect("discard", self, "discard_stage") - for it in db: - self.add_item(get_entry_view(it)) - - clear_selection() + load_database() func get_entry_view(database_entry: Dictionary) -> String: @@ -62,7 +58,7 @@ func delete_action(): if selected_idx < 0: return - dialog.setup("The entry with process ID '%s' will be deleted from the database." % db[selected_idx].process_id, "Delete", "No") + dialog.setup("The entry #%d with process ID '%s' will be deleted from the database." % [selected_idx+1, db[selected_idx].process_id], "Delete", "No") dialog.connect("accepted", self, "delete_action_confirmed") popup.open_popup("Delete entry?", dialog) @@ -95,8 +91,8 @@ func add_action(): func save_stage(entry: Dictionary): if DatabaseEntry.is_valid_entry(entry) == false: - printerr("INVALID ENTRY RECEIVED") - return # @DAM Deal with this. + printerr("Invalid entry detected.") + return var next_selected_idx: int if staged_idx >= 0: @@ -125,7 +121,89 @@ func discard_stage(): grab_focus() +func save_database(file_path: String = DATABASE_FILE_PATH): + match file_path.get_extension(): + "json": + export_json(file_path, db) + + "csv": + export_csv(file_path, db) + + _: + printerr("Invalid database file extension: '%s'." % file_path.get_file()) + return + + +static func export_json(file_path: String, data: Array): + var database_file := { + "version": DATABASE_FILE_VERSION, + "database": data, + } + var indentation_char := "" if file_path == DATABASE_FILE_PATH else "\t" + var file_content := JSON.print(database_file, indentation_char) + + var file := File.new() + file.open(file_path, File.WRITE) + file.store_string(file_content) + file.close() + + +static func export_csv(file_path: String, data: Array): + var file := File.new() + file.open(file_path, File.WRITE) + var header := PoolStringArray(DatabaseEntry.ENTRY_PROTOTYPE.keys()) + file.store_csv_line(header) + for it in data: + file.store_csv_line(it.values()) + file.close() + + func load_database(file_path: String = DATABASE_FILE_PATH): + match file_path.get_extension(): + "json": + clear_database() + db = import_json(file_path) + if file_path != DATABASE_FILE_PATH: + sanitize_database(db) + + "csv": + clear_database() + db = import_csv(file_path) + + _: + printerr("Invalid database file extension: '%s'." % file_path.get_file()) + return + + for it in db: + # The JSON specification does not define integer or float types, but only a number type. + # Therefore, converting a Variant to JSON text will convert all numerical values to float types. + # Thus, we cast all integer values once we load them. + it["date_year"] = int(it["date_year"]) + it["date_month"] = int(it["date_month"]) + it["date_day"] = int(it["date_day"]) + + self.add_item(get_entry_view(it)) + + +static func sanitize_database(database: Array): + var blueprint := DatabaseEntry.ENTRY_PROTOTYPE + + for entry in database: + # Delete extra keys. + var keys_to_delete: Array + for key in entry: + if blueprint.has(key) == false: + keys_to_delete.append(key) + for key in keys_to_delete: + entry.erase(key) + + # Fix wrong value types. + for key in blueprint: + if entry.has(key) == false || typeof(entry[key]) != typeof(blueprint[key]): + entry[key] = blueprint[key] + + +static func import_json(file_path: String) -> Array: var file := File.new() file.open(file_path, File.READ_WRITE) var file_content = file.get_as_text() @@ -133,43 +211,21 @@ func load_database(file_path: String = DATABASE_FILE_PATH): var parse_result = JSON.parse(file_content) if parse_result.error != OK || typeof(parse_result.result) != TYPE_DICTIONARY: - push_error("Failed to parse database file: '%s'.") - return + printerr("Failed to parse database file: '%s'.") + return [] if parse_result.result["version"] != DATABASE_FILE_VERSION: - push_error("Invalid database file version '%s', expected '%s'." % DATABASE_FILE_VERSION) - return + printerr("Invalid database file version '%s', expected '%s'." % DATABASE_FILE_VERSION) + return [] if typeof(parse_result.result["database"]) != TYPE_ARRAY: - push_error("Failed to load database file contents.") - return - - db = parse_result.result["database"] - - # The JSON specification does not define integer or float types, but only a number type. - # Therefore, converting a Variant to JSON text will convert all numerical values to float types. - # Thus, we cast all integer values once we load them. - for it in db: - it.date_year = int(it.date_year) - it.date_month = int(it.date_month) - it.date_day = int(it.date_day) - - -func save_database(file_path: String = DATABASE_FILE_PATH): - var database_file := { - "version": DATABASE_FILE_VERSION, - "database": db, - } - var indentation_char := "" if file_path == DATABASE_FILE_PATH else "\t" - var file_content := JSON.print(database_file, indentation_char) + printerr("Failed to load database file contents.") + return [] - var file := File.new() - file.open(file_path, File.WRITE) - file.store_string(file_content) - file.close() + return parse_result.result["database"] -static func import_database(file_path: String) -> Array: +static func import_csv(file_path: String) -> Array: var result: Array var file := File.new() file.open(file_path, File.READ_WRITE) @@ -196,17 +252,6 @@ static func import_database(file_path: String) -> Array: return result -static func export_database(file_path: String, database: Array = db): - var file := File.new() - file.open(file_path, File.WRITE) - var header := PoolStringArray(DatabaseEntry.ENTRY_PROTOTYPE.keys()) - file.store_csv_line(header) - for it in database: - # @DAM This approach depends on the order the dictionary fields are created. - file.store_csv_line(it.values()) - file.close() - - func clear_database(): clear_selection() self.clear() diff --git a/logic/database_entry.gd b/logic/database_entry.gd index 496b752..8b0c51f 100644 --- a/logic/database_entry.gd +++ b/logic/database_entry.gd @@ -6,9 +6,9 @@ const DATE_FORMAT: String = "%04d-%02d-%02d" const ENTRY_PROTOTYPE: Dictionary = { "process_id": "", "surgery_id": "", - "date_year": 0, - "date_month": 0, - "date_day": 0, + "date_year": 1, + "date_month": 1, + "date_day": 1, "place": "", "anesthesia": "", "first_assistant": "", diff --git a/logic/popup.gd b/logic/popup.gd index d7c98f9..95fc2c3 100644 --- a/logic/popup.gd +++ b/logic/popup.gd @@ -5,12 +5,12 @@ signal dismissed # () export var clear_signals_on_hide := true -var control : Control -var control_parent : Node +var control : Control +var control_parent : Node -onready var title := get_node("title") as Label -onready var background := get_node("background") as Panel -onready var dismiss := get_node("dismiss") as Button +onready var title := get_node("title") as Label +onready var background := get_node("background") as Panel +onready var dismiss_button := get_node("dismiss") as Button func _init(): @@ -21,7 +21,7 @@ func _init(): func _ready(): - dismiss.connect("pressed", self, "dismiss") + dismiss_button.connect("pressed", self, "dismiss") func _clear_signals(): diff --git a/logic/stage.gd b/logic/stage.gd index e2248fa..764ee52 100644 --- a/logic/stage.gd +++ b/logic/stage.gd @@ -105,7 +105,7 @@ func show_options(field: String): func save_action(): self.visible = false var staged_entry := get_stage() - gather_option_sets(staged_entry) + gather_option_sets(staged_entry, option_sets) save_option_sets() emit_signal("save", staged_entry) @@ -164,7 +164,7 @@ func get_stage() -> Dictionary: return entry -func sanitize_option_sets(entry: Dictionary, blueprint: Dictionary = OPTION_SETS_TREE_STRUCTURE): +static func sanitize_option_sets(entry: Dictionary, blueprint: Dictionary = OPTION_SETS_TREE_STRUCTURE): # Delete extra keys. var keys_to_delete: Array for key in entry: @@ -185,7 +185,7 @@ func sanitize_option_sets(entry: Dictionary, blueprint: Dictionary = OPTION_SETS sanitize_option_sets(entry[key][sub_key], blueprint[key]) -func gather_option_sets(entry: Dictionary, target: Dictionary = option_sets, blueprint: Dictionary = OPTION_SETS_TREE_STRUCTURE): +static func gather_option_sets(entry: Dictionary, target: Dictionary, blueprint: Dictionary = OPTION_SETS_TREE_STRUCTURE): for key in blueprint: if target.get(key) == null: target[key] = {} @@ -201,7 +201,55 @@ func gather_option_sets(entry: Dictionary, target: Dictionary = option_sets, blu gather_option_sets(entry, target[key][value], blueprint[key]) +func save_option_sets(file_path: String = OPTION_SETS_FILE_PATH): + match file_path.get_extension(): + "json": + export_json(file_path, option_sets) + +# "csv": +# export_csv(file_path, option_sets) + + _: + printerr("Invalid option sets file extension: '%s'." % file_path.get_file()) + return + + +static func export_json(file_path: String, data: Dictionary): + var option_sets_file := { + "version": OPTION_SETS_FILE_VERSION, + "option_sets": data, + } + var indentation_char := "" if file_path == OPTION_SETS_FILE_PATH else "\t" + var file_content := JSON.print(option_sets_file, indentation_char) + + var file := File.new() + file.open(file_path, File.WRITE) + file.store_string(file_content) + file.close() + + +#static func export_csv(file_path: String, data: Dictionary): +# pass + + func load_option_sets(file_path: String = OPTION_SETS_FILE_PATH): + match file_path.get_extension(): + "json": + clear_option_sets() + option_sets = import_json(file_path) + if file_path != OPTION_SETS_FILE_PATH: + sanitize_option_sets(option_sets) + + "csv": + clear_option_sets() + option_sets = import_csv(file_path) + + _: + printerr("Invalid option sets file extension: '%s'." % file_path.get_file()) + return + + +static func import_json(file_path: String) -> Dictionary: var file := File.new() file.open(file_path, File.READ_WRITE) var file_content = file.get_as_text() @@ -209,32 +257,25 @@ func load_option_sets(file_path: String = OPTION_SETS_FILE_PATH): var parse_result = JSON.parse(file_content) if parse_result.error != OK || typeof(parse_result.result) != TYPE_DICTIONARY: - push_error("Failed to parse option sets file: '%s'.") - return + printerr("Failed to parse option sets file: '%s'.") + return {} if parse_result.result["version"] != OPTION_SETS_FILE_VERSION: - push_error("Invalid option sets file version '%s', expected '%s'." % OPTION_SETS_FILE_VERSION) - return + printerr("Invalid option sets file version '%s', expected '%s'." % OPTION_SETS_FILE_VERSION) + return {} if typeof(parse_result.result["option_sets"]) != TYPE_DICTIONARY: - push_error("Failed to load option sets file contents.") - return + printerr("Failed to load option sets file contents.") + return {} - option_sets = parse_result.result["option_sets"] + return parse_result.result["option_sets"] -func save_option_sets(file_path: String = OPTION_SETS_FILE_PATH): - var option_sets_file := { - "version": OPTION_SETS_FILE_VERSION, - "option_sets": option_sets, - } - var indentation_char := "" if file_path == OPTION_SETS_FILE_PATH else "\t" - var file_content := JSON.print(option_sets_file, indentation_char) - - var file := File.new() - file.open(file_path, File.WRITE) - file.store_string(file_content) - file.close() +static func import_csv(file_path: String) -> Dictionary: + var result := {} + for it in Database.import_csv(file_path): + gather_option_sets(it, result) + return result func clear_option_sets(): |
