Как создать представление дерева каталогов проекта и хранилище дерева в GTK? - PullRequest
0 голосов
/ 26 сентября 2018

Недавно я столкнулся с проблемой при попытке создать представление проекта в GTK.Проблема заключается в том, что моя программа постоянно удаляет и добавляет файлы в каталог проекта, но для учета этих изменений необходимо очистить и заново заполнить TreeStore представления дерева проекта.Когда TreeStore очищается и снова заполняется, проект TreeView сворачивает все свои заголовки.Возьмите следующий пример:

enter image description here

Это представление проекта до того, как программа добавляет другую папку с именем «SubProject2» в MainProject, очищает TreeModel и заполняет заново.это с тем же каталогом.

Это представление проекта после: enter image description here

Обратите внимание, что папка «SubProject2» была добавлена ​​правильно в «MainProject», ноTreeView свернул «MainProject».

Мой текущий код для повторного заполнения TreeView следующий:

void populate_directory_tree_store(GtkTreeStore *treestore, const char *directory, GtkTreeIter *toplevel) {
    DIR *dir;
    struct dirent *entry;

    GtkTreeIter child;

    if (!(dir = opendir(directory)))
        return;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_DIR) {
            char path[1024];
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
                continue;
            snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name);

            gtk_tree_store_append(treestore, &child, toplevel);
            gtk_tree_store_set(treestore, &child,
                0, entry->d_name,
                -1);

            populate_directory_tree_store(treestore, path, &child);
        }
        else {
            gtk_tree_store_append(treestore, &child, toplevel);
            gtk_tree_store_set(treestore, &child,
                0, entry->d_name,
                -1);
        }
    }
    closedir(dir);
}

Каждый раз, когда изменяется каталог проекта, я вызываю функцию следующим образом:

gtk_tree_store_clear(treestore);
populate_directory_tree_store(treestore, "C:\\Projects", &topIterator);

Я думал об использовании библиотеки, такой как libfswatch (, расположенной здесь ), для обнаружения изменений каталога в реальном времени и изменения TreeView проекта при каждом изменении, но это требует многопоточности.Я не знаю, пропускаю ли я что-то в GtkTreeView, но кое-что в этом тривиальном не должно быть таким сложным.Если у вас есть какие-либо вопросы или пожелания, пожалуйста, напишите их.

Спасибо, Vikas

1 Ответ

0 голосов
/ 26 сентября 2018

Я решил эту проблему, сохранив развернутые строки в структуре данных перед очисткой TreeView.Я использовал список данных с ключами, чтобы связать имя расширенной строки и соответствующую ей глубину (имя строки - это ключ, а глубина - это значение).Затем я очищаю TreeView и снова заполняю его как обычно.После этого я пересекаю TreeModel строка за строкой.Если имя строки является ключом в списке данных с ключами, а глубина строки равна значению глубины списка данных с ключами, я расширяю эту строку.Вот код:

num
{
    COL_NAME = 0,
    NUM_COLS
};

void populate_directory_tree_store(GtkTreeStore *treestore, const char *directory, GtkTreeIter *toplevel) {
    DIR *dir;
    struct dirent *entry;

    GtkTreeIter child;

    if (!(dir = opendir(directory)))
        return;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_DIR) {
            char path[1024];
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
                continue;
            snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name);

            gtk_tree_store_append(treestore, &child, toplevel);
            gtk_tree_store_set(treestore, &child,
                0, entry->d_name,
                -1);

            populate_directory_tree_store(treestore, path, &child);
        }
        else {
            gtk_tree_store_append(treestore, &child, toplevel);
            gtk_tree_store_set(treestore, &child,
                0, entry->d_name,
                -1);
        }
    }
    closedir(dir);
}

void foreach_expanded_row(GtkTreeView *tree_view, GtkTreePath *path, gpointer user_data) {
    GData **datalist = user_data;

    GtkTreeStore *treestore = GTK_TREE_STORE(gtk_tree_view_get_model(tree_view));

    GValue key = G_VALUE_INIT;

    char *treePathString = gtk_tree_path_to_string(path);

    GtkTreeIter treeIter;
    gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(treestore), &treeIter, treePathString);
    gtk_tree_model_get_value(GTK_TREE_MODEL(treestore), &treeIter, COL_NAME, &key);

    g_datalist_id_set_data(datalist, g_quark_from_string(g_value_get_string(&key)), GINT_TO_POINTER(gtk_tree_path_get_depth(path)));
}

gboolean foreach_tree_model_row(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
    struct combined_data {
        GData **datalist;
        GtkTreeView *treeview;
    };

    struct combined_data *cd = data;

    GData **datalist = cd->datalist;
    GtkTreeView *treeview = cd->treeview;

    GValue key = G_VALUE_INIT;

    char *treePathString = gtk_tree_path_to_string(path);

    GtkTreeIter treeIter;
    gtk_tree_model_get_iter_from_string(model, &treeIter, treePathString);
    gtk_tree_model_get_value(model, &treeIter, COL_NAME, &key);

    int depth = g_datalist_get_data(datalist, g_value_get_string(&key));

    if (depth && gtk_tree_path_get_depth(path) == depth) {
        gtk_tree_view_expand_row(treeview, path, FALSE);
    }

    return FALSE;
}

void refresh_tree_view(GtkTreeView *treeview, GtkTreeStore *treestore) {
    GData *datalist;

    g_datalist_init(&datalist);

    gtk_tree_view_map_expanded_rows(treeview, foreach_expanded_row, &datalist);

    GtkTreeIter toplevel;
    gtk_tree_store_clear(treestore);
    gtk_tree_store_append(treestore, &toplevel, NULL);
    gtk_tree_store_set(treestore, &toplevel, 0, "MainProject", -1);

    populate_directory_tree_store(treestore, "C:\\Projects, &toplevel);

    struct combined_data {
        GData **datalist;
        GtkTreeView *treeview;
    };

    struct combined_data *cd = malloc(sizeof(struct combined_data));

    cd->datalist = &datalist;
    cd->treeview = treeview;

    gtk_tree_model_foreach(GTK_TREE_MODEL(treestore), foreach_tree_model_row, cd);

    free(cd);
}

Каждый раз, когда мне нужно обновить представление проекта с текущими каталогами, я просто звоню

refresh_tree_view(treeview, treestore);

Надеюсь, это поможет любому с той же проблемой.

...