grapher/database.py

224 lines
7.3 KiB
Python

# Custom
from model import *
from appstate import *
# External
from imgui_bundle import (
imgui,
imgui_ctx,
immapp,
imgui_md,
im_file_dialog,
hello_imgui
)
# Built In
from typing import List
import shelve
from pathlib import Path
from datetime import datetime
def file_info(path: Path) -> None:
stat = path.stat()
modified = datetime.fromtimestamp(stat.st_atime)
created = datetime.fromtimestamp(stat.st_ctime)
format = '%c'
data = {
"File": path.name,
"Size": f"{stat.st_size/100} KB",
"Modified": modified.strftime(format),
"Created": created.strftime(format)
}
if imgui.begin_table("File Info", 2):
imgui.table_setup_column(" ", 0)
imgui.table_setup_column(" ")
for k, v in data.items():
imgui.push_id(k)
imgui.table_next_row()
imgui.table_next_column()
imgui.text(k)
imgui.table_next_column()
imgui.text(v)
imgui.pop_id()
imgui.end_table()
@immapp.static(inited=False, res=False)
def select_file(app_state: AppState):
statics = select_file
if not statics.inited:
statics.res = None
statics.current = None
with shelve.open("state") as state:
statics.current = Path(state["DB"])
statics.inited = True
imgui_md.render("# Database Manager")
file_info(statics.current)
if imgui.button("Open File"):
im_file_dialog.FileDialog.instance().open("SelectDatabase", "Open Database", "Database File (*.json;*.db){.json,.db}")
if im_file_dialog.FileDialog.instance().is_done("SelectDatabase"):
if im_file_dialog.FileDialog.instance().has_result():
statics.res = im_file_dialog.FileDialog.instance().get_result()
LOG_INFO(f"Load File {statics.res}")
im_file_dialog.FileDialog.instance().close()
if statics.res:
filename = statics.res.filename()
info = Path(statics.res.path())
imgui.separator()
file_info(info)
file = None
if imgui.button("Load"):
if not db.is_closed():
db.close()
if statics.res.extension() == '.json':
file = filename.removesuffix('.json')
file = file + '.db'
db.init(file)
db.connect(reuse_if_open=True)
db.create_tables([Class, Student, Lecture, Submission])
load_from_json(str(info))
LOG_INFO(f"Successfully created {file}")
if statics.res.extension() == '.db':
file = str(statics.res.path())
db.init(file)
db.connect(reuse_if_open=True)
db.create_tables([Class, Student, Lecture, Submission])
LOG_INFO(f"Successfully loaded {filename}")
with shelve.open("state") as state:
state["DB"] = file
app_state.update()
statics.res = None
@immapp.static(inited=False)
def table(app_state: AppState) -> None:
statics = table
if not statics.inited:
statics.class_id = None
statics.lectures = None
statics.points = list()
statics.inited = True
if statics.class_id != app_state.current_class_id:
statics.class_id = app_state.current_class_id
statics.lectures = Lecture.select().where(Lecture.class_id == statics.class_id)
statics.data = dict()
for student in Student.select().where(Student.class_id == statics.class_id):
subs = Submission.select().where(Submission.student_id == student.id)
points = [sub.points for sub in subs]
statics.data[f"{student.prename} {student.surname}"] = points
if not statics.lectures:
imgui.text("No Lecture queried")
return
table_flags = (
imgui.TableFlags_.row_bg.value
| imgui.TableFlags_.borders.value
| imgui.TableFlags_.resizable.value
| imgui.TableFlags_.sizing_stretch_same.value
)
if imgui.begin_table("Overview", len(statics.lectures)+1, table_flags):
imgui.table_setup_column("Students")
for n, lecture in enumerate(statics.lectures, start=1):
imgui.table_setup_column(f"{n}. {lecture.title} ({lecture.points})")
imgui.table_setup_scroll_freeze(1, 1)
imgui.table_headers_row()
for k, v in statics.data.items():
imgui.push_id(k)
imgui.table_next_row()
imgui.table_next_column()
imgui.text(k)
for points in v:
imgui.table_next_column()
if points.is_integer():
points = int(points)
imgui.text(str(points))
imgui.pop_id()
imgui.end_table()
@immapp.static(inited=False)
def class_editor() -> None:
statics = class_editor
if not statics.inited:
statics.classes = None
statics.selected = 0
statics.inited = True
statics.classes = Class.select()
imgui_md.render("# Edit Classes")
_, statics.selected = imgui.combo("Classes", statics.selected, [c.name for c in statics.classes])
imgui.text(statics.classes[statics.selected].name)
def database_editor(app_state: AppState) -> None:
class_editor()
def database_docking_splits() -> List[hello_imgui.DockingSplit]:
split_main_command = hello_imgui.DockingSplit()
split_main_command.initial_dock = "MainDockSpace"
split_main_command.new_dock = "CommandSpace"
split_main_command.direction = imgui.Dir.down
split_main_command.ratio = 0.3
# Log Space
split_main_command2 = hello_imgui.DockingSplit()
split_main_command2.initial_dock = "CommandSpace"
split_main_command2.new_dock = "CommandSpace2"
split_main_command2.direction = imgui.Dir.right
split_main_command2.ratio = 0.3
split_main_misc = hello_imgui.DockingSplit()
split_main_misc.initial_dock = "MainDockSpace"
split_main_misc.new_dock = "MiscSpace"
split_main_misc.direction = imgui.Dir.left
split_main_misc.ratio = 0.2
splits = [split_main_misc, split_main_command, split_main_command2]
return splits
def set_database_editor_layout(app_state: AppState) -> List[hello_imgui.DockableWindow]:
file_dialog = hello_imgui.DockableWindow()
file_dialog.label = "Database"
file_dialog.dock_space_name = "MiscSpace"
file_dialog.gui_function = lambda: select_file(app_state)
log = hello_imgui.DockableWindow()
log.label = "Logs"
log.dock_space_name = "CommandSpace2"
log.gui_function = hello_imgui.log_gui
table_view = hello_imgui.DockableWindow()
table_view.label = "Table"
table_view.dock_space_name = "MainDockSpace"
table_view.gui_function = lambda: table(app_state)
editor = hello_imgui.DockableWindow()
editor.label = "Editor"
editor.dock_space_name = "CommandSpace"
editor.gui_function = lambda: database_editor(app_state)
return [
file_dialog, log, table_view, editor
]
def database_editor_layout(app_state: AppState) -> hello_imgui.DockingParams:
docking_params = hello_imgui.DockingParams()
docking_params.layout_name = "Database Editor"
docking_params.docking_splits = database_docking_splits()
docking_params.dockable_windows = set_database_editor_layout(app_state)
return docking_params