|
- #define _DEFAULT_SOURCE
- #include <dirent.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <unistd.h>
-
- #include "btk/btk.h"
-
- /* for filesystem navigation */
- /* change depending on your system */
- #define NAME_SIZE 255
- #define PATH_SIZE 4096
-
- /* buffer increments */
- #define DIR_BUFFER_INC 100
- #define DATA_BUFFER_INC 2
-
- #define READ_SIZE 2048
- #define TEXT_SIZE 4096
- #define ITEM_SIZE 256
-
- #define TAG_COL 0
- #define UID_COL 1
- #define NAME_COL 2
- #define DATA_COLS_N 9 /* excludes id, filename and tag */
-
- enum tag_type {
- TAG_NONE = 0,
- TAG_STRAY = 1U << 0,
- TAG_NEW = 1U << 1,
- TAG_DEL = 1U << 2,
- TAG_EDITED = 1U << 3,
- TAG_VISIBILITY = 1U << 4
- };
-
- enum status {
- STATUS_NONE,
- STATUS_ERROR,
- STATUS_LATEST,
- STATUS_EDITED,
- STATUS_BUSY
- };
-
- enum dir_mode {
- DIR_FILES = 1U << 0,
- DIR_HIDDEN = 1U << 1
- };
-
- typedef struct {
- char uid[ITEM_SIZE];
- char filename[ITEM_SIZE];
- char misc[DATA_COLS_N][ITEM_SIZE];
- char notes[TEXT_SIZE];
- unsigned int notes_w;
- } data_entry_t;
-
- /* window creation functions */
- void build_entry_form ();
- void build_file_picker ();
- void build_main_window ();
- void build_settings ();
-
- /* functions */
- void clean_string_copy (char *, char *, unsigned int, int);
- int cmp_str_for_qsort (const void *, const void*);
- void entry_form_apply ();
- void entry_form_close ();
- void entry_form_open ();
- int file_exists ();
- void file_picker_close ();
- void file_picker_open (int);
- void file_picker_open_entry ();
- void file_picker_open_open ();
- void file_picker_open_new ();
- void file_picker_select ();
- int find_dir_spot (char *, char *);
- char* get_data_item (unsigned int, unsigned int);
- void hotpot_close ();
- void hotpot_load ();
- void hotpot_reload ();
- void hotpot_sync ();
- void hotpot_unload ();
- void move_dir (int);
- void open_ext_dir ();
- void open_ext_entry (int);
- void quit ();
- int parse_dir (char *, int);
- void push_entry (int, data_entry_t);
- void settings_close ();
- void settings_open ();
- void set_activity_status (int, int);
- void set_entry_tag_col (unsigned int, int);
- void set_main_win_states (int);
- void set_file_picker_states (int);
- void str_to_lower_case (char *);
- void toggle_del_tag ();
- void toggle_col (int, btk_arg_t);
- void toggle_hidden (int, btk_arg_t);
- void toggle_notes (int, btk_arg_t);
- void toggle_visibility_tag ();
- void update_select_data (int);
-
- /* btk windows */
- btk_session_t *session;
- btk_window_t *entry_form;
- btk_window_t *file_picker;
- btk_window_t *main_win;
- btk_window_t *settings;
- btk_window_t *windows[4];
-
- /* btk important cells */
- btk_cell_t *table_cell;
- btk_cell_t *dir_list_cell;
- btk_cell_t *notes_view_cell;
- btk_cell_t *file_select_cell;
- btk_cell_t *activity_cell;
- btk_cell_t *edited_note_cell;
- unsigned int table_cell_id;
- unsigned int dir_list_cell_id;
- unsigned int notes_view_cell_id;
- unsigned int file_select_cell_id;
- unsigned int activity_cell_id;
- unsigned int edited_note_cell_id;
-
- /* file navigation */
- char dir_current[PATH_SIZE];
- char *dir_list = NULL;
- int *dir_spot = NULL;
- unsigned int dir_list_n = 0;
- int nav_select = -1;
- int nav_mode;
-
- /* hotpot data */
- int file_picker_mode;
- char open_dir[PATH_SIZE] = "";
- int hotpot_open = 0;
- char *data = NULL;
- char *data_notes = NULL;
- int *data_tags = NULL;
- int *data_spot = NULL;
- char *data_rename = NULL;
- unsigned int data_n = 0;
- unsigned int data_buffer_n = 0;
- unsigned int last_uid = 0;
-
- /* selected data */
- int select_data = -1;
- char select_note[TEXT_SIZE];
-
- /* edited data */
- char edited_uid[ITEM_SIZE];
- char edited_filename[ITEM_SIZE];
- char edited_misc[DATA_COLS_N][ITEM_SIZE];
- char edited_note[TEXT_SIZE];
-
- /* misc gui stuff */
- char status_open_file[PATH_SIZE + NAME_SIZE];
- char status_files_n[15];
- char status_activity[9];
- char misc_titles[DATA_COLS_N][ITEM_SIZE];
- char misc_switches[DATA_COLS_N][ITEM_SIZE];
- unsigned int data_cols_cw[DATA_COLS_N + 3] = {1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2};
- int data_cols_ena[DATA_COLS_N + 3] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
- char data_header[DATA_COLS_N + 3][ITEM_SIZE] = {
- "TAGS",
- "UID",
- "FILENAME",
- "TOPICS",
- "AUTHORS",
- "INSTITUTIONS",
- "PUBLISHER",
- "YEAR",
- "VOL",
- "NO",
- "PAGES",
- "ACCESSED"
- };
-
- /* misc */
- btk_arg_t dummy_arg = {.i = 0, .f = 0.0f, .c = NULL, .p = NULL};
-
- /*******************************************************************/
-
- void
- build_entry_form()
- {
- entry_form = btk_window_create(session->x_con,
- session->x_scr,
- session->x_vis,
- 8, 6 + DATA_COLS_N,
- 4, 3 + DATA_COLS_N,
- 100, 0,
- 10 + 2 * DATA_COLS_N,
- entry_form_close);
- btk_window_set_name(entry_form, "hotpot - entry form");
-
- edited_note_cell_id = 0;
- edited_note_cell = &(entry_form->cells[edited_note_cell_id]);
- btk_cell_set_editor(edited_note_cell, 2, 2 + DATA_COLS_N, 6, 4, (char*)&edited_note, TEXT_SIZE);
-
- btk_cell_set_mark (&(entry_form->cells[1]), 0, 0, 2, BTK_JUSTIFY_RIGHT, "uid :");
- btk_cell_set_mark (&(entry_form->cells[2]), 0, 1, 2, BTK_JUSTIFY_RIGHT, "filename :");
- btk_cell_set_mark (&(entry_form->cells[3]), 2, 0, 6, BTK_JUSTIFY_LEFT, edited_uid);
- btk_cell_set_input (&(entry_form->cells[4]), 2, 1, 6, (char*)edited_filename, NAME_SIZE);
- btk_cell_set_mark (&(entry_form->cells[5]), 0, 2 + DATA_COLS_N, 2, BTK_JUSTIFY_RIGHT, "notes :");
- btk_cell_set_empty (&(entry_form->cells[6]), 0, 3 + DATA_COLS_N, 2, 1);
- btk_cell_set_button (&(entry_form->cells[7]), 0, 4 + DATA_COLS_N, 2, "apply", entry_form_apply);
- btk_cell_set_button (&(entry_form->cells[8]), 0, 5 + DATA_COLS_N, 2, "close", entry_form_close);
-
- /* generate input fields for misc data */
- for (int i = 0; i < DATA_COLS_N; i++) {
-
- strcpy(misc_titles[i], data_header[i + 3]);
- str_to_lower_case(misc_titles[i]);
- strcat(misc_titles[i], " :");
-
- btk_cell_set_mark (&(entry_form->cells[9 + i]), 0, 2 + i, 2, BTK_JUSTIFY_RIGHT, misc_titles[i]);
- btk_cell_set_input (&(entry_form->cells[10 + DATA_COLS_N + i]), 2, 2 + i, 6, (char*)edited_misc[i], NAME_SIZE);
- }
- }
-
- void
- build_file_picker()
- {
- file_picker = btk_window_create(session->x_con,
- session->x_scr,
- session->x_vis,
- 4, 9,
- 2, 2,
- 0, 300,
- 5,
- file_picker_close);
- btk_window_set_name(file_picker, "hotpot - file picker");
-
- dir_list_cell_id = 0;
- dir_list_cell = &(file_picker->cells[dir_list_cell_id]);
- btk_cell_set_list (dir_list_cell,
- 0, 1, 4, 5,
- &dir_list,
- &dir_list_n,
- NAME_SIZE,
- NULL, NULL,
- &dir_spot,
- move_dir,
- set_file_picker_states);
-
- file_select_cell_id = 1;
- file_select_cell = &(file_picker->cells[file_select_cell_id]);
- btk_cell_set_button (file_select_cell, 0, 7, 4, "select", file_picker_select);
-
- btk_cell_set_mark (&(file_picker->cells[2]), 0, 0, 4, BTK_JUSTIFY_RIGHT, (char*)&dir_current);
- btk_cell_set_switch (&(file_picker->cells[3]), 0, 6, 4, "show hidden", toggle_hidden, dummy_arg);
- btk_cell_set_button (&(file_picker->cells[4]), 0, 8, 4, "cancel", file_picker_close);
- }
-
- void
- build_main_window()
- {
- main_win = btk_window_create(session->x_con,
- session->x_scr,
- session->x_vis,
- 13, 16,
- 4, 7,
- 400, 0,
- 21,
- quit);
- btk_window_set_name(main_win, "hotpot");
-
- table_cell_id = 0;
- table_cell = &(main_win->cells[table_cell_id]);
- btk_cell_set_table(table_cell,
- 3, 0, 10, 15,
- (char*)data_header,
- &data,
- ITEM_SIZE,
- DATA_COLS_N + 3,
- &data_n,
- (int*)data_cols_ena,
- data_cols_cw,
- 2,
- NULL, NULL,
- &data_spot,
- open_ext_entry,
- update_select_data);
-
- strcpy(select_note, "");
- notes_view_cell_id = 1;
- notes_view_cell = &(main_win->cells[notes_view_cell_id]);
- btk_cell_set_editor(notes_view_cell,
- 3, 9, 10, 6,
- select_note,
- TEXT_SIZE);
- main_win->cells[notes_view_cell_id].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[notes_view_cell_id].state |= BTK_CELL_STATE_HIDDEN;
-
- activity_cell_id = 18;
- activity_cell = &(main_win->cells[activity_cell_id]);
- btk_cell_set_mark (activity_cell,
- 11, 15, 2,
- BTK_JUSTIFY_RIGHT,
- (char*)&status_activity);
-
- btk_cell_set_button (&(main_win->cells[2]), 0, 0, 3, "open", file_picker_open_open);
- btk_cell_set_button (&(main_win->cells[3]), 0, 1, 3, "new", file_picker_open_new);
- btk_cell_set_button (&(main_win->cells[4]), 0, 2, 3, "sync", hotpot_sync);
- btk_cell_set_button (&(main_win->cells[5]), 0, 3, 3, "view directory", open_ext_dir);
- btk_cell_set_button (&(main_win->cells[6]), 0, 4, 3, "reload", hotpot_reload);
- btk_cell_set_button (&(main_win->cells[7]), 0, 5, 3, "close", hotpot_close);
- btk_cell_set_button (&(main_win->cells[8]), 0, 6, 3, "quit", quit);
- btk_cell_set_empty (&(main_win->cells[9]), 0, 7, 3, 1);
- btk_cell_set_button (&(main_win->cells[10]), 0, 8, 3, "add file", file_picker_open_entry);
- btk_cell_set_button (&(main_win->cells[11]), 0, 9, 3, "edit entry", entry_form_open);
- btk_cell_set_button (&(main_win->cells[12]), 0, 10, 3, "tag for deletion", toggle_del_tag);
- btk_cell_set_button (&(main_win->cells[19]), 0, 11, 3, "tag for visibility", toggle_visibility_tag);
- btk_cell_set_button (&(main_win->cells[20]), 0, 12, 3, "export citation", NULL);
- btk_cell_set_empty (&(main_win->cells[13]), 0, 13, 3, 1);
- btk_cell_set_switch (&(main_win->cells[14]), 0, 14, 3, "show notes", toggle_notes, dummy_arg);
- btk_cell_set_button (&(main_win->cells[15]), 0, 15, 3, "settings", settings_open);
- btk_cell_set_mark (&(main_win->cells[16]), 3, 15, 6, BTK_JUSTIFY_RIGHT, (char*)&status_open_file);
- btk_cell_set_mark (&(main_win->cells[17]), 9, 15, 2, BTK_JUSTIFY_RIGHT, (char*)&status_files_n);
-
- main_win->cells[15].state |= BTK_CELL_STATE_ON;
- main_win->cells[20].state |= BTK_CELL_STATE_DISABLED;
- set_main_win_states(0);
- }
-
- void
- build_settings()
- {
- settings = btk_window_create(session->x_con,
- session->x_scr,
- session->x_vis,
- 3, 3 + DATA_COLS_N,
- -1, -1,
- 0, 0,
- 3 + DATA_COLS_N,
- settings_close);
- btk_window_set_name(settings, "hotpot - settings");
-
- btk_arg_t col_arg= {.i = TAG_COL};
-
- btk_cell_set_switch (&(settings->cells[0]), 0, 0, 3, "show tags", toggle_col, col_arg);
- btk_cell_set_empty (&(settings->cells[1 + DATA_COLS_N]), 0, 1 + DATA_COLS_N, 3, 1);
- btk_cell_set_button (&(settings->cells[2 + DATA_COLS_N]), 0, 2 + DATA_COLS_N, 3, "close", settings_close);
-
- settings->cells[0].state |= BTK_CELL_STATE_ON;
-
- /* generate col toggles for misc data */
- for (int i = 0; i < DATA_COLS_N; i++) {
-
- sprintf(misc_switches[i], "show %s", data_header[i + 3]);
- str_to_lower_case(misc_switches[i]);
-
- btk_arg_t col_arg = {.i = i + 3};
- btk_cell_set_switch (&(settings->cells[1 + i]), 0, 1 + i, 3, misc_switches[i], toggle_col, col_arg);
- settings->cells[1 + i].state |= BTK_CELL_STATE_ON;
- }
- }
-
- /****************************************************************************************/
-
- int
- main()
- {
- getcwd(dir_current, PATH_SIZE);
- strcat(dir_current, "/");
-
- /* btk init */
- session = btk_open();
- build_entry_form();
- build_file_picker();
- build_main_window();
- build_settings();
- windows[0] = main_win;
- windows[1] = file_picker;
- windows[2] = entry_form;
- windows[3] = settings;
-
- btk_map(session, main_win);
- btk_loop(session, windows, 4);
-
- btk_close(session);
-
- quit();
- return 0;
- }
-
- /****************************************************************************************/
-
- void
- clean_string_copy(char* dest, char* src, unsigned int max_size, int del_newline)
- {
- if (!max_size)
- return;
-
- char mid[max_size];
-
- strncpy(mid, src, max_size);
- if (del_newline)
- *strchr(mid, '\n') = '\0';
- mid[max_size - 1] = '\0';
- strcpy(dest, mid);
- }
-
- int
- cmp_str_for_qsort(const void *a, const void *b)
- {
- return strcmp((char*)a, (char*)b);
- }
-
- /* check if any data changed, copy it and update status if so */
- void
- entry_form_apply()
- {
- int changed = 0;
-
- if (strcmp(edited_filename, get_data_item(NAME_COL, select_data))) {
- strcpy(data_rename + select_data * ITEM_SIZE, get_data_item(NAME_COL, select_data));
- strcpy(get_data_item(NAME_COL, select_data), edited_filename);
- changed = 1;
- }
-
- for (int i = 0; i < DATA_COLS_N; i++) {
- if (strcmp(edited_misc[i], get_data_item(i + 3, select_data))) {
- strcpy(get_data_item(i + 3, select_data), edited_misc[i]);
- changed = 1;
- }
- }
- if (strcmp(edited_note, select_note)) {
- strcpy(data_notes + select_data * TEXT_SIZE, edited_note);
- strcpy(select_note, edited_note);
- btk_cell_editor_update_text(notes_view_cell);
- changed = 1;
- }
-
- if (changed) {
- data_tags[select_data] |= TAG_EDITED;
- set_entry_tag_col(select_data, data_tags[select_data]);
- set_activity_status(STATUS_EDITED, 1);
- btk_window_redraw(main_win);
- }
- }
-
- void
- entry_form_open()
- {
- if (select_data < 0 || select_data >= data_n)
- return;
-
- strcpy(edited_note, select_note);
- btk_cell_editor_reset_caret(edited_note_cell);
-
- strcpy(edited_uid, get_data_item(1, select_data));
- strcpy(edited_filename, get_data_item(2, select_data));
- btk_cell_input_reset_caret(&(entry_form->cells[4]));
-
- for (int i = 0; i < DATA_COLS_N; i++) {
- strcpy(edited_misc[i], get_data_item(i + 3, select_data));
- btk_cell_input_reset_caret(&(entry_form->cells[10 + DATA_COLS_N + i]));
- }
-
- btk_cell_editor_update_text(edited_note_cell);
- btk_window_disable(main_win);
- btk_map(session, entry_form);
- }
-
- void
- entry_form_close()
- {
- btk_window_enable(main_win);
- btk_unmap(session, entry_form);
- }
-
- /* checks if currently selected file in the file picker
- * exists in the open hotpot directory */
- int
- file_exists()
- {
- DIR *d;
- struct dirent *dir;
-
- d = opendir(open_dir);
- if (!d) {
- printf("ERROR - couldn't read directory");
- return 0;
- }
-
- while ((dir = readdir(d))) {
- if (!strcmp(dir->d_name, dir_list + nav_select * NAME_SIZE))
- return 1;
- }
-
- return 0;
- }
-
- void
- file_picker_close()
- {
- btk_window_enable(main_win);
- btk_unmap(session, file_picker);
- }
-
- void
- file_picker_open(int mode)
- {
- btk_cell_list_deselect(dir_list_cell);
- set_file_picker_states(-1);
-
- file_picker_mode = mode;
- if (!file_picker_mode) {
- nav_mode |= DIR_FILES;
- } else {
- nav_mode &= ~DIR_FILES;
- }
-
- btk_window_disable(main_win);
- btk_map(session, file_picker);
- parse_dir(dir_current, nav_mode);
- }
-
- void file_picker_open_entry() { file_picker_open(0); }
- void file_picker_open_open() { file_picker_open(1); }
- void file_picker_open_new() { file_picker_open(2); }
-
- void
- file_picker_select()
- {
- if (nav_select < 0 || nav_select >= dir_list_n) {
- printf("ERROR -> tried to open out of bound selection\n");
- return;
- }
-
- switch(file_picker_mode) {
-
- /* copy selected file into open hotpot directory, then add it to data */
- case 0:;
- /* compose command */
- char cmd[12 + 2 * PATH_SIZE + NAME_SIZE];
- sprintf(cmd,
- "cp -n \'%s%s\' \'%s\'",
- dir_current,
- dir_list + nav_select * NAME_SIZE,
- open_dir);
- system(cmd);
- /* create new entry */
- data_entry_t new_entry;
- new_entry.notes_w = 0;
- new_entry.notes[0] = '\0';
- new_entry.uid[0] = '\0';
- for (int i = 0; i < DATA_COLS_N; i++)
- new_entry.misc[i][0] = '\0';
- strcpy(new_entry.filename, dir_list + nav_select * NAME_SIZE);
- push_entry(TAG_NEW, new_entry);
- /* update window */
- set_activity_status(STATUS_EDITED, 0);
- set_entry_tag_col(data_n - 1, data_tags[data_n - 1]);
- set_main_win_states(1);
- break;
-
- /* open hotpot */
- case 1:
- strcpy(open_dir, dir_current);
- strcat(open_dir, dir_list + nav_select * NAME_SIZE);
- hotpot_load();
- break;
-
- /* create hotpot file, then open it */
- case 2:
- strcpy(open_dir, dir_current);
- strcat(open_dir, dir_list + nav_select * NAME_SIZE);
- char hotpot_file[PATH_SIZE + NAME_SIZE];
- strcpy(hotpot_file, open_dir);
- strcat(hotpot_file, "/.htpt");
- FILE *f = fopen(hotpot_file, "w");
- if (!f) {
- set_activity_status(STATUS_ERROR, 1);
- printf("ERROR - couldn't create new hotpot file");
- return;
- }
- fclose(f);
- hotpot_load();
- break;
- }
-
- file_picker_close();
- set_main_win_states(1);
- }
-
- /* returns the hilight color index of the directory */
- int
- find_dir_spot(char *search_dir, char *sub_dir)
- {
- char search_path[PATH_SIZE];
- strcpy(search_path, search_dir);
- strcat(search_path, sub_dir);
- strcat(search_path, "/");
-
- DIR *d;
- struct dirent *dir;
- struct stat file_stats;
- char file_path[PATH_SIZE + NAME_SIZE];
-
- d = opendir(search_path);
- if (!d) {
- printf("ERROR - couldn't read directory");
- return 0;
- }
-
- while ((dir = readdir(d))) {
- strcpy(file_path, search_path);
- strcat(file_path, dir->d_name);
- stat(file_path, &file_stats);
- if ((file_stats.st_mode & S_IFMT) != S_IFDIR) {
- if (strcmp(dir->d_name, ".htpt") == 0) {
- return 1;
- }
- }
- }
- return 2;
- }
-
- char*
- get_data_item(unsigned int col, unsigned int row)
- {
- return data + ITEM_SIZE * (col + row * (DATA_COLS_N + 3));
- }
-
- void
- hotpot_close()
- {
- hotpot_unload();
- select_data = -1;
- strcpy(select_note, "");
- strcpy(open_dir, "");
-
- set_main_win_states(1);
- }
-
- void
- hotpot_load()
- {
- set_activity_status(STATUS_BUSY, 1);
-
- char hotpot_file[PATH_SIZE + NAME_SIZE];
- strcpy(hotpot_file, open_dir);
- strcat(hotpot_file, "/.htpt");
-
- FILE *f = fopen(hotpot_file, "r");
- if (!f) {
- printf("ERROR - couldn't read hotpot file\n");
- set_activity_status(STATUS_ERROR, 1);
- return;
- }
-
- hotpot_unload();
-
- /* arrays preparation for on the go resizing */
- data_buffer_n = DATA_BUFFER_INC;
- data = malloc(data_buffer_n * ITEM_SIZE * (DATA_COLS_N + 3));
- data_notes = malloc(data_buffer_n * TEXT_SIZE);
- data_tags = malloc(data_buffer_n * sizeof(int));
- data_spot = malloc(data_buffer_n * sizeof(int));
- data_rename = malloc(data_buffer_n * ITEM_SIZE); /* used for syncing later */
-
- data_entry_t entry_read;
- char line_read[READ_SIZE];
- char *last_newline;
- int in_section = 0, col = 0, w = 0;
-
- /* get lastest used uid on the first line */
- /* if it is not present it will be regenerated after the rest of the file has
- * been parsed */
- if (fgets(line_read, READ_SIZE, f) && line_read[0] == '-') {
- last_uid = strtol(line_read + 1, NULL, 16);
- } else {
- last_uid = 0; /* to be regenerated */
- }
-
- /* parse rest of .htpt file */
- while (fgets(line_read, READ_SIZE, f)) {
- switch (line_read[0]) {
-
- /* open section, reset entry_read */
- case '[':
- if (in_section)
- break;
- in_section = 1;
- col = 0;
- w = 0;
- entry_read.notes_w = 0;
- entry_read.notes[0] = '\0';
- entry_read.uid[0] = '\0';
- entry_read.filename[0] = '\0';
- for (int i = 0; i < DATA_COLS_N; i++)
- entry_read.misc[i][0] = '\0';
- break;
-
- /* close section, push entry_read to data */
- case ']':
- if (!in_section)
- break;
- in_section = 0;
- last_newline = strrchr(entry_read.notes, '\n');
- if (last_newline) /* remove last unecessary newline */
- *last_newline = '\0';
- push_entry(TAG_STRAY, entry_read);
- break;
-
- /* get uid */
- case '-':
- if (!in_section)
- break;
- clean_string_copy(entry_read.uid, line_read + 1, ITEM_SIZE, 1);
- break;
-
- /* get filename */
- case '+':
- if (!in_section)
- break;
- clean_string_copy(entry_read.filename, line_read + 1, ITEM_SIZE, 1);
- break;
-
- /* get other data */
- case '.':
- if (!in_section || col >= DATA_COLS_N)
- break;
- clean_string_copy(entry_read.misc[col], line_read + 1, ITEM_SIZE, 1);
- col++;
- break;
-
- /* get notes on multiple lines until section close or reaching TEXT_SIZE
- * character limit */
- case '*':
- if (!in_section)
- break;
- w = strlen(line_read + 1);
- if (entry_read.notes_w + w >= TEXT_SIZE) {
- w = TEXT_SIZE - entry_read.notes_w;
- } else {
- strncat(entry_read.notes, line_read + 1, w);
- }
- entry_read.notes_w += w;
- break;
-
- default:
- break;
- }
- }
- fclose(f);
-
- /* regenerate uid if needed */
- if (!last_uid) {
- for (int i = 0; i < data_n; i++)
- if (last_uid < strtol(get_data_item(UID_COL, i), NULL, 16))
- last_uid = strtol(get_data_item(UID_COL, i), NULL, 16);
- }
-
- /* parse all files in hotpot directory and match them to parsed data */
- DIR *d = opendir(open_dir);
- struct dirent *dir;
- struct stat file_stats;
- char file_path[PATH_SIZE + NAME_SIZE];
- int found = 0;
- int new_files = 0;
- int n = data_n;
- int is_dir;
-
- data_entry_t dummy_entry;
- dummy_entry.uid[0] = '\0';
- dummy_entry.notes[0] = '\0';
- dummy_entry.notes_w = 0;
- for (int i = 0; i < DATA_COLS_N; i++)
- dummy_entry.misc[i][0] = '\0';
-
- /* scan found files */
- while ((dir = readdir(d))) {
- found = 0;
- strcpy(file_path, open_dir);
- strcat(file_path, dir->d_name);
- stat(file_path, &file_stats);
- is_dir = (file_stats.st_mode & S_IFMT) == S_IFDIR ? 1 : 0;
- //printf("%i\t%s\n", is_dir, dir->d_name); TODO fix directory detection
- if (is_dir || dir->d_name[0] == '.') {
- continue;
- }
- for (int i = 0; i < n; i++) {
- if (strcmp(dir->d_name, get_data_item(NAME_COL, i)) == 0) {
- data_tags[i] = TAG_NONE;
- found = 1;
- break;
- }
- }
- /* if file not found, create new entry */
- if (!found) {
- clean_string_copy(dummy_entry.filename, dir->d_name, ITEM_SIZE, 0);
- push_entry(TAG_NEW, dummy_entry);
- new_files = 1;
- }
- }
-
- /* set tag values in data */
- for (int i = 0; i < data_n; i++) {
- set_entry_tag_col(i, data_tags[i]);
- }
-
- btk_cell_table_deselect(table_cell);
- strcpy(select_note, "");
- set_activity_status((new_files ? STATUS_EDITED : STATUS_LATEST), 1);
-
-
- return;
- }
-
- void
- hotpot_reload()
- {
- hotpot_unload();
- select_data = -1;
- strcpy(select_note, "");
-
- hotpot_load();
-
- set_main_win_states(1);
- }
-
- void
- hotpot_sync()
- {
- set_activity_status(STATUS_BUSY, 1);
-
- char hotpot_file[PATH_SIZE + NAME_SIZE];
- strcpy(hotpot_file, open_dir);
- strcat(hotpot_file, "/.htpt");
-
- FILE *f = fopen(hotpot_file, "w");
- if (!f) {
- printf("ERROR - couldn't write hotpot file\n");
- set_activity_status(STATUS_ERROR, 1);
- return;
- }
-
- /* output last uid */
- fprintf(f, "-%X\n\n", last_uid);
-
- /* output rows of data */
- char *note_token;
- char note[TEXT_SIZE];
- for (int i = 0; i < data_n; i++) {
-
- if ((data_tags[i] & TAG_DEL))
- continue;
-
- fprintf(f, "[\n");
-
- fprintf(f, "-%s\n", get_data_item(UID_COL, i));
- fprintf(f, "+%s\n", get_data_item(NAME_COL, i));
- for (int j = 0; j < DATA_COLS_N; j++)
- fprintf(f, ".%s\n", get_data_item(j + 3, i));
-
- // TODO
- /*
- strcpy(note, data_notes + i * TEXT_SIZE);
- char *lim = strchr(note, '\n');
- while (lim) {
- *lim = '\0';
- printf("%lu >> \'%s\'\n", strlen(note), note);
- fprintf(f, "*%s\n", note);
- strcpy(note, ++lim);
- lim = strchr(note, '\n');
- }
- */
-
- strcpy(note, data_notes + i * TEXT_SIZE);
- note_token = strtok(note, "\n");
- while (note_token) {
- fprintf(f, "*%s\n", note_token);
- note_token = strtok(NULL, "\n");
- }
-
- fprintf(f, "]\n\n");
- }
- fclose(f);
-
- /* rename edited files if those are not stray entries */
- char cmd_mv[11 + 2 * (PATH_SIZE + NAME_SIZE)];
- for (int i = 0; i < data_n; i++) {
- if (!(data_tags[i] & TAG_STRAY) && strcmp(data_rename + i * ITEM_SIZE, "")) {
- sprintf(cmd_mv,
- "mv \'%s/%s\' \'%s/%s\'",
- open_dir,
- data_rename + i * ITEM_SIZE,
- open_dir,
- get_data_item(NAME_COL, i));
- system(cmd_mv);
- }
- }
-
- /* delete rows with DEL tag by shifting down */
- int c = 0;
- char mid[TEXT_SIZE]; /* just to get rid of pointer overlap warning */
- char cmd_rm[5 + PATH_SIZE + NAME_SIZE];
- for (int i = 0; i < data_n; i++) {
- if (c) {
- data_tags[i - c] = data_tags[i];
- strcpy(mid, data_notes + i * TEXT_SIZE);
- strcpy(data_notes + (i - c) * TEXT_SIZE, mid);
- for (int j = 0; j < DATA_COLS_N + 3; j++)
- strcpy(get_data_item(j, i - c), get_data_item(j, i));
- }
- if ((data_tags[i] & TAG_DEL)) {
- if (!(data_tags[i] & TAG_STRAY)) {
- sprintf(cmd_rm,
- "rm \'%s/%s\'",
- open_dir,
- get_data_item(NAME_COL, i));
- system(cmd_rm);
- }
- c++;
- }
- }
- data_n -= c;
-
- /* remove EDIT and NEW tags */
- for (int i = 0; i < data_n; i++) {
- data_tags[i] &= ~(TAG_EDITED | TAG_NEW);
- }
-
- /* update tag values in data */
- for (int i = 0; i < data_n; i++) {
- set_entry_tag_col(i, data_tags[i]);
- }
-
- set_activity_status(STATUS_LATEST, 0);
- btk_window_redraw(main_win);
-
- return;
- }
-
- void
- hotpot_unload()
- {
- if (data_n) {
- free(data);
- free(data_tags);
- free(data_spot);
- free(data_notes);
- free(data_rename);
- data_n = 0;
- }
- }
-
- void
- move_dir(int dir_sel)
- {
- if (dir_sel < 0 || !dir_spot[dir_sel])
- return;
-
- /* if first item selected ("..") go one dir up, unless at / */
- if (!dir_sel) {
- if (strlen(dir_current) <= 1)
- return;
- dir_current[strlen(dir_current) - 1] = '\0';
- *(strrchr(dir_current, '/')) = '\0';
- } else {
- char dir_sel_name[PATH_SIZE];
- strcpy(dir_sel_name, dir_list + dir_sel * NAME_SIZE);
- strcat(dir_current, dir_sel_name);
- }
-
- strcat(dir_current, "/");
- parse_dir(dir_current, nav_mode);
- btk_window_redraw_cell(file_picker, dir_list_cell_id);
- btk_window_redraw_cell(file_picker, 2);
-
- if (dir_sel) {
- btk_cell_list_deselect(dir_list_cell);
- set_file_picker_states(-1);
- }
- }
-
- void
- open_ext_dir()
- {
- char *args[PATH_SIZE]={"./EXEC", open_dir, NULL};
- int pid = fork();
-
- if (pid == 0) {
- execvp("xdg-open", args);
- } else if (pid < 0) {
- printf("ERROR - couldn't open hotpot directory in file explorer\n");
- }
- }
-
- void
- open_ext_entry(int sel)
- {
- if (sel < 0)
- return;
-
- char file[PATH_SIZE + ITEM_SIZE];
- strcpy(file, open_dir);
- strcat(file, "/");
- strcat(file, get_data_item(NAME_COL, sel));
-
- char *args[PATH_SIZE]={"./EXEC", file, NULL};
- int pid = fork();
-
- if (pid == 0) {
- execvp("xdg-open", args);
- } else if (pid < 0) {
- printf("ERROR - couldn't open item externaly\n");
- }
- }
-
- int
- parse_dir(char *dir_path, int mode)
- {
- DIR *d = opendir(dir_path);
- if (!d) {
- printf("ERROR - couldn't read directory");
- return 1;
- }
-
- struct dirent *dir;
- struct stat file_stats;
- char file_path[PATH_SIZE + NAME_SIZE];
- unsigned int dir_buffer_n = DIR_BUFFER_INC;
- int c = 0;
- int is_dir;
-
- if (dir_list_n) {
- free(dir_list);
- free(dir_spot);
- }
-
- dir_list_n = 0;
- dir_list = malloc(dir_buffer_n * NAME_SIZE);
- dir_spot = malloc(dir_buffer_n * sizeof(int));
-
- while ((dir = readdir(d))) {
- sprintf(file_path, "%s%s", dir_path, dir->d_name);
- stat(file_path, &file_stats);
- is_dir = (file_stats.st_mode & S_IFMT) == S_IFDIR ? 1 : 0;
- if (((mode & DIR_FILES) || is_dir) && c &&
- ((mode & DIR_HIDDEN) || dir->d_name[0] != '.' || c < 2)) {
- strcpy(dir_list + dir_list_n * NAME_SIZE, dir->d_name);
- if (is_dir) /* adding '/' to dir items to easily detect them when sorting */
- strcat(dir_list + dir_list_n * NAME_SIZE, "/");
- dir_spot[dir_list_n] = 0;
- dir_list_n++;
- }
- c++;
- if (dir_list_n >= dir_buffer_n - 1) {
- dir_buffer_n += DIR_BUFFER_INC;
- dir_spot = realloc(dir_spot, dir_buffer_n * sizeof(int));
- dir_list = realloc(dir_list, dir_buffer_n * NAME_SIZE);
- }
- }
-
- /* sort dir list and set hilights */
- char *a;
- qsort(dir_list, dir_list_n, NAME_SIZE, cmp_str_for_qsort);
- for (int i = 0; i < dir_list_n; i++) {
- a = strchr(dir_list + i * NAME_SIZE, '/');
- if (a) {
- *a = '\0';
- dir_spot[i] = find_dir_spot(dir_path, dir_list + i * NAME_SIZE);
- }
- }
-
- return 0;
- }
-
- void
- push_entry(int tag, data_entry_t entry)
- {
- if (!data) {
- printf("ERROR - tried to push entry into NULL data array\n");
- return;
- }
-
- if (data_n >= data_buffer_n - 1) {
- data_buffer_n += DATA_BUFFER_INC;
- data = realloc(data, data_buffer_n * ITEM_SIZE * (DATA_COLS_N + 3));
- data_notes = realloc(data_notes, data_buffer_n * TEXT_SIZE);
- data_tags = realloc(data_tags, data_buffer_n * sizeof(int));
- data_spot = realloc(data_spot, data_buffer_n * sizeof(int));
- data_rename = realloc(data_rename, data_buffer_n * ITEM_SIZE);
- }
-
- if (!strcmp(entry.uid, "")) {
- char new_uid[64];
- sprintf(new_uid, "%X", ++last_uid);
- strcpy(get_data_item(UID_COL, data_n), new_uid);
- } else {
- strcpy(get_data_item(UID_COL, data_n), entry.uid);
- }
-
- data_tags[data_n] = tag;
- strcpy(data_rename + data_n * ITEM_SIZE, "");
- strcpy(get_data_item(NAME_COL, data_n), entry.filename);
- for (int i = 0; i < DATA_COLS_N; i++)
- strcpy(get_data_item(i + 3, data_n), entry.misc[i]);
- strcpy(data_notes + data_n * TEXT_SIZE, entry.notes);
-
- data_n++;
- }
-
- void
- quit()
- {
- hotpot_unload();
- if (dir_list_n) {
- free(dir_list);
- free(dir_spot);
- }
-
- btk_window_destroy(entry_form);
- btk_window_destroy(file_picker);
- btk_window_destroy(main_win);
- btk_window_destroy(settings);
- btk_close(session);
-
- exit(0);
- }
-
- void
- settings_close()
- {
- btk_window_enable(main_win);
- btk_unmap(session, settings);
- }
-
- void
- settings_open()
- {
- btk_window_disable(main_win);
- btk_map(session, settings);
- }
-
- void
- set_activity_status(int status, int redraw)
- {
- switch (status) {
- case STATUS_NONE:
- strcpy(status_activity, "n/a");
- activity_cell->state |= BTK_CELL_STATE_DISABLED;
- activity_cell->state &= ~BTK_CELL_STATE_BELL;
- activity_cell->state &= ~BTK_CELL_STATE_ON;
- break;
- case STATUS_ERROR:
- strcpy(status_activity, "error");
- activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
- activity_cell->state |= BTK_CELL_STATE_BELL;
- activity_cell->state &= ~BTK_CELL_STATE_ON;
- break;
- case STATUS_LATEST:
- strcpy(status_activity, "synced");
- activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
- activity_cell->state &= ~BTK_CELL_STATE_BELL;
- activity_cell->state &= ~BTK_CELL_STATE_ON;
- break;
- case STATUS_EDITED:
- strcpy(status_activity, "unsynced");
- activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
- activity_cell->state &= ~BTK_CELL_STATE_BELL;
- activity_cell->state |= BTK_CELL_STATE_ON;
- break;
- case STATUS_BUSY:
- strcpy(status_activity, "busy");
- activity_cell->state &= ~BTK_CELL_STATE_DISABLED;
- activity_cell->state |= BTK_CELL_STATE_BELL;
- activity_cell->state &= ~BTK_CELL_STATE_ON;
- break;
- }
-
- if (redraw)
- btk_window_redraw_cell(main_win, activity_cell_id);
- }
-
- void
- set_edit_tag()
- {
- if (select_data < 0 || select_data >= data_n) {
- printf("ERROR - can't tag out of bounds selection\n");
- return;
- }
-
- data_tags[select_data] |= TAG_DEL;
- btk_window_redraw_cell(main_win, table_cell_id);
- }
-
- void
- set_entry_tag_col(unsigned int id, int tag)
- {
- if (tag & TAG_DEL) {
- strcpy(get_data_item(TAG_COL, id), "DEL");
- data_spot[id] = 1;
- } else if (tag & TAG_VISIBILITY) {
- strcpy(get_data_item(TAG_COL, id), "FOCUS");
- data_spot[id] = 4;
- } else if (tag & TAG_EDITED){
- strcpy(get_data_item(TAG_COL, id), "EDIT");
- data_spot[id] = 1;
- } else if (tag & TAG_STRAY){
- strcpy(get_data_item(TAG_COL, id), "STRAY");
- data_spot[id] = 3;
- } else if (tag & TAG_NEW){
- strcpy(get_data_item(TAG_COL, id), "NEW");
- data_spot[id] = 2;
- } else {
- strcpy(get_data_item(TAG_COL, id), "");
- data_spot[id] = 0;
- }
- }
-
- void
- set_file_picker_states(int sel)
- {
- nav_select = sel;
-
- if (sel < 1) { /* separate to avoid segfault */
- file_select_cell->state |= BTK_CELL_STATE_DISABLED;
- btk_window_redraw_cell(file_picker, file_select_cell_id);
- return;
- }
-
- switch (file_picker_mode) {
- case 0:;
- char forbidden_path[PATH_SIZE];
- strcpy(forbidden_path, open_dir);
- strcat(forbidden_path, "/");
- if(!dir_spot[sel] && strcmp(dir_current, forbidden_path) != 0 && !file_exists()) {
- file_select_cell->state &= ~(BTK_CELL_STATE_DISABLED);
- } else {
- file_select_cell->state |= BTK_CELL_STATE_DISABLED;
- }
- break;
- case 1:
- if (dir_spot[sel] == 1) {
- file_select_cell->state &= ~(BTK_CELL_STATE_DISABLED);
- } else {
- file_select_cell->state |= BTK_CELL_STATE_DISABLED;
- }
- break;
- case 2:
- if (dir_spot[sel] == 1) {
- file_select_cell->state |= BTK_CELL_STATE_DISABLED;
- } else {
- file_select_cell->state &= ~(BTK_CELL_STATE_DISABLED);
- }
- break;
- }
-
- btk_window_redraw_cell(file_picker, file_select_cell_id);
- }
-
- void
- set_main_win_states(int redraw)
- {
- if (!(strcmp(open_dir, ""))) {
- main_win->cells[4].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[5].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[6].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[7].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[10].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[16].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[17].state |= BTK_CELL_STATE_DISABLED;
- strcpy(status_open_file, "no hotpot opened");
- strcpy(status_files_n, "n/a entries");
- set_activity_status(STATUS_NONE, redraw);
- } else {
- main_win->cells[4].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[5].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[6].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[7].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[10].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[16].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[17].state &= ~BTK_CELL_STATE_DISABLED;
- strcpy(status_open_file, open_dir);
- sprintf(status_files_n, "%i entries", data_n);
- }
-
- if (data_n < 1 || select_data < 0) {
- main_win->cells[11].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[12].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[19].state |= BTK_CELL_STATE_DISABLED;
- } else {
- main_win->cells[11].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[12].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[19].state &= ~BTK_CELL_STATE_DISABLED;
- }
-
- if (redraw)
- btk_window_redraw(main_win);
- }
-
- void
- str_to_lower_case(char *str)
- {
- for (int i = 0; str[i] != '\0'; i++)
- if(str[i] >= 'A' && str[i] <= 'Z')
- str[i] += 32;
- }
-
- void
- toggle_col(int val, btk_arg_t arg)
- {
- data_cols_ena[arg.i] = val;
- btk_cell_table_update_geometry(table_cell);
- btk_window_redraw_cell(main_win, table_cell_id);
- }
-
- void
- toggle_del_tag()
- {
- if (select_data < 0 || select_data >= data_n) {
- printf("ERROR - can't tag out of bounds selection\n");
- return;
- }
-
- data_tags[select_data] ^= TAG_DEL;
- set_entry_tag_col(select_data, data_tags[select_data]);
- set_activity_status(STATUS_EDITED, 1);
- btk_window_redraw_cell(main_win, table_cell_id);
- }
-
- void
- toggle_hidden(int i, btk_arg_t arg)
- {
- if (i) {
- nav_mode |= DIR_HIDDEN;
- } else {
- nav_mode &= ~DIR_HIDDEN;
- }
- parse_dir(dir_current, nav_mode);
- btk_window_redraw_cell(file_picker, dir_list_cell_id);
- }
-
- void
- toggle_notes(int val, btk_arg_t arg)
- {
- if (val) {
- table_cell->ca.h = 9;
- notes_view_cell->state &= ~BTK_CELL_STATE_HIDDEN;
- } else {
- table_cell->ca.h = 15;
- notes_view_cell->state |= BTK_CELL_STATE_HIDDEN;
- }
- btk_window_update_cell_area(main_win, table_cell);
- btk_window_redraw(main_win);
- }
-
- void
- toggle_visibility_tag()
- {
- if (select_data < 0 || select_data >= data_n) {
- printf("ERROR - can't tag out of bounds selection\n");
- return;
- }
-
- data_tags[select_data] ^= TAG_VISIBILITY;
- set_entry_tag_col(select_data, data_tags[select_data]);
- btk_window_redraw_cell(main_win, table_cell_id);
- }
-
- void
- update_select_data(int sel)
- {
- select_data = sel;
- if (sel > data_n)
- select_data = -1;
-
- if (select_data < 0) {
- strcpy(select_note, "");
- main_win->cells[11].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[12].state |= BTK_CELL_STATE_DISABLED;
- main_win->cells[19].state |= BTK_CELL_STATE_DISABLED;
- } else {
- strcpy(select_note,data_notes + sel * TEXT_SIZE);
- main_win->cells[11].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[12].state &= ~BTK_CELL_STATE_DISABLED;
- main_win->cells[19].state &= ~BTK_CELL_STATE_DISABLED;
- }
-
- btk_cell_editor_update_text(notes_view_cell);
- btk_window_redraw_cell(main_win, notes_view_cell_id);
- btk_window_redraw_cell(main_win, 11);
- btk_window_redraw_cell(main_win, 12);
- btk_window_redraw_cell(main_win, 19);
- }
|