From 1650a741b2a868f36f921ce3697a5cd967bbdc3f Mon Sep 17 00:00:00 2001 From: Eduard Dlabal Date: Sun, 18 May 2025 00:49:59 +0200 Subject: [PATCH] Enhance database management and TUI functionality: update person data in CSV, add edit and delete options in TUI, and improve mutex handling in user functions. --- TestList.csv | 14 +-- src/main.c | 2 + src/tui.c | 285 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/users.c | 16 +-- 4 files changed, 293 insertions(+), 24 deletions(-) diff --git a/TestList.csv b/TestList.csv index 7431a1d..f40b5cf 100644 --- a/TestList.csv +++ b/TestList.csv @@ -1,19 +1,17 @@ 1,Klara,Novotna,3010,1,0,0 2,Jan,Novak,3011,1,0,0 -3,Petr,Horak,3012,1,0,0 4,Lucie,Kralova,3013,1747515862,416,0 -5,Martin,Prochazka,3014,1,0,0 6,Anna,Urbanova,3015,1747515857,0,1 -7,David,Svoboda,3016,1,0,0 +7,David,Svoboda,3016,1747519032,0,1 8,Veronika,Kucerova,3017,1,0,0 -9,Tomas,Blaha,3018,1747515450,0,1 +9,Tomas,Blaha,3018,1747518718,3268,0 10,Barbora,Kratochvilova,3019,1,0,0 11,Jakub,Pospisil,3020,1747515462,0,1 -12,Eliska,Valkova,3021,1,0,0 +12,Eliska,Valkova,3021,1747518666,0,1 13,Ondrej,Stepanek,3022,1747515457,0,1 14,Simona,Holubova,3023,1747515453,0,1 15,Filip,Navratil,3024,1,0,0 -16,Adela,Slavikova,3025,1,0,0 +16,Adela,Slavikova,3025,1747518672,0,1 17,Radek,Polak,3026,1,0,0 18,Monika,Adamcova,3027,1,0,0 19,Jaroslav,Kolar,3028,1,0,0 @@ -30,3 +28,7 @@ 30,Marketa,Rezacova,3039,1,0,0 31,Libor,Hanak,3040,1,0,0 32,Libor,Hanak,3040,1,0,0 +17267,Kamil,Novacek,2502,0,0,0 +17747,Kamil,Franta,2502,0,0,0 +17767,Kamil,Filip,2502,0,0,0 +9158,Jindrich,Sidlo,2440,0,0,0 diff --git a/src/main.c b/src/main.c index 1dd3ade..932502b 100644 --- a/src/main.c +++ b/src/main.c @@ -55,6 +55,7 @@ int main(int argc, char const **argv) puts("Corrupted and/or empty list. Exiting...\n"); return EXIT_FAILURE; } + pthread_mutex_unlock(&person_list.lock); noecho(); noraw(); @@ -118,6 +119,7 @@ int main(int argc, char const **argv) pthread_join(uart_thread, NULL); free(args); + pthread_mutex_destroy(&person_list.lock); clear(); endwin(); diff --git a/src/tui.c b/src/tui.c index f3dfb7a..277e05f 100644 --- a/src/tui.c +++ b/src/tui.c @@ -216,6 +216,10 @@ void mainMenu(list_t *person_list, char *db_filename, int terminal_x, int termin case 1: personSearch(person_list, terminal_x, terminal_y); break; + + case 2: + editDatabaseMenu(person_list, terminal_x, terminal_y); + break; case 3: if (!saveListToCSV(db_filename, person_list)) dialogWindow(3, "Unknown error while saving.", terminal_x, terminal_y); @@ -249,7 +253,7 @@ void mainMenu(list_t *person_list, char *db_filename, int terminal_x, int termin void personListing(list_t *person_list, int terminal_x, int terminal_y) { - int win_height = 20; + int win_height = 22; int win_width = 76; int start_y = (terminal_y - win_height) / 2; int start_x = (terminal_x - win_width) / 2; @@ -279,10 +283,9 @@ void personListing(list_t *person_list, int terminal_x, int terminal_y) current = person_list->head; int idx = 0, row = 2; - while (current && row < win_height) + while (current && row < win_height -1) { - - if (idx >= offset && row < win_height - 1) + if (idx >= offset) { if (idx == highlight) wattron(personlisting, COLOR_PAIR(2)); @@ -298,6 +301,7 @@ void personListing(list_t *person_list, int terminal_x, int terminal_y) idx++; current = current->next; } + wrefresh(personlisting); @@ -489,10 +493,7 @@ void personInfo(list_t *_list, node_t *_person, int terminal_x, int terminal_y) WINDOW *personinfodialog = newwin(win_height, win_width, start_y, start_x); - int max_rows = win_height - 2; - int total_count = 0; - - char buttons[3][20] = {"", "", ""}; + char buttons[3][20] = {"", "", ""}; char prompts[6][32] = {"Name", "Surname", "Department", "Last time event", "Total time", "Available"}; char keyboard_input; @@ -500,8 +501,7 @@ void personInfo(list_t *_list, node_t *_person, int terminal_x, int terminal_y) int field_y = 2; int field_x = 4; - int button_y = field_y + 15; - int button_x = field_x; + while (1) { @@ -556,7 +556,10 @@ void personInfo(list_t *_list, node_t *_person, int terminal_x, int terminal_y) { if (highlight == 0) { - exportPersonInfo(_person); + if (exportPersonInfo(_person)) + dialogWindow(1, "Export succesfully created", terminal_x, terminal_y); + else + dialogWindow(3, "Unknown error", terminal_x, terminal_y); } else if (highlight == 1) { @@ -686,14 +689,274 @@ int exportDialog(list_t *_list, int terminal_x, int terminal_y) void editDatabaseMenu(list_t *_person_list, int terminal_x, int terminal_y) { + + int win_height = 10; + int win_width = 50; + int start_y = (terminal_y - win_height) / 2; + int start_x = (terminal_x - win_width) / 2; + + char choices[4][30] = {"Add person to database", "Remove person from database", "Log time event", "Back"}; + + char keyboard_input; + int highlight = 0; + + start_color(); + + WINDOW *mainmenu = newwin(win_height, win_width, start_y, start_x); + + while (1) + { + initWindow(mainmenu, win_width, terminal_x, terminal_y, STANDARD_WIN_COLOUR, "Database Editing"); + for (int i = 0; i < 6; i++) + { + if (i == highlight) + wattron(mainmenu, COLOR_PAIR(2)); + else + wattron(mainmenu, COLOR_PAIR(1)); + wattron(mainmenu, A_BOLD); + mvwprintw(mainmenu, 2 + i, (win_width - strlen(choices[i])) / 2, "%s", choices[i]); + wattroff(mainmenu, A_BOLD); + + if (i == highlight) + wattroff(mainmenu, COLOR_PAIR(2)); + else + wattroff(mainmenu, COLOR_PAIR(1)); + } + wrefresh(mainmenu); + flushinp(); + keyboard_input = wgetch(mainmenu); + + if (keyboard_input == '\t') + { + if (highlight < 3) + highlight++; + else + highlight = 0; + } + + else if (keyboard_input == '\n') + { + switch (highlight) + { + case 0: + addPersonDialog(_person_list, terminal_x, terminal_y); + break; + case 1: + deletePersonDialog(_person_list, terminal_x, terminal_y); + break; + case 2: + dialogWindow(2, "You can add time event for existing user from main menu", terminal_x, terminal_y); + break; + case 3: + if (keyboard_input == '\n') + { + wclear(mainmenu); + wrefresh(mainmenu); + touchwin(stdscr); + refresh(); + delwin(mainmenu); + refresh(); + return; + } + break; + } + } + } } void addPersonDialog(list_t *_person_list, int terminal_x, int terminal_y) { + int win_height = 14; + int win_width = 60; + int start_y = (terminal_y - win_height) / 2; + int start_x = (terminal_x - win_width) / 2; + WINDOW *addwin = newwin(win_height, win_width, start_y, start_x); + initWindow(addwin, win_width, terminal_x, terminal_y, STANDARD_WIN_COLOUR, "Add Person"); + + char name[32] = ""; + char surname[32] = ""; + char department[8] = ""; + int highlight = 0; + char *fields[3] = {name, surname, department}; + int field_lens[3] = {31, 31, 7}; + char *prompts[3] = {"Name", "Surname", "Department"}; + char *buttons[2] = {"", ""}; + + while (1) + { + werase(addwin); + initWindow(addwin, win_width, terminal_x, terminal_y, STANDARD_WIN_COLOUR, "Add Person"); + + for (int i = 0; i < 3; i++) + { + if (highlight == i) + wattron(addwin, COLOR_PAIR(2)); + else + wattron(addwin, COLOR_PAIR(1)); + mvwprintw(addwin, 2 + i * 2, 4, "%s: [%s]", prompts[i], fields[i][0] ? fields[i] : "______________________________"); + if (highlight == i) + wattroff(addwin, COLOR_PAIR(2)); + else + wattroff(addwin, COLOR_PAIR(1)); + } + + for (int i = 0; i < 2; i++) + { + if (highlight == 3 + i) + wattron(addwin, COLOR_PAIR(2) | A_BOLD); + else + wattron(addwin, COLOR_PAIR(1) | A_BOLD); + mvwprintw(addwin, 10, 4 + i * 16, "%s", buttons[i]); + if (highlight == 3 + i) + wattroff(addwin, COLOR_PAIR(2) | A_BOLD); + else + wattroff(addwin, COLOR_PAIR(1) | A_BOLD); + } + + wrefresh(addwin); + + int ch = wgetch(addwin); + if (ch == '\t') + { + highlight = (highlight + 1) % 5; + } + else if (ch == '\n') + { + if (highlight < 3) + { + echo(); + curs_set(1); + mvwprintw(addwin, 2 + highlight * 2, 7 + strlen(prompts[highlight]), "%-30s", ""); + wmove(addwin, 2 + highlight * 2, 7 + strlen(prompts[highlight])); + wgetnstr(addwin, fields[highlight], field_lens[highlight]); + curs_set(0); + noecho(); + } + else if (highlight == 3) + { + if (strlen(name) == 0 || strlen(surname) == 0 || strlen(department) == 0) + { + dialogWindow(3, "All fields must be filled.", terminal_x, terminal_y); + continue; + } + if (addPersonToList(_person_list, name, surname, atoi(department))) + { + dialogWindow(1, "Person added successfully.", terminal_x, terminal_y); + } + else + { + dialogWindow(3, "Failed to add person.", terminal_x, terminal_y); + } + delwin(addwin); + touchwin(stdscr); + refresh(); + return; + } + else if (highlight == 4) + { + delwin(addwin); + touchwin(stdscr); + refresh(); + return; + } + } + else if (ch == 27 || ch == 'q') + { + delwin(addwin); + touchwin(stdscr); + refresh(); + return; + } + } } void deletePersonDialog(list_t *_person_list, int terminal_x, int terminal_y) { + int win_height = 8; + int win_width = 50; + int start_y = (terminal_y - win_height) / 2; + int start_x = (terminal_x - win_width) / 2; + WINDOW *delwin_dialog = newwin(win_height, win_width, start_y, start_x); + initWindow(delwin_dialog, win_width, terminal_x, terminal_y, STANDARD_WIN_COLOUR, "Delete Person"); + + char prompt[] = "Enter UUID of person to delete:"; + char input[16] = ""; + int highlight = 0; + int button_x = (win_width - 7) / 2; + int text_x = (win_width - 18) / 2; + + while (1) + { + werase(delwin_dialog); + initWindow(delwin_dialog, win_width, terminal_x, terminal_y, STANDARD_WIN_COLOUR, "Delete Person"); + + mvwprintw(delwin_dialog, 2, (win_width - strlen(prompt)) / 2, "%s", prompt); + + if (highlight == 0) + wattron(delwin_dialog, COLOR_PAIR(2)); + else + wattron(delwin_dialog, COLOR_PAIR(1)); + mvwprintw(delwin_dialog, 4, text_x, "[%15s]", input); + if (highlight == 0) + wattroff(delwin_dialog, COLOR_PAIR(2)); + else + wattroff(delwin_dialog, COLOR_PAIR(1)); + + if (highlight == 1) + wattron(delwin_dialog, COLOR_PAIR(2) | A_BOLD); + else + wattron(delwin_dialog, COLOR_PAIR(1) | A_BOLD); + mvwprintw(delwin_dialog, 6, button_x, ""); + if (highlight == 1) + wattroff(delwin_dialog, COLOR_PAIR(2) | A_BOLD); + else + wattroff(delwin_dialog, COLOR_PAIR(1) | A_BOLD); + + wrefresh(delwin_dialog); + + int ch = wgetch(delwin_dialog); + if (ch == '\t') + { + highlight = !highlight; + } + else if (ch == '\n') + { + if (highlight == 0) + { + echo(); + curs_set(1); + mvwprintw(delwin_dialog, 4, text_x + 1, "%-15s", ""); + wmove(delwin_dialog, 4, text_x + 1); + wgetnstr(delwin_dialog, input, 15); + curs_set(0); + noecho(); + } + else if (highlight == 1) + { + uint16_t uuid = (uint16_t)atoi(input); + node_t *for_delete = searchPersonByUUID(_person_list, uuid); + if (removePersonFromList(_person_list, &for_delete)) + { + dialogWindow(1, "Person deleted successfully.", terminal_x, terminal_y); + } + else + { + dialogWindow(3, "Person not found.", terminal_x, terminal_y); + } + delwin(delwin_dialog); + touchwin(stdscr); + refresh(); + return; + } + } + else if (ch == 27 || ch == 'q') + { + delwin(delwin_dialog); + touchwin(stdscr); + refresh(); + return; + } + } } \ No newline at end of file diff --git a/src/users.c b/src/users.c index d374e3a..fa28571 100644 --- a/src/users.c +++ b/src/users.c @@ -15,12 +15,11 @@ uint16_t generateUUID( { uint16_t uuid; int found; + pthread_mutex_lock(&_list->lock); do { found = 0; uuid = (uint16_t)(rand() % (UINT16_MAX + 1)); - - pthread_mutex_lock(&_list->lock); node_t *current = _list->head; while (current != NULL) { @@ -60,7 +59,8 @@ uint16_t searchUUIDByName(list_t *_list, char *_name, char *_surname, uint16_t * { uint16_t sum = 0; uint16_t *uuids = malloc(sizeof(uint16_t)); - if (uuids == NULL) { + if (uuids == NULL) + { *_uuids_found = NULL; return 0; } @@ -127,7 +127,7 @@ int addPersonToList( strcpy(new_node->user.name, _name); strcpy(new_node->user.surname, _surname); new_node->user.department = _department; - new_node->user.last_time_event = -255; + new_node->user.last_time_event = 0; new_node->user.total = 0; new_node->user.available = FALSE; @@ -166,7 +166,8 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname, if (_list->head == NULL) { _list->head = (node_t *)malloc(sizeof(node_t)); - if (_list->head == NULL) { + if (_list->head == NULL) + { pthread_mutex_unlock(&_list->lock); return 0; } @@ -236,7 +237,6 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname, } current->next = new_node; pthread_mutex_unlock(&_list->lock); - return 1; } @@ -254,7 +254,8 @@ int addTimeEvent( pthread_mutex_lock(&_list->lock); if (_person->user.available) { - if (current_time > _person->user.last_time_event) { + if (current_time > _person->user.last_time_event) + { _person->user.total += (current_time - _person->user.last_time_event); } } @@ -291,6 +292,7 @@ int removePersonFromList(list_t *_list, node_t **_person) free(current->user.surname); free(current); *_person = NULL; + pthread_mutex_unlock(&_list->lock); return 1; } prev = current;