rat-times/scripts/time_sheet.gd

171 lines
4.8 KiB
GDScript3
Raw Normal View History

2023-03-03 21:12:54 +00:00
class_name TimeSheet
var source_path := ""
2023-03-09 20:26:57 +00:00
var entries := []
2023-04-22 01:08:05 +00:00
# warning-ignore:integer_division
var _last_update := Time.get_ticks_msec() / 1000
2023-03-09 20:26:57 +00:00
2023-03-03 21:12:54 +00:00
## Loads the data file
func load_file() -> bool:
2023-03-09 20:26:57 +00:00
var file := File.new()
var success := file.open(source_path, File.READ)
if success != OK:
success = file.open(source_path, File.WRITE)
if success != OK:
2023-03-03 21:12:54 +00:00
printerr("Failed to open file %s"%[ProjectSettings.globalize_path(source_path)])
return false
return true
2023-03-09 23:25:50 +00:00
2023-03-03 21:12:54 +00:00
while not file.eof_reached():
var line := file.get_csv_line()
if line.size() == 0 or "".join(line).length() == 0:
continue
if not TimeEntry.is_csv_line_valid(line):
push_warning("CSV Line `%s` is not conform"%[",".join(line)])
continue
var entry := TimeEntry.new().from_csv_line(line)
entries.append(entry)
file.close()
2023-03-09 23:25:50 +00:00
2023-03-03 21:12:54 +00:00
return true
2023-04-22 01:08:05 +00:00
func get_active_entry_from_name(task_name: String) -> TimeEntry:
for _entry in entries:
var current_time_entry := _entry as TimeEntry
if current_time_entry.name == task_name and not current_time_entry.is_closed:
return current_time_entry
return null
2023-03-03 21:12:54 +00:00
## Adds a new time entry to the tree and to the data file
2023-04-22 01:08:05 +00:00
func add_entry(entry_name: String) -> TimeEntry:
2023-03-09 23:25:50 +00:00
var current_entry := TimeEntry.new().start_recording()
2023-03-03 21:12:54 +00:00
current_entry.name = entry_name
2023-04-22 01:08:05 +00:00
current_entry.is_closed = false
2023-03-09 20:26:57 +00:00
var file := File.new()
var success := file.open(source_path, File.READ_WRITE)
if success != OK:
2023-03-03 21:12:54 +00:00
printerr("Could not open file")
2023-04-22 01:08:05 +00:00
return null
file.seek_end()
2023-03-03 21:12:54 +00:00
entries.append(current_entry)
file.store_csv_line(current_entry.to_csv_line())
2023-04-22 01:08:05 +00:00
return current_entry
func stop_entry(entry_name: String, do_save := true) -> bool:
for _entry in entries:
var current_time_entry := _entry as TimeEntry
if current_time_entry.name == entry_name and not current_time_entry.is_closed:
current_time_entry.close()
if do_save:
save()
return true
return false
func toggle_entry(entry_name: String, do_save := true) -> void:
if stop_entry(entry_name, do_save):
return
else:
# warning-ignore:return_value_discarded
add_entry(entry_name)
2023-03-03 21:12:54 +00:00
func update() -> void:
2023-04-22 01:08:05 +00:00
# warning-ignore:integer_division
var current_time := Time.get_ticks_msec() / 1000
if current_time == _last_update:
return
_last_update = current_time
2023-03-09 23:25:50 +00:00
for entry in entries:
var time_entry := entry as TimeEntry
if time_entry.is_closed == false:
time_entry.update()
2023-03-03 21:12:54 +00:00
func save() -> void:
2023-03-09 20:26:57 +00:00
var file := File.new()
var success := file.open(source_path, File.WRITE)
if success != OK:
2023-03-03 21:12:54 +00:00
printerr("Could not open file")
return
2023-03-03 21:12:54 +00:00
for time_entry in entries:
file.store_csv_line(time_entry.to_csv_line())
2023-04-22 01:08:05 +00:00
func make_items_tree() -> TimeEntryTreeItem:
2023-04-30 16:47:36 +00:00
var sorted_entries := EntrySorter.new(entries).sort_by([["name"], ["start_date", true]]).entries
2023-04-22 01:08:05 +00:00
var tree := TimeEntryTreeItem.new()
2023-04-30 16:47:36 +00:00
for entry_index in sorted_entries.size():
var entry := sorted_entries[entry_index] as TimeEntry
2023-04-22 01:08:05 +00:00
var parts := entry.name.split("/")
var repo: TimeEntryTreeItem = tree.get_child(parts, true)
repo.append(entry)
return tree
2023-03-03 21:12:54 +00:00
static func restore(file_path: String) -> TimeSheet:
2023-03-09 20:26:57 +00:00
var timesheet = load("res://scripts/time_sheet.gd").new()
2023-03-03 21:12:54 +00:00
timesheet.source_path = file_path
2023-03-09 20:26:57 +00:00
var success: bool = timesheet.load_file()
2023-03-03 21:12:54 +00:00
if success:
return timesheet
return null
2023-04-30 16:47:36 +00:00
class EntrySorter:
var entries: Array
var _sorters := PoolStringArray()
func _init(initial_entries: Array) -> void:
entries = initial_entries.duplicate()
func by_name(reverse := false) -> EntrySorter:
return sort_by_one("name", reverse)
func by_date(reverse := false) -> EntrySorter:
return sort_by_one("date", reverse)
func sort_by_one(property: String, reverse := false) -> EntrySorter:
var method_name := "_by_%s"%[property]
assert(has_method(method_name), "%s is not a valid sorting property"%[property])
entries.sort_custom(self, method_name)
if reverse:
entries.invert()
return self
func sort_by(initial_sorters: Array) -> EntrySorter:
for item in initial_sorters:
var property = item[0]
var reversed = item[1] if item.size() > 1 else false
var method_name := "_by_%s"%[property]
assert(has_method(method_name), "%s is not a valid sorting property"%[property])
assert(reversed == null or reversed is bool, "The second item is not a boolean")
return self
_sorters = initial_sorters
entries.sort_custom(self, "__by_multiple")
_sorters = PoolStringArray()
return self
func __by_multiple(a: TimeEntry, b: TimeEntry) -> bool:
for item in _sorters:
var property = item[0]
var reversed = item[1]
var method_name := "_by_%s"%[property]
var result: bool = call(method_name, a, b)
if reversed:
result = not result
if result == false:
return false
return true
func _by_name(a: TimeEntry, b: TimeEntry) -> bool:
return a.name < b.name
func _by_date(a: TimeEntry, b: TimeEntry) -> bool:
return a.start_time < b.start_time