1
0
mirror of https://github.com/altlinux/admc.git synced 2025-01-08 01:18:25 +03:00

move layout to glade

This commit is contained in:
Dmitry Degtyarev 2020-05-01 15:00:25 +04:00
parent 1e43d647ac
commit 31dfebd211
21 changed files with 706 additions and 432 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
obj/*

View File

@ -9,6 +9,7 @@ OBJS := $(addprefix $(OBJDIR)/, $(addsuffix .o, $(basename $(notdir $(SOURCES)))
CFLAGS += -Isrc/libs/
CFLAGS += -g -Wall -Wformat
CFLAGS += `pkg-config --cflags gtk+-3.0`
CFLAGS += -rdynamic
LIBS += `pkg-config --libs gtk+-3.0`
LIBS += -lldap -llber -lresolv -lgsasl

373
data/adtool.glade Normal file
View File

@ -0,0 +1,373 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkTreeStore" id="attributes_model">
<columns>
<!-- column-name Name -->
<column type="gchararray"/>
<!-- column-name Value -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeStore" id="containers_model">
<columns>
<!-- column-name containers_model_column_DN -->
<column type="gchararray"/>
<!-- column-name containers_model_column_Name -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeModelFilter" id="containers_model_filter">
<property name="child_model">containers_model</property>
</object>
<object class="GtkTreeStore" id="contents_model">
<columns>
<!-- column-name DN -->
<column type="gchararray"/>
<!-- column-name Name -->
<column type="gchararray"/>
<!-- column-name Type -->
<column type="gchararray"/>
<!-- column-name Description -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeModelFilter" id="contents_model_filter">
<property name="child_model">contents_model</property>
</object>
<object class="GtkWindow" id="window">
<property name="width_request">900</property>
<property name="height_request">600</property>
<property name="can_focus">False</property>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkMenuBar" id="menu_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-new</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-save-as</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-quit</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Edit</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-cut</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-copy</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-paste</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-delete</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menu_bar_view">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_View</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckMenuItem" id="advanced_view_toggle">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Advanced View</property>
<property name="use_underline">True</property>
<signal name="toggled" handler="advanced_view_toggled_func" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Help</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-about</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkPaned" id="outer_paned">
<property name="width_request">200</property>
<property name="height_request">500</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkTreeView" id="containers_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">containers_model_filter</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<signal name="changed" handler="containers_selection_changed_func" swapped="no"/>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Name</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkPaned" id="inner_paned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkTreeView" id="contents_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">contents_model_filter</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<signal name="changed" handler="contents_selection_changed_func" swapped="no"/>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Name</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Type</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Description</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">DN</property>
</object>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkTreeView" id="attributes_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">attributes_model</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Name</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Value</property>
<child>
<object class="GtkCellRendererText">
<property name="editable">True</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</interface>

View File

@ -1,6 +0,0 @@
#pragma once
#include <gtk/gtk.h>
GtkWidget* attributes_init();
void attributes_update_model(const char* new_root_dn);

View File

@ -1,5 +1,5 @@
#include "attributes_pane.h"
#include "attributes_view.h"
#include "constants.h"
#include "utils.h"
@ -14,7 +14,7 @@ enum {
ATTRIBUTES_COLUMN_COUNT
};
GtkWidget* attributes_view = NULL;
GtkTreeView* attributes_view = NULL;
char selected_dn[DN_LENGTH_MAX];
// Lists attributes of last selected entry in contents pane
@ -27,8 +27,7 @@ void attributes_value_edited_func(
gchar* new_text,
gpointer user_data)
{
GtkTreeView* view = GTK_TREE_VIEW(attributes_view);
GtkTreeModel* model = gtk_tree_view_get_model(view);
GtkTreeModel* model = gtk_tree_view_get_model(attributes_view);
GtkTreeIter iter;
gtk_tree_model_get_iter_from_string(model, &iter, path_string);
@ -54,31 +53,10 @@ void attributes_value_edited_func(
free(old_value);
}
GtkWidget* attributes_init() {
// NOTE: model is set when an entry is selected in contents pane
GtkTreeStore* model = gtk_tree_store_new(ATTRIBUTES_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING);
attributes_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
// Name column
GtkTreeViewColumn* name_column = gtk_tree_view_column_new_with_attributes("Name", gtk_cell_renderer_text_new(), "text", ATTRIBUTES_COLUMN_NAME, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(attributes_view), name_column);
// Value column, editable
// Create special editable renderer for value column
GtkCellRenderer* value_renderer = gtk_cell_renderer_text_new();
g_object_set(value_renderer, "editable", TRUE, NULL);
g_signal_connect(value_renderer, "edited", (GCallback) attributes_value_edited_func, NULL);
GtkTreeViewColumn* value_column = gtk_tree_view_column_new_with_attributes("Value", value_renderer, "text", ATTRIBUTES_COLUMN_VALUE, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(attributes_view), value_column);
return attributes_view;
}
void attributes_update_model(const char* new_root_dn) {
GtkTreeStore* model = gtk_tree_store_new(ATTRIBUTES_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING);
// entry* e = shget(entries, new_root_dn);
// NOTE: model is set when an entry is selected in contents pane
void attributes_populate_model(const char* new_root_dn) {
GtkTreeStore* model = GTK_TREE_STORE(gtk_tree_view_get_model(attributes_view));
gtk_tree_store_clear(model);
// Populate model
// List all key->value pairs in order
@ -101,8 +79,9 @@ void attributes_update_model(const char* new_root_dn) {
}
}
gtk_tree_view_set_model(GTK_TREE_VIEW(attributes_view), GTK_TREE_MODEL(model));
g_object_unref(model);
strncpy(selected_dn, new_root_dn, DN_LENGTH_MAX);
}
void attributes_init(GtkBuilder* builder) {
attributes_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "attributes_view"));
}

6
src/attributes_view.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <gtk/gtk.h>
void attributes_init(GtkBuilder* builder);
void attributes_populate_model(const char* new_root_dn);

View File

@ -1,127 +0,0 @@
#include "containers_pane.h"
#include "contents_pane.h"
#include "menubar.h"
#include "constants.h"
#include "utils.h"
#include "entry.h"
#include "stb_ds.h"
#include <string.h>
#include <stdbool.h>
#include <gtk/gtk.h>
enum {
CONTAINERS_COLUMN_DN,
CONTAINERS_COLUMN_NAME,
CONTAINERS_COLUMN_COUNT
};
GtkWidget* containers_view = NULL;
void containers_refilter_model() {
GtkTreeModel* model_filter = gtk_tree_view_get_model(GTK_TREE_VIEW(containers_view));
gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(model_filter));
}
void containers_populate_model(GtkTreeStore* model, char* node_dn, GtkTreeIter* parent) {
// Populate model with name's of entries
entry* e = shget(entries, node_dn);
// Skip if entry is not a container
if (!entry_is_container(e)) {
return;
}
// TODO: handle no name?
STR_ARRAY name = entry_get_attribute(e, "name");
GtkTreeIter this_node;
gtk_tree_store_append(model, &this_node, parent);
gtk_tree_store_set(model, &this_node, CONTAINERS_COLUMN_DN, node_dn, -1);
gtk_tree_store_set(model, &this_node, CONTAINERS_COLUMN_NAME, name[0], -1);
// Recurse into entry's children
for (int i = 0; i < arrlen(e->children); i++) {
char* child_dn = e->children[i];
containers_populate_model(model, child_dn, &this_node);
}
}
void containers_selection_changed_func(GtkTreeSelection* selection, gpointer user_data) {
// Get selected iter
GtkTreeView* view = gtk_tree_selection_get_tree_view(selection);
GtkTreeModel* model = gtk_tree_view_get_model(view);
GtkTreeIter iter;
gboolean any_selected = gtk_tree_selection_get_selected(selection, &model, &iter);
if (!any_selected) {
return;
}
// Get dn of selected iter
char* dn;
gtk_tree_model_get(model, &iter, CONTAINERS_COLUMN_DN, &dn, -1);
// Update contents model
contents_update_model(dn);
free(dn);
}
gboolean containers_filter_func(
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
// Filter out entries with "showInAdvancedViewOnly" set to TRUE
gboolean visible = TRUE;
char* dn;
gtk_tree_model_get(model, iter, CONTAINERS_COLUMN_DN, &dn, -1);
entry* e = shget(entries, dn);
STR_ARRAY showInAdvancedViewOnly = entry_get_attribute(e, "showInAdvancedViewOnly");
if (!advanced_view_is_on() && showInAdvancedViewOnly != NULL && streql(showInAdvancedViewOnly[0], "TRUE")) {
visible = FALSE;
}
g_free(dn);
return visible;
}
GtkWidget* containers_init() {
// 2 columns: name and dn
// only name is shown, dn is used for identification in control
// Create and populate child model
GtkTreeStore* child_model = gtk_tree_store_new(CONTAINERS_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING);
containers_populate_model(child_model, HEAD_DN, NULL);
// Create model filter
GtkTreeModel* model = gtk_tree_model_filter_new(GTK_TREE_MODEL(child_model), NULL);
gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), containers_filter_func, NULL, NULL);
containers_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
g_object_unref(model);
// DN column, invisible, only for identification
GtkTreeViewColumn* dn_column = gtk_tree_view_column_new_with_attributes("DN", gtk_cell_renderer_text_new(), "text", CONTAINERS_COLUMN_DN, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(containers_view), dn_column);
gtk_tree_view_column_set_visible(dn_column, FALSE);
// Name column
GtkTreeViewColumn* name_column = gtk_tree_view_column_new_with_attributes("Name", gtk_cell_renderer_text_new(), "text", CONTAINERS_COLUMN_NAME, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(containers_view), name_column);
gtk_tree_view_column_set_sizing(name_column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width(name_column, 300);
// Selection changed callback
GtkTreeSelection* tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(containers_view));
g_signal_connect(tree_selection, "changed", G_CALLBACK(containers_selection_changed_func), NULL);
return containers_view;
}

View File

@ -1,6 +0,0 @@
#pragma once
#include <gtk/gtk.h>
GtkWidget* containers_init();
void containers_refilter_model();

109
src/containers_view.c Normal file
View File

@ -0,0 +1,109 @@
#include "containers_view.h"
#include "contents_view.h"
#include "constants.h"
#include "utils.h"
#include "entry.h"
#include "menu_bar.h"
#include "stb_ds.h"
#include <string.h>
#include <stdbool.h>
#include <gtk/gtk.h>
enum {
CONTAINERS_COLUMN_DN,
CONTAINERS_COLUMN_NAME,
};
GtkTreeView* containers_view = NULL;
void containers_refilter() {
GtkTreeModelFilter* model_filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(containers_view));
gtk_tree_model_filter_refilter(model_filter);
}
void containers_selection_changed_func(GtkTreeSelection* selection, gpointer user_data) {
// Get selected iter
GtkTreeView* view = gtk_tree_selection_get_tree_view(selection);
GtkTreeModel* model = gtk_tree_view_get_model(view);
GtkTreeIter iter;
gboolean any_selected = gtk_tree_selection_get_selected(selection, &model, &iter);
if (!any_selected) {
return;
}
// Get dn of selected iter
char* dn;
gtk_tree_model_get(model, &iter, CONTAINERS_COLUMN_DN, &dn, -1);
// Update contents model
contents_populate_model(dn);
free(dn);
}
gboolean containers_filter_func(
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
// Filter out entries with "showInAdvancedViewOnly" set to TRUE
gboolean visible = TRUE;
char* dn;
gtk_tree_model_get(model, iter, CONTAINERS_COLUMN_DN, &dn, -1);
entry* e = shget(entries, dn);
STR_ARRAY showInAdvancedViewOnly = entry_get_attribute(e, "showInAdvancedViewOnly");
if (!advanced_view_is_on() && showInAdvancedViewOnly != NULL && streql(showInAdvancedViewOnly[0], "TRUE")) {
visible = FALSE;
}
g_free(dn);
return visible;
}
void containers_populate_model_recursive(GtkTreeStore* model, char* node_dn, GtkTreeIter* parent) {
// Populate model with name's of entries
entry* e = shget(entries, node_dn);
// Skip if entry is not a container
// TODO: move this to filter?
// TODO: make containers and contents share model?
// contents can use "gtk_tree_path_is_descendant()"
if (!entry_is_container(e)) {
return;
}
// TODO: handle no name?
STR_ARRAY name = entry_get_attribute(e, "name");
GtkTreeIter this_node;
gtk_tree_store_append(model, &this_node, parent);
gtk_tree_store_set(model, &this_node, CONTAINERS_COLUMN_DN, node_dn, -1);
gtk_tree_store_set(model, &this_node, CONTAINERS_COLUMN_NAME, name[0], -1);
// Recurse into entry's children
for (int i = 0; i < arrlen(e->children); i++) {
char* child_dn = e->children[i];
containers_populate_model_recursive(model, child_dn, &this_node);
}
}
void containers_init(GtkBuilder* builder) {
containers_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "containers_view"));
// Populate model
GtkTreeStore* model = GTK_TREE_STORE(gtk_builder_get_object(builder, "containers_model"));
containers_populate_model_recursive(model, HEAD_DN, NULL);
// Set filter func
GtkTreeModelFilter* model_filter = GTK_TREE_MODEL_FILTER((gtk_tree_view_get_model(containers_view)));
gtk_tree_model_filter_set_visible_func(model_filter, containers_filter_func, NULL, NULL);
gtk_tree_model_filter_refilter(model_filter);
}

6
src/containers_view.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <gtk/gtk.h>
void containers_init(GtkBuilder* builder);
void containers_refilter();

View File

@ -1,113 +0,0 @@
#include "contents_pane.h"
#include "attributes_pane.h"
#include "entry.h"
#include "constants.h"
#include "stb_ds.h"
#include <gtk/gtk.h>
enum {
CONTENTS_COLUMN_DN,
CONTENTS_COLUMN_NAME,
CONTENTS_COLUMN_CATEGORY,
CONTENTS_COLUMN_DESCRIPTION,
CONTENTS_COLUMN_COUNT
};
GtkWidget* contents_view = NULL;
void contents_selection_changed_func(GtkTreeSelection* selection, gpointer user_data) {
GtkTreeView* view = gtk_tree_selection_get_tree_view(selection);
GtkTreeModel* model = gtk_tree_view_get_model(view);
GtkTreeIter iter;
gboolean any_selected = gtk_tree_selection_get_selected(selection, &model, &iter);
if (!any_selected) {
return;
}
// Get dn of selected iter
char* dn;
gtk_tree_model_get(model, &iter, CONTENTS_COLUMN_DN, &dn, -1);
// Update contents model
attributes_update_model(dn);
free(dn);
}
void contents_update_model(const char* new_root_dn) {
GtkTreeStore* model = gtk_tree_store_new(CONTENTS_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
entry* e = shget(entries, new_root_dn);
// Populate model
for (int i = 0; i < arrlen(e->children); i++) {
char* child_dn = e->children[i];
entry* child = shget(entries, child_dn);
GtkTreeIter this_node;
gtk_tree_store_append(model, &this_node, NULL);
// DN
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DN, child->dn, -1);
// Name
STR_ARRAY name = entry_get_attribute(child, "name");
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_NAME, name[0], -1);
// Category
STR_ARRAY category_dn = entry_get_attribute(child, "objectCategory");
if (category_dn == NULL) {
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DESCRIPTION, "none", -1);
} else {
char short_category[DN_LENGTH_MAX];
first_element_in_dn(short_category, category_dn[0], DN_LENGTH_MAX);
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_CATEGORY, short_category, -1);
}
// Description
STR_ARRAY description = entry_get_attribute(child, "description");
if (description == NULL) {
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DESCRIPTION, "none", -1);
} else {
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DESCRIPTION, description[0], -1);
}
}
gtk_tree_view_set_model(GTK_TREE_VIEW(contents_view), GTK_TREE_MODEL(model));
g_object_unref(model);
}
GtkWidget* contents_init() {
// NOTE: contents model is populated when a container in containers panel is selected
contents_view = gtk_tree_view_new();
GtkTreeViewColumn* dn_column = gtk_tree_view_column_new_with_attributes("DN", gtk_cell_renderer_text_new(), "text", CONTENTS_COLUMN_DN, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(contents_view), dn_column);
gtk_tree_view_column_set_visible(dn_column, FALSE);
GtkTreeViewColumn* name_column = gtk_tree_view_column_new_with_attributes("Name", gtk_cell_renderer_text_new(), "text", CONTENTS_COLUMN_NAME, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(contents_view), name_column);
gtk_tree_view_column_set_sizing(name_column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width(name_column, 200);
GtkTreeViewColumn* category_column = gtk_tree_view_column_new_with_attributes("Category", gtk_cell_renderer_text_new(), "text", CONTENTS_COLUMN_CATEGORY, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(contents_view), category_column);
gtk_tree_view_column_set_sizing(category_column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width(category_column, 200);
GtkTreeViewColumn* description_column = gtk_tree_view_column_new_with_attributes("Description", gtk_cell_renderer_text_new(), "text", CONTENTS_COLUMN_DESCRIPTION, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(contents_view), description_column);
gtk_tree_view_column_set_sizing(description_column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width(description_column, 300);
// Selection changed callback
GtkTreeSelection* tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(contents_view));
g_signal_connect(tree_selection, "changed", G_CALLBACK(contents_selection_changed_func), NULL);
return contents_view;
}

View File

@ -1,6 +0,0 @@
#pragma once
#include <gtk/gtk.h>
GtkWidget* contents_init();
void contents_update_model(const char* new_root);

122
src/contents_view.c Normal file
View File

@ -0,0 +1,122 @@
#include "contents_view.h"
#include "attributes_view.h"
#include "entry.h"
#include "constants.h"
#include "menu_bar.h"
#include "utils.h"
#include "stb_ds.h"
#include <gtk/gtk.h>
enum {
CONTENTS_COLUMN_DN,
CONTENTS_COLUMN_NAME,
CONTENTS_COLUMN_CATEGORY,
CONTENTS_COLUMN_DESCRIPTION,
CONTENTS_COLUMN_COUNT
};
GtkTreeView* contents_view = NULL;
void contents_refilter() {
GtkTreeModelFilter* model_filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(contents_view));
gtk_tree_model_filter_refilter(model_filter);
}
gboolean contents_filter_func(
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
// Filter out entries with "showInAdvancedViewOnly" set to TRUE
gboolean visible = TRUE;
char* dn;
gtk_tree_model_get(model, iter, CONTENTS_COLUMN_DN, &dn, -1);
if (dn != NULL) {
entry* e = shget(entries, dn);
STR_ARRAY showInAdvancedViewOnly = entry_get_attribute(e, "showInAdvancedViewOnly");
if (!advanced_view_is_on() && showInAdvancedViewOnly != NULL && streql(showInAdvancedViewOnly[0], "TRUE")) {
visible = FALSE;
}
g_free(dn);
}
return visible;
}
void contents_selection_changed_func(GtkTreeSelection* selection, gpointer user_data) {
GtkTreeView* view = gtk_tree_selection_get_tree_view(selection);
GtkTreeModel* model = gtk_tree_view_get_model(view);
GtkTreeIter iter;
gboolean any_selected = gtk_tree_selection_get_selected(selection, &model, &iter);
if (!any_selected) {
return;
}
// Get dn of selected iter
char* dn;
gtk_tree_model_get(model, &iter, CONTENTS_COLUMN_DN, &dn, -1);
// Update contents model
attributes_populate_model(dn);
free(dn);
}
// NOTE: contents model is repopulated everytime a new container is selected
void contents_populate_model(const char* new_root_dn) {
GtkTreeModelFilter* model_filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(contents_view));
GtkTreeStore* model = GTK_TREE_STORE(gtk_tree_model_filter_get_model(model_filter));
gtk_tree_store_clear(model);
entry* e = shget(entries, new_root_dn);
// Populate model
for (int i = 0; i < arrlen(e->children); i++) {
char* child_dn = e->children[i];
entry* child = shget(entries, child_dn);
GtkTreeIter this_node;
gtk_tree_store_append(model, &this_node, NULL);
// DN
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DN, child->dn, -1);
// Name
STR_ARRAY name = entry_get_attribute(child, "name");
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_NAME, name[0], -1);
// Category
STR_ARRAY category_dn = entry_get_attribute(child, "objectCategory");
if (category_dn == NULL) {
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DESCRIPTION, "none", -1);
} else {
char short_category[DN_LENGTH_MAX];
first_element_in_dn(short_category, category_dn[0], DN_LENGTH_MAX);
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_CATEGORY, short_category, -1);
}
// Description
STR_ARRAY description = entry_get_attribute(child, "description");
if (description == NULL) {
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DESCRIPTION, "none", -1);
} else {
gtk_tree_store_set(model, &this_node, CONTENTS_COLUMN_DESCRIPTION, description[0], -1);
}
}
}
void contents_init(GtkBuilder* builder) {
contents_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "contents_view"));
// Set filter func
GtkTreeModelFilter* model_filter = GTK_TREE_MODEL_FILTER((gtk_tree_view_get_model(contents_view)));
gtk_tree_model_filter_set_visible_func(model_filter, contents_filter_func, NULL, NULL);
gtk_tree_model_filter_refilter(model_filter);
}

7
src/contents_view.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <gtk/gtk.h>
void contents_init(GtkBuilder* builder);
void contents_populate_model(const char* new_root);
void contents_refilter();

View File

@ -257,20 +257,31 @@ void entry_init_fake() {
// Load entries recursively
entry_load(HEAD_DN);
// HEAD_DN= "DC=domain,DC=alt"
entry* head = make_fake_entry(HEAD_DN, NULL, true, "Person");
entry* dave = make_fake_entry("dave", head, true, "Person");
entry* daves_dog = make_fake_entry("daves_dog", dave, false, "Robot");
entry* daves_car = make_fake_entry("daves_car", dave, false, "Robot");
entry* alice = make_fake_entry("alice", head, true, "Person");
entry* alices_child = make_fake_entry("alices_child", alice, false, "Robot");
entry* alices_son = make_fake_entry("alices_son", alice, false, "Person");
entry* alices_second_son = make_fake_entry("alices_second_son", alice, false, "Person");
make_fake_entry("daves_dog", dave, false, "Robot");
make_fake_entry("daves_car", dave, false, "Robot");
entry* mark = make_fake_entry("mark", head, true, "Person");
entry* marks_son = make_fake_entry("marks_son", mark, false, "Robot");
entry* marks_daughter = make_fake_entry("marks_daughter", mark, false, "Robot");
make_fake_entry("marks_son", mark, false, "Robot");
make_fake_entry("marks_daughter", mark, false, "Robot");
entry* alice = make_fake_entry("alice", head, true, "Person");
make_fake_entry("alices_child", alice, false, "Robot");
make_fake_entry("alices_son", alice, false, "Person");
make_fake_entry("alices_second_son", alice, false, "Person");
entry* advanced_bob = make_fake_entry("advanced_bob", head, true, "Person");
make_fake_entry("advanced_bobs_son", advanced_bob, false, "Robot");
make_fake_entry("advanced_bobs_daughter", advanced_bob, false, "Robot");
add_fake_attribute(advanced_bob, "showInAdvancedViewOnly", "TRUE");
entry* advanced_klaren = make_fake_entry("advanced_klaren", head, true, "Person");
make_fake_entry("advanced_klarens_son", advanced_klaren, false, "Robot");
make_fake_entry("advanced_klarens_daughter", advanced_klaren, false, "Robot");
add_fake_attribute(advanced_klaren, "showInAdvancedViewOnly", "TRUE");
}

View File

@ -1,5 +1,8 @@
#include "mainwindow.h"
// #include "mainwindow.h"
#include "containers_view.h"
#include "contents_view.h"
#include "attributes_view.h"
#include "entry.h"
#include "active_directory.h"
@ -32,8 +35,32 @@ int main(int argc, char** argv) {
// Setup UI
gtk_init(&argc, &argv);
GtkWidget* window = mainwindow_init();
gtk_widget_show_all(window);
// Load builder
GtkBuilder *builder = gtk_builder_new_from_file("data/adtool.glade");
if (builder == NULL) {
printf("Failed to load glade file\n");
return 0;
}
containers_init(builder);
contents_init(builder);
attributes_init(builder);
gtk_builder_connect_signals(builder, NULL);
// Get window object from builder
GtkWidget* window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
if (window == NULL) {
printf("Failed to get window widget\n");
return 0;
}
gtk_widget_show(window);
g_object_unref(G_OBJECT(builder));
gtk_main();
return 0;

View File

@ -1,65 +0,0 @@
#include "mainwindow.h"
#include "menubar.h"
#include "containers_pane.h"
#include "contents_pane.h"
#include "attributes_pane.h"
#include <gtk/gtk.h>
// TODO: good behavior would be 3 panes, border adjustable between each
// none of them auto-resize, start out at reasonable widths for each column
GtkWidget* mainwindow_init() {
GtkWidget* menubar = menubar_init();
GtkWidget* containers_view = containers_init();
GtkWidget* contents_view = contents_init();
GtkWidget* attributes_view = attributes_init();
// Horizontal box containing panes
// Expand and fill each pane
GtkWidget* panes = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
{
GtkWidget* frame1 = gtk_frame_new("Containers");
GtkWidget* frame2 = gtk_frame_new("Contents");
gtk_frame_set_shadow_type(GTK_FRAME(frame1), GTK_SHADOW_IN);
gtk_frame_set_shadow_type(GTK_FRAME(frame2), GTK_SHADOW_IN);
gtk_widget_set_size_request(panes, 200, -1);
// gtk_paned_pack1(GTK_PANED(panes), frame1, true, false);
// gtk_widget_set_size_request(frame1, 50, -1);
gtk_container_add(GTK_CONTAINER(frame1), containers_view);
// gtk_paned_pack2(GTK_PANED(panes), frame2, true, FALSE);
// gtk_widget_set_size_request(frame2, 50, -1);
gtk_container_add(GTK_CONTAINER(frame2), contents_view);
gtk_paned_add1(panes, frame1);
gtk_paned_add2(panes, frame2);
gtk_paned_set_wide_handle(panes, true);
}
// int box_spacing = 0;
// GtkWidget* box_for_panes = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, box_spacing);
// gtk_box_pack_start(GTK_BOX(box_for_panes), panes, false, false, 0);
// gtk_box_pack_start(GTK_BOX(box_for_panes), attributes_view, true, true, 0);
// // Scrolled window
// GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL);
// gtk_container_add(GTK_CONTAINER(scrolled_window), box_for_panes);
// Window
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_add(GTK_CONTAINER(window), panes);
gtk_window_set_title(GTK_WINDOW(window), "Adtool");
// Set starting window size
gtk_window_set_default_size(GTK_WINDOW(window), 1700, 900);
// Set minimum window size
gtk_widget_set_size_request(window, 1500, 900);
return window;
}

View File

@ -1,5 +0,0 @@
#pragma once
#include <gtk/gtk.h>
GtkWidget* mainwindow_init();

19
src/menu_bar.c Normal file
View File

@ -0,0 +1,19 @@
#include "menu_bar.h"
#include "containers_view.h"
#include "contents_view.h"
#include <gtk/gtk.h>
bool advanced_view = false;
bool advanced_view_is_on() {
return advanced_view;
}
void advanced_view_toggled_func(GtkWidget *widget, gpointer statusbar) {
advanced_view = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
containers_refilter();
contents_refilter();
}

View File

@ -1,7 +1,5 @@
#pragma once
#include <stdbool.h>
#include <gtk/gtk.h>
GtkWidget* menubar_init();
bool advanced_view_is_on();

View File

@ -1,57 +0,0 @@
#include "menubar.h"
#include "containers_pane.h"
#include <gtk/gtk.h>
bool advanced_view = false;
bool advanced_view_is_on() {
return advanced_view;
}
void File_item_New_func(GtkMenuItem *menuitem, gpointer data) {
printf("New!\n");
}
void toggle_advanced_view_func(GtkWidget *widget, gpointer statusbar) {
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
advanced_view = true;
} else {
advanced_view = false;
}
containers_refilter_model();
}
// TODO: should do this layout in xml/glade
GtkWidget* menubar_init() {
GtkWidget* menubar = gtk_menu_bar_new();
// NOTE: this item/menu/item stuff is dumb
// Create top level "File" menu item
GtkWidget* File_item = gtk_menu_item_new_with_label("File");
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), File_item);
// Add drop-down menu to "File" item
GtkWidget* File_menu = gtk_menu_new();
gtk_menu_item_set_submenu(GTK_MENU_ITEM(File_item), File_menu);
// New item
GtkWidget* File_item_New = gtk_menu_item_new_with_label("New");
g_signal_connect(G_OBJECT(File_item_New), "activate", G_CALLBACK(File_item_New_func), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(File_menu), File_item_New);
// Advanced view toggle
// TODO: menu is closed when this is toggled, which feels weird, find a way to keep it open
GtkWidget* toggle_advanced_view = gtk_check_menu_item_new_with_label("Advanced view");
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(toggle_advanced_view), advanced_view);
g_signal_connect(G_OBJECT(toggle_advanced_view), "activate", G_CALLBACK(toggle_advanced_view_func), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(File_menu), toggle_advanced_view);
// Quit item
GtkWidget* File_item_Quit = gtk_menu_item_new_with_label("Quit");
g_signal_connect(G_OBJECT(File_item_Quit), "activate", G_CALLBACK(gtk_main_quit), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(File_menu), File_item_Quit);
return menubar;
}