263 lines
9.5 KiB
GDScript
263 lines
9.5 KiB
GDScript
class_name WordList
|
|
extends Control
|
|
|
|
@export var element_scene: PackedScene = preload("res://sources/language_tool/word_list_element.tscn")
|
|
|
|
var undo_redo: UndoRedo = UndoRedo.new()
|
|
var in_new_gp_mode: bool = false:
|
|
set = set_in_new_gp_mode
|
|
var _element: WordListElement
|
|
var sub_elements_list: Dictionary = {}
|
|
var new_gp_asked_element: WordListElement
|
|
var new_gp_asked_ind: int
|
|
|
|
@onready var elements_container: VBoxContainer = %ElementsContainer
|
|
@onready var new_gp_layer: CanvasLayer = $NewGPLayer
|
|
@onready var new_gp: Variant = %NewGP
|
|
@onready var title: ListTitle = %ListTitle
|
|
@onready var lesson_title: Label = %Lesson
|
|
@onready var word_title: Label = %Word
|
|
@onready var graphemes_title: Label = %Graphemes
|
|
@onready var error_label: Label = %ErrorLabel
|
|
|
|
|
|
func create_sub_elements_list() -> void:
|
|
sub_elements_list.clear()
|
|
Database.db.query("Select * FROM GPs ORDER BY GPs.Grapheme")
|
|
for element: Dictionary in Database.db.query_result:
|
|
sub_elements_list[element.ID] = {
|
|
grapheme = element.Grapheme,
|
|
phoneme = element.Phoneme,
|
|
}
|
|
|
|
|
|
func _ready() -> void:
|
|
create_sub_elements_list()
|
|
|
|
_element = element_scene.instantiate()
|
|
|
|
ensure_column_exists(_element.table, "Reading", "1")
|
|
ensure_column_exists(_element.table, "Writing", "0")
|
|
|
|
Database.db.query(_get_query())
|
|
|
|
var results: Array[Dictionary] = Database.db.query_result
|
|
for elem: Dictionary in results:
|
|
var element: WordListElement = element_scene.instantiate()
|
|
element.sub_elements_list = sub_elements_list
|
|
element.word = elem[_element.table_graph_column]
|
|
element.id = elem[_element.table_graph_column + "Id"]
|
|
element.exception = elem.Exception
|
|
element.reading = elem.Reading
|
|
element.writing = elem.Writing
|
|
element.set_gp_ids_from_string(elem[_element.sub_table_id + "s"] as String)
|
|
elements_container.add_child(element)
|
|
element.undo_redo = undo_redo
|
|
element.delete_pressed.connect(_on_element_delete_pressed.bind(element))
|
|
element.new_gp_asked.connect(_on_element_new_gp_asked.bind(element))
|
|
element.gps_updated.connect(_on_gps_updated)
|
|
element.update_lesson()
|
|
|
|
title.set_title(_element.table_graph_column + " List")
|
|
lesson_title.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
|
word_title.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
|
word_title.text = _element.table_graph_column
|
|
graphemes_title.text = _element.sub_table
|
|
_reorder_by("lesson")
|
|
|
|
|
|
func _get_query() -> String:
|
|
return "SELECT %s.ID as %sId, %s, group_concat(%s, ' ') as %ss, group_concat(%s, ' ') as %ss, group_concat(%s.ID, ' ') as %ss, %s.Exception, %s.Reading, %s.Writing
|
|
FROM %s
|
|
INNER JOIN ( SELECT * FROM %s ORDER BY %s.Position ) %s ON %s.ID = %s.%sID
|
|
INNER JOIN %s ON %s.ID = %s.%s
|
|
GROUP BY %s.ID" % [_element.table, _element.table_graph_column,
|
|
_element.table_graph_column, _element.sub_table_graph_column, _element.sub_table_graph_column,
|
|
_element.sub_table_phon_column, _element.sub_table_phon_column,
|
|
_element.sub_table, _element.sub_table_id, _element.table, _element.table, _element.table,
|
|
_element.table,
|
|
_element.relational_table, _element.relational_table, _element.relational_table, _element.table, _element.relational_table, _element.table_graph_column,
|
|
_element.sub_table, _element.sub_table, _element.relational_table, _element.sub_table_id,
|
|
_element.table]
|
|
|
|
|
|
func ensure_column_exists(table_name: String, column_name: String, default_value: String) -> void:
|
|
Database.db.query("PRAGMA table_info(%s);" % table_name)
|
|
var column_exists: bool = false
|
|
for row: Dictionary in Database.db.query_result:
|
|
if row.has("name") and row["name"] == column_name:
|
|
column_exists = true
|
|
break
|
|
|
|
if not column_exists:
|
|
var alter_sql: String = "ALTER TABLE %s ADD COLUMN %s INTEGER DEFAULT %s;" % [table_name, column_name, default_value]
|
|
var result: bool = Database.db.query(alter_sql)
|
|
if not result:
|
|
Logger.error("WordList: Failed to add column '%s' to table '%s'" % [column_name, table_name])
|
|
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event.is_action_pressed("ui_undo"):
|
|
undo_redo.undo()
|
|
elif event.is_action_pressed("ui_redo"):
|
|
undo_redo.redo()
|
|
|
|
|
|
func _on_element_delete_pressed(element: Control) -> void:
|
|
undo_redo.create_action("delete")
|
|
undo_redo.add_do_method(elements_container.remove_child.bind(element))
|
|
undo_redo.add_undo_method(elements_container.add_child.bind(element))
|
|
undo_redo.add_undo_method(elements_container.move_child.bind(element, element.get_index()))
|
|
undo_redo.commit_action()
|
|
|
|
|
|
func _on_plus_button_pressed() -> void:
|
|
undo_redo.create_action("add")
|
|
var element: WordListElement = element_scene.instantiate()
|
|
element.sub_elements_list = sub_elements_list
|
|
element.word = ""
|
|
element.undo_redo = undo_redo
|
|
element.delete_pressed.connect(_on_element_delete_pressed.bind(element))
|
|
element.new_gp_asked.connect(_on_element_new_gp_asked.bind(element))
|
|
element.gps_updated.connect(_on_gps_updated)
|
|
undo_redo.add_do_method(elements_container.add_child.bind(element))
|
|
undo_redo.add_do_method(elements_container.move_child.bind(element, 0))
|
|
undo_redo.add_undo_method(elements_container.remove_child.bind(element))
|
|
undo_redo.commit_action()
|
|
element.edit_mode()
|
|
|
|
|
|
func _on_element_new_gp_asked(ind: int, element: WordListElement) -> void:
|
|
in_new_gp_mode = true
|
|
new_gp_asked_element = element
|
|
new_gp_asked_ind = ind
|
|
if new_gp is WordListElement:
|
|
(new_gp as WordListElement).edit_mode()
|
|
elif new_gp is GPListElement:
|
|
(new_gp as GPListElement).edit_mode()
|
|
else:
|
|
Logger.error("WordList: Variable new_gp is of unknown type %s" % type_string(typeof(new_gp)))
|
|
|
|
|
|
func set_in_new_gp_mode(p_in_new_gp_mode: bool) -> void:
|
|
in_new_gp_mode = p_in_new_gp_mode
|
|
new_gp_layer.visible = in_new_gp_mode
|
|
|
|
|
|
func _on_gp_list_element_validated() -> void:
|
|
if new_gp is WordListElement:
|
|
(new_gp as WordListElement).insert_in_database()
|
|
elif new_gp is GPListElement:
|
|
(new_gp as GPListElement).insert_in_database()
|
|
else:
|
|
Logger.error("WordList: Variable new_gp is of unknown type %s" % type_string(typeof(new_gp)))
|
|
if new_gp is Object:
|
|
if (new_gp as Object).has_method("update_lesson"):
|
|
if new_gp is WordListElement:
|
|
(new_gp as WordListElement).update_lesson()
|
|
elif new_gp is SentenceListElement:
|
|
(new_gp as SentenceListElement).update_lesson()
|
|
else:
|
|
Logger.error("WordList: Variable new_gp is of unknown type %s" % type_string(typeof(new_gp)))
|
|
else:
|
|
Logger.error("WordList: Variable new_gp is of unknown type %s" % type_string(typeof(new_gp)))
|
|
in_new_gp_mode = false
|
|
create_sub_elements_list()
|
|
for element: WordListElement in elements_container.get_children():
|
|
element.sub_elements_list = sub_elements_list
|
|
new_gp_asked_element.new_gp_asked_added(new_gp_asked_ind, new_gp.id as int)
|
|
|
|
|
|
func _on_gps_updated() -> void:
|
|
create_sub_elements_list()
|
|
for element: WordListElement in elements_container.get_children():
|
|
element.sub_elements_list = sub_elements_list
|
|
|
|
|
|
func _on_save_button_pressed() -> void:
|
|
for element: WordListElement in elements_container.get_children():
|
|
element.insert_in_database()
|
|
Database.db.query(_get_query())
|
|
var result: Array[Dictionary] = Database.db.query_result
|
|
for elem: Dictionary in result:
|
|
var found: bool = false
|
|
for element: WordListElement in elements_container.get_children():
|
|
if " ".join(element.gp_ids) == elem[_element.sub_table_id + "s"] and element.word == elem[_element.table_graph_column]:
|
|
found = true
|
|
break
|
|
if not found:
|
|
Database.db.delete_rows(_element.table, "ID=%s" % elem[_element.table_graph_column + "Id"])
|
|
undo_redo.clear_history()
|
|
|
|
|
|
func _on_back_button_pressed() -> void:
|
|
get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn")
|
|
|
|
|
|
func _reorder_by(property_name: String) -> void:
|
|
Utils.reorder_children_by_property(elements_container, property_name)
|
|
|
|
|
|
func _on_list_title_add_pressed() -> void:
|
|
_on_plus_button_pressed()
|
|
|
|
|
|
func _on_list_title_back_pressed() -> void:
|
|
_on_back_button_pressed()
|
|
|
|
|
|
func _on_list_title_new_search(new_text: String) -> void:
|
|
for element: WordListElement in elements_container.get_children():
|
|
element.visible = element.word.begins_with(new_text)
|
|
|
|
|
|
func _on_list_title_save_pressed() -> void:
|
|
_on_save_button_pressed()
|
|
|
|
|
|
func _on_lesson_gui_input(event: InputEvent) -> void:
|
|
if event.is_action_pressed("left_click"):
|
|
_reorder_by("lesson")
|
|
|
|
|
|
func _on_word_gui_input(event: InputEvent) -> void:
|
|
if event.is_action_pressed("left_click"):
|
|
_reorder_by(_element.table_graph_column.to_lower())
|
|
|
|
|
|
func _on_list_title_import_path_selected(path: String, match_to_file: bool) -> void:
|
|
if not FileAccess.file_exists(path):
|
|
Logger.error("WordList: File not found %s" % path)
|
|
error_label.text = "File not found"
|
|
return
|
|
var file: FileAccess = FileAccess.open(path, FileAccess.READ)
|
|
var error: Error = FileAccess.get_open_error()
|
|
if error != OK:
|
|
Logger.error("WordList: Cannot open file %s. Error: %s" % [path, error_string(error)])
|
|
return
|
|
if file == null:
|
|
Logger.error("WordList: Cannot open file %s. File is null" % path)
|
|
return
|
|
var line: PackedStringArray = file.get_csv_line()
|
|
if line.size() < 2 or line[0] != "ORTHO" or line[1] != "GPMATCH":
|
|
error_label.text = "Column names should be ORTHO, GPMATCH"
|
|
return
|
|
var all_data: Dictionary = {}
|
|
while not file.eof_reached():
|
|
line = file.get_csv_line()
|
|
if line.size() < 2:
|
|
continue
|
|
_element._try_to_complete_from_word(line[0])
|
|
all_data[line[0]] = true
|
|
get_tree().reload_current_scene()
|
|
|
|
# delete elements that are not in file
|
|
if match_to_file:
|
|
var query: String = "Select * FROM Words"
|
|
Database.db.query(query)
|
|
var result: Array[Dictionary] = Database.db.query_result
|
|
for element: Dictionary in result:
|
|
if not element.Word in all_data:
|
|
Database.db.delete_rows("Words", "ID=%s" % element.ID)
|
|
|