36 |
#endif |
#endif |
37 |
|
|
38 |
|
|
|
/* ------------------------- some generic treeview helpers -----------------------*/ |
|
|
|
|
|
|
|
|
static void |
|
|
list_pre_inplace_edit_tweak (GtkTreeModel *model) |
|
|
{ |
|
|
// Remove any current sort ordering, leaving items where they are. |
|
|
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), |
|
|
GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, |
|
|
GTK_SORT_ASCENDING); |
|
|
} |
|
|
|
|
|
|
|
|
/* Refocus a GtkTreeView an item specified by iter, unselecting the current |
|
|
selection and optionally highlighting the new one. Typically called after |
|
|
making an edit to an item with a covering sub-dialog. */ |
|
|
|
|
|
static void |
|
|
list_focus_on (GtkTreeView *view, GtkTreeModel *model, |
|
|
GtkTreeIter *iter, gboolean highlight) |
|
|
{ |
|
|
// Handle de/reselection |
|
|
GtkTreeSelection *sel = gtk_tree_view_get_selection(view); |
|
|
gtk_tree_selection_unselect_all(sel); |
|
|
|
|
|
// Scroll to it, since it might now be out of view. |
|
|
GtkTreePath *path = gtk_tree_model_get_path(model, iter); |
|
|
gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0); |
|
|
gtk_tree_path_free(path); |
|
|
|
|
|
// reselect |
|
|
if (highlight) |
|
|
gtk_tree_selection_select_iter(sel, iter); |
|
|
} |
|
|
|
|
|
|
|
39 |
/* --------------- relation dialog for an item (node or way) ----------- */ |
/* --------------- relation dialog for an item (node or way) ----------- */ |
40 |
|
|
41 |
typedef struct { |
typedef struct { |
42 |
relation_item_t *item; |
relation_item_t *item; |
43 |
appdata_t *appdata; |
appdata_t *appdata; |
44 |
GtkWidget *dialog, *view; |
GtkWidget *dialog, *list; |
45 |
GtkListStore *store; |
GtkListStore *store; |
|
GtkWidget *but_add, *but_edit, *but_remove; |
|
46 |
} relitem_context_t; |
} relitem_context_t; |
47 |
|
|
48 |
enum { |
enum { |
211 |
static void relation_item_list_selected(relitem_context_t *context, |
static void relation_item_list_selected(relitem_context_t *context, |
212 |
gboolean selected) { |
gboolean selected) { |
213 |
|
|
214 |
if(context->but_remove) |
list_button_enable(context->list, LIST_BUTTON_REMOVE, selected); |
215 |
gtk_widget_set_sensitive(context->but_remove, selected); |
list_button_enable(context->list, LIST_BUTTON_EDIT, selected); |
|
if(context->but_edit) |
|
|
gtk_widget_set_sensitive(context->but_edit, selected); |
|
|
} |
|
|
|
|
|
static gboolean |
|
|
relation_item_list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, |
|
|
GtkTreePath *path, gboolean path_currently_selected, |
|
|
gpointer userdata) { |
|
|
relitem_context_t *context = (relitem_context_t*)userdata; |
|
|
GtkTreeIter iter; |
|
|
|
|
|
if(gtk_tree_model_get_iter(model, &iter, path)) { |
|
|
g_assert(gtk_tree_path_get_depth(path) == 1); |
|
|
relation_item_list_selected(context, TRUE); |
|
|
} |
|
|
|
|
|
return TRUE; /* allow selection state to change */ |
|
216 |
} |
} |
217 |
|
|
218 |
/* try to find something descriptive */ |
/* try to find something descriptive */ |
252 |
RELITEM_COL_DATA, relation, |
RELITEM_COL_DATA, relation, |
253 |
-1); |
-1); |
254 |
|
|
255 |
gtk_tree_selection_select_iter(gtk_tree_view_get_selection( |
gtk_tree_selection_select_iter(list_get_selection(context->list), &iter); |
|
GTK_TREE_VIEW(context->view)), &iter); |
|
256 |
|
|
257 |
/* scroll to end */ |
/* scroll to end */ |
258 |
// GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(); |
// GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(); |
265 |
GtkTreeModel *model; |
GtkTreeModel *model; |
266 |
GtkTreeIter iter; |
GtkTreeIter iter; |
267 |
|
|
268 |
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)); |
selection = list_get_selection(context->list); |
269 |
if(gtk_tree_selection_get_selected(selection, &model, &iter)) { |
if(gtk_tree_selection_get_selected(selection, &model, &iter)) { |
270 |
relation_t *relation; |
relation_t *relation; |
271 |
gtk_tree_model_get(model, &iter, RELITEM_COL_DATA, &relation, -1); |
gtk_tree_model_get(model, &iter, RELITEM_COL_DATA, &relation, -1); |
306 |
-1); |
-1); |
307 |
|
|
308 |
// Order will probably have changed, so refocus |
// Order will probably have changed, so refocus |
309 |
list_focus_on(GTK_TREE_VIEW(context->view), GTK_TREE_MODEL(context->store), |
list_focus_on(context->list, &iter, TRUE); |
|
&iter, TRUE); |
|
310 |
} |
} |
311 |
|
|
312 |
/* remove the selected relation */ |
/* remove the selected relation */ |
327 |
|
|
328 |
/* first remove selected row from list */ |
/* first remove selected row from list */ |
329 |
GtkTreeIter iter; |
GtkTreeIter iter; |
330 |
GtkTreeSelection *selection = |
GtkTreeSelection *selection = list_get_selection(context->list); |
|
gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)); |
|
331 |
if(gtk_tree_selection_get_selected(selection, NULL, &iter)) |
if(gtk_tree_selection_get_selected(selection, NULL, &iter)) |
332 |
gtk_list_store_remove(context->store, &iter); |
gtk_list_store_remove(context->store, &iter); |
333 |
|
|
423 |
} |
} |
424 |
|
|
425 |
static GtkWidget *relation_item_list_widget(relitem_context_t *context) { |
static GtkWidget *relation_item_list_widget(relitem_context_t *context) { |
426 |
GtkWidget *vbox = gtk_vbox_new(FALSE,3); |
context->list = list_new(LIST_HILDON_WITH_HEADERS); |
|
context->view = gtk_tree_view_new(); |
|
|
|
|
|
gtk_tree_selection_set_select_function( |
|
|
gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)), |
|
|
relation_item_list_selection_func, |
|
|
context, NULL); |
|
|
|
|
|
|
|
|
/* --- "selected" column --- */ |
|
|
GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new(); |
|
|
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( |
|
|
_(""), renderer, "active", RELITEM_COL_SELECTED, NULL); |
|
|
g_signal_connect(renderer, "toggled", G_CALLBACK(relitem_toggled), context); |
|
|
gtk_tree_view_column_set_sort_column_id(column, RELITEM_COL_SELECTED); |
|
|
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
|
|
|
|
|
/* --- "Type" column --- */ |
|
|
renderer = gtk_cell_renderer_text_new(); |
|
|
column = gtk_tree_view_column_new_with_attributes(_("Type"), renderer, |
|
|
"text", RELITEM_COL_TYPE, NULL); |
|
|
gtk_tree_view_column_set_sort_column_id(column, RELITEM_COL_TYPE); |
|
|
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
|
|
|
|
|
/* --- "Role" column --- */ |
|
|
renderer = gtk_cell_renderer_text_new(); |
|
|
column = gtk_tree_view_column_new_with_attributes(_("Role"), renderer, |
|
|
"text", RELITEM_COL_ROLE, NULL); |
|
|
gtk_tree_view_column_set_sort_column_id(column, RELITEM_COL_ROLE); |
|
|
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
|
|
|
|
|
/* --- "Name" column --- */ |
|
|
renderer = gtk_cell_renderer_text_new(); |
|
|
g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
|
|
column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, |
|
|
"text", RELITEM_COL_NAME, NULL); |
|
|
gtk_tree_view_column_set_expand(column, TRUE); |
|
|
gtk_tree_view_column_set_sort_column_id(column, RELITEM_COL_NAME); |
|
|
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
|
427 |
|
|
428 |
|
list_set_columns(context->list, |
429 |
|
_(""), RELITEM_COL_SELECTED, LIST_FLAG_TOGGLE, |
430 |
|
G_CALLBACK(relitem_toggled), context, |
431 |
|
_("Type"), RELITEM_COL_TYPE, 0, |
432 |
|
_("Role"), RELITEM_COL_ROLE, 0, |
433 |
|
_("Name"), RELITEM_COL_NAME, LIST_FLAG_ELLIPSIZE, |
434 |
|
NULL); |
435 |
|
|
436 |
/* build and fill the store */ |
/* build and fill the store */ |
437 |
context->store = gtk_list_store_new(RELITEM_NUM_COLS, |
context->store = gtk_list_store_new(RELITEM_NUM_COLS, |
438 |
G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, |
G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, |
439 |
G_TYPE_STRING, G_TYPE_POINTER); |
G_TYPE_STRING, G_TYPE_POINTER); |
440 |
|
|
441 |
gtk_tree_view_set_model(GTK_TREE_VIEW(context->view), |
list_set_store(context->list, context->store); |
|
GTK_TREE_MODEL(context->store)); |
|
442 |
|
|
443 |
// Debatable whether to sort by the "selected" or the "Name" column by |
// Debatable whether to sort by the "selected" or the "Name" column by |
444 |
// default. Both are be useful, in different ways. |
// default. Both are be useful, in different ways. |
466 |
|
|
467 |
g_object_unref(context->store); |
g_object_unref(context->store); |
468 |
|
|
469 |
/* put it into a scrolled window */ |
list_set_static_buttons(context->list, G_CALLBACK(on_relation_item_add), |
470 |
GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL); |
G_CALLBACK(on_relation_item_edit),G_CALLBACK(on_relation_item_remove), context); |
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), |
|
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); |
|
|
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), |
|
|
GTK_SHADOW_ETCHED_IN); |
|
|
gtk_container_add(GTK_CONTAINER(scrolled_window), context->view); |
|
|
|
|
|
gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window); |
|
|
|
|
|
/* ------- button box ------------ */ |
|
|
|
|
|
GtkWidget *hbox = gtk_hbox_new(TRUE,3); |
|
|
|
|
|
context->but_add = gtk_button_new_with_label(_("Add...")); |
|
|
// gtk_widget_set_sensitive(context->but_add, FALSE); |
|
|
gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_add); |
|
|
gtk_signal_connect(GTK_OBJECT(context->but_add), "clicked", |
|
|
GTK_SIGNAL_FUNC(on_relation_item_add), context); |
|
|
|
|
|
context->but_edit = gtk_button_new_with_label(_("Edit...")); |
|
|
gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_edit); |
|
|
gtk_signal_connect(GTK_OBJECT(context->but_edit), "clicked", |
|
|
GTK_SIGNAL_FUNC(on_relation_item_edit), context); |
|
|
|
|
|
context->but_remove = gtk_button_new_with_label(_("Remove")); |
|
|
gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_remove); |
|
|
gtk_signal_connect(GTK_OBJECT(context->but_remove), "clicked", |
|
|
GTK_SIGNAL_FUNC(on_relation_item_remove), context); |
|
471 |
|
|
472 |
relation_item_list_selected(context, FALSE); |
relation_item_list_selected(context, FALSE); |
473 |
|
|
474 |
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
return context->list; |
|
return vbox; |
|
475 |
} |
} |
476 |
|
|
477 |
void relation_add_dialog(appdata_t *appdata, relation_item_t *relitem) { |
void relation_add_dialog(appdata_t *appdata, relation_item_t *relitem) { |
523 |
|
|
524 |
typedef struct { |
typedef struct { |
525 |
appdata_t *appdata; |
appdata_t *appdata; |
526 |
GtkWidget *dialog, *view; |
GtkWidget *dialog, *list; |
|
GtkWidget *but_members, *but_add, *but_edit, *but_remove; |
|
527 |
GtkListStore *store; |
GtkListStore *store; |
528 |
} relation_context_t; |
} relation_context_t; |
529 |
|
|
541 |
GtkTreeModel *model; |
GtkTreeModel *model; |
542 |
GtkTreeIter iter; |
GtkTreeIter iter; |
543 |
|
|
544 |
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)); |
selection = list_get_selection(context->list); |
545 |
if(gtk_tree_selection_get_selected(selection, &model, &iter)) { |
if(gtk_tree_selection_get_selected(selection, &model, &iter)) { |
546 |
relation_t *relation; |
relation_t *relation; |
547 |
gtk_tree_model_get(model, &iter, RELATION_COL_DATA, &relation, -1); |
gtk_tree_model_get(model, &iter, RELATION_COL_DATA, &relation, -1); |
553 |
static void relation_list_selected(relation_context_t *context, |
static void relation_list_selected(relation_context_t *context, |
554 |
relation_t *selected) { |
relation_t *selected) { |
555 |
|
|
556 |
if(context->but_members) |
list_button_enable(context->list, LIST_BUTTON_USER0, |
557 |
gtk_widget_set_sensitive(context->but_members, |
(selected != NULL) && (selected->member != NULL)); |
558 |
(selected != NULL) && (selected->member != NULL)); |
|
559 |
|
list_button_enable(context->list, LIST_BUTTON_REMOVE, selected != NULL); |
560 |
if(context->but_remove) |
list_button_enable(context->list, LIST_BUTTON_EDIT, selected != NULL); |
|
gtk_widget_set_sensitive(context->but_remove, selected != NULL); |
|
|
if(context->but_edit) |
|
|
gtk_widget_set_sensitive(context->but_edit, selected != NULL); |
|
561 |
} |
} |
562 |
|
|
563 |
static gboolean |
static gboolean |
774 |
RELATION_COL_DATA, relation, |
RELATION_COL_DATA, relation, |
775 |
-1); |
-1); |
776 |
|
|
777 |
gtk_tree_selection_select_iter(gtk_tree_view_get_selection( |
gtk_tree_selection_select_iter(list_get_selection(context->list), &iter); |
|
GTK_TREE_VIEW(context->view)), &iter); |
|
778 |
|
|
779 |
/* scroll to end */ |
/* scroll to end */ |
780 |
// GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(); |
// GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(); |
817 |
-1); |
-1); |
818 |
|
|
819 |
// Order will probably have changed, so refocus |
// Order will probably have changed, so refocus |
820 |
list_focus_on(GTK_TREE_VIEW(context->view), GTK_TREE_MODEL(context->store), |
list_focus_on(context->list, &iter, TRUE); |
|
&iter, TRUE); |
|
821 |
} |
} |
822 |
|
|
823 |
|
|
839 |
|
|
840 |
/* first remove selected row from list */ |
/* first remove selected row from list */ |
841 |
GtkTreeIter iter; |
GtkTreeIter iter; |
842 |
GtkTreeSelection *selection = |
GtkTreeSelection *selection = list_get_selection(context->list); |
|
gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)); |
|
843 |
if(gtk_tree_selection_get_selected(selection, NULL, &iter)) |
if(gtk_tree_selection_get_selected(selection, NULL, &iter)) |
844 |
gtk_list_store_remove(context->store, &iter); |
gtk_list_store_remove(context->store, &iter); |
845 |
|
|
850 |
} |
} |
851 |
|
|
852 |
static GtkWidget *relation_list_widget(relation_context_t *context) { |
static GtkWidget *relation_list_widget(relation_context_t *context) { |
853 |
GtkWidget *vbox = gtk_vbox_new(FALSE,3); |
context->list = list_new(LIST_HILDON_WITH_HEADERS); |
|
context->view = gtk_tree_view_new(); |
|
|
|
|
|
gtk_tree_selection_set_select_function( |
|
|
gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)), |
|
|
relation_list_selection_func, |
|
|
context, NULL); |
|
|
|
|
|
/* --- "id" column --- */ |
|
|
GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
|
|
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( |
|
|
_("Id"), renderer, "text", RELATION_COL_ID, NULL); |
|
|
gtk_tree_view_column_set_sort_column_id(column, RELATION_COL_ID); |
|
|
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
|
|
|
|
|
/* --- "Type" column --- */ |
|
|
renderer = gtk_cell_renderer_text_new(); |
|
|
column = gtk_tree_view_column_new_with_attributes(_("Type"), renderer, |
|
|
"text", RELATION_COL_TYPE, NULL); |
|
|
gtk_tree_view_column_set_sort_column_id(column, RELATION_COL_TYPE); |
|
|
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
|
854 |
|
|
855 |
/* --- "Name" column --- */ |
list_set_selection_function(context->list, relation_list_selection_func, context); |
|
renderer = gtk_cell_renderer_text_new(); |
|
|
g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
|
|
column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, |
|
|
"text", RELATION_COL_NAME, NULL); |
|
|
gtk_tree_view_column_set_expand(column, TRUE); |
|
|
gtk_tree_view_column_set_sort_column_id(column, RELATION_COL_NAME); |
|
|
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
|
856 |
|
|
857 |
/* --- "members" column --- */ |
list_set_columns(context->list, |
858 |
renderer = gtk_cell_renderer_text_new(); |
_("Id"), RELATION_COL_ID, 0, |
859 |
column = gtk_tree_view_column_new_with_attributes(_("Members"), renderer, |
_("Type"), RELATION_COL_TYPE, 0, |
860 |
"text", RELATION_COL_MEMBERS, NULL); |
_("Name"), RELATION_COL_NAME, LIST_FLAG_ELLIPSIZE, |
861 |
gtk_tree_view_column_set_sort_column_id(column, RELATION_COL_MEMBERS); |
_("Members"), RELATION_COL_MEMBERS, 0, |
862 |
gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
NULL); |
863 |
|
|
864 |
/* build and fill the store */ |
/* build and fill the store */ |
865 |
context->store = gtk_list_store_new(RELATION_NUM_COLS, |
context->store = gtk_list_store_new(RELATION_NUM_COLS, |
866 |
G_TYPE_ITEM_ID_T, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, |
G_TYPE_ITEM_ID_T, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, |
867 |
G_TYPE_POINTER); |
G_TYPE_POINTER); |
868 |
|
|
869 |
gtk_tree_view_set_model(GTK_TREE_VIEW(context->view), |
list_set_store(context->list, context->store); |
|
GTK_TREE_MODEL(context->store)); |
|
870 |
|
|
871 |
// Sorting by ref/name by default is useful for places with lots of numbered |
// Sorting by ref/name by default is useful for places with lots of numbered |
872 |
// bus routes. Especially for small screens. |
// bus routes. Especially for small screens. |
896 |
|
|
897 |
g_object_unref(context->store); |
g_object_unref(context->store); |
898 |
|
|
899 |
/* put it into a scrolled window */ |
list_set_static_buttons(context->list, G_CALLBACK(on_relation_add), |
900 |
GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL); |
G_CALLBACK(on_relation_edit), G_CALLBACK(on_relation_remove), context); |
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), |
|
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); |
|
|
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), |
|
|
GTK_SHADOW_ETCHED_IN); |
|
|
gtk_container_add(GTK_CONTAINER(scrolled_window), context->view); |
|
|
|
|
|
gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window); |
|
|
|
|
|
/* ------- button box ------------ */ |
|
901 |
|
|
902 |
GtkWidget *hbox = gtk_hbox_new(TRUE,3); |
list_set_user_buttons(context->list, |
903 |
|
LIST_BUTTON_USER0, _("Members..."), G_CALLBACK(on_relation_members), |
904 |
context->but_add = gtk_button_new_with_label(_("Add...")); |
0); |
|
gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_add); |
|
|
gtk_signal_connect(GTK_OBJECT(context->but_add), "clicked", |
|
|
GTK_SIGNAL_FUNC(on_relation_add), context); |
|
|
|
|
|
context->but_edit = gtk_button_new_with_label(_("Edit...")); |
|
|
gtk_widget_set_sensitive(context->but_edit, FALSE); |
|
|
gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_edit); |
|
|
gtk_signal_connect(GTK_OBJECT(context->but_edit), "clicked", |
|
|
GTK_SIGNAL_FUNC(on_relation_edit), context); |
|
|
|
|
|
context->but_members = gtk_button_new_with_label(_("Members...")); |
|
|
gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_members); |
|
|
gtk_signal_connect(GTK_OBJECT(context->but_members), "clicked", |
|
|
GTK_SIGNAL_FUNC(on_relation_members), context); |
|
|
|
|
|
context->but_remove = gtk_button_new_with_label(_("Remove")); |
|
|
gtk_widget_set_sensitive(context->but_remove, FALSE); |
|
|
gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_remove); |
|
|
gtk_signal_connect(GTK_OBJECT(context->but_remove), "clicked", |
|
|
GTK_SIGNAL_FUNC(on_relation_remove), context); |
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
|
905 |
|
|
906 |
relation_list_selected(context, NULL); |
relation_list_selected(context, NULL); |
907 |
|
|
908 |
return vbox; |
return context->list; |
909 |
} |
} |
910 |
|
|
911 |
/* a global view on all relations */ |
/* a global view on all relations */ |