anastasis-gtk_handle-policy-meta.c (10260B)
1 /* 2 This file is part of anastasis-gtk. 3 Copyright (C) 2021 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 Anastasis is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with Anastasis; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 21 /** 22 * @file src/anastasis/anastasis-gtk_handle-policy-meta.c 23 * @brief Handle right-click context menu in policy review 24 * @author Christian Grothoff 25 */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include "anastasis-gtk_action.h" 28 #include "anastasis-gtk_helper.h" 29 #include "anastasis-gtk_pe.h" 30 #include <jansson.h> 31 32 33 /** 34 * Context for menu callbacks. 35 */ 36 struct MenuContext 37 { 38 /** 39 * Reference to the row that the user right-clicked. 40 */ 41 GtkTreeRowReference *rr; 42 43 }; 44 45 46 /** 47 * The user selected the 'add policy' menu. 48 * 49 * @param menuitem the selected menu 50 * @param user_data a `struct MenuContext` 51 */ 52 static void 53 add_from_ctx_menu (GtkMenuItem *menuitem, 54 gpointer user_data) 55 { 56 (void) user_data; 57 (void) menuitem; 58 AG_add_policy (); 59 } 60 61 62 /** 63 * The user selected the 'delete challenge' menu item. 64 * 65 * @param menuitem the selected menu 66 * @param user_data a `struct MenuContext` 67 */ 68 static void 69 delete_challenge_from_ctx_menu (GtkMenuItem *menuitem, 70 gpointer user_data) 71 { 72 struct MenuContext *ctx = user_data; 73 GtkTreePath *path = gtk_tree_row_reference_get_path (ctx->rr); 74 GtkTreeModel *tm = gtk_tree_row_reference_get_model (ctx->rr); 75 GtkTreeIter iter; 76 guint pindex; 77 gboolean is_challenge; 78 guint mindex; 79 80 if (NULL == path) 81 return; 82 if (! gtk_tree_model_get_iter (tm, 83 &iter, 84 path)) 85 { 86 GNUNET_break (0); 87 return; 88 } 89 gtk_tree_path_free (path); 90 gtk_tree_model_get (tm, 91 &iter, 92 AG_PRMC_POLICY_INDEX, 93 &pindex, 94 AG_PRMC_IS_CHALLENGE, 95 &is_challenge, 96 AG_PRMC_METHOD_INDEX, 97 &mindex, 98 -1); 99 if (! is_challenge) 100 { 101 GNUNET_break (0); 102 return; 103 } 104 AG_delete_challenge (pindex, 105 mindex); 106 } 107 108 109 /** 110 * The user selected the 'delete policy' menu item. 111 * 112 * @param menuitem the selected menu 113 * @param user_data a `struct MenuContext` 114 */ 115 static void 116 delete_policy_from_ctx_menu (GtkMenuItem *menuitem, 117 gpointer user_data) 118 { 119 struct MenuContext *ctx = user_data; 120 GtkTreePath *path = gtk_tree_row_reference_get_path (ctx->rr); 121 GtkTreeModel *tm = gtk_tree_row_reference_get_model (ctx->rr); 122 GtkTreeIter iter; 123 guint pindex; 124 125 if (NULL == path) 126 return; 127 if (! gtk_tree_model_get_iter (tm, 128 &iter, 129 path)) 130 { 131 GNUNET_break (0); 132 return; 133 } 134 gtk_tree_path_free (path); 135 gtk_tree_model_get (tm, 136 &iter, 137 AG_PRMC_POLICY_INDEX, 138 &pindex, 139 -1); 140 AG_delete_policy (pindex); 141 } 142 143 144 /** 145 * The user selected the 'edit policy' menu. 146 * 147 * @param menuitem the selected menu 148 * @param user_data a `struct MenuContext` 149 */ 150 static void 151 edit_from_ctx_menu (GtkMenuItem *menuitem, 152 gpointer user_data) 153 { 154 struct MenuContext *ctx = user_data; 155 GtkTreePath *path = gtk_tree_row_reference_get_path (ctx->rr); 156 GtkTreeModel *tm = gtk_tree_row_reference_get_model (ctx->rr); 157 GtkTreeIter iter; 158 guint pindex; 159 160 if (NULL == path) 161 return; 162 if (! gtk_tree_model_get_iter (tm, 163 &iter, 164 path)) 165 { 166 GNUNET_break (0); 167 return; 168 } 169 gtk_tree_path_free (path); 170 gtk_tree_model_get (tm, 171 &iter, 172 AG_PRMC_POLICY_INDEX, 173 &pindex, 174 -1); 175 AG_edit_policy (pindex); 176 } 177 178 179 /** 180 * An item was selected from the context menu; destroy the menu shell. 181 * 182 * @param menushell menu to destroy 183 * @param user_data the 'struct MenuContext' of the menu 184 */ 185 static void 186 context_popup_selection_done (GtkMenuShell *menushell, 187 gpointer user_data) 188 { 189 struct MenuContext *ctx = user_data; 190 191 gtk_widget_destroy (GTK_WIDGET (menushell)); 192 if (NULL != ctx->rr) 193 { 194 gtk_tree_row_reference_free (ctx->rr); 195 ctx->rr = NULL; 196 } 197 GNUNET_free (ctx); 198 } 199 200 201 /** 202 * Context menu was requested for the policy. Compute which menu 203 * items are applicable and display an appropriate menu. 204 * 205 * @param tm tree model underlying the tree view where the event happened 206 * @param iter location in the tree model selected at the time 207 * @return NULL if no menu could be created, 208 * otherwise the a pop-up menu 209 */ 210 static GtkMenu * 211 get_popup (GtkTreeModel *tm, 212 GtkTreeIter *iter) 213 { 214 GtkMenu *menu; 215 struct MenuContext *ctx; 216 217 ctx = GNUNET_new (struct MenuContext); 218 menu = GTK_MENU (gtk_menu_new ()); 219 if (NULL != iter) 220 { 221 gboolean is_challenge; 222 223 { 224 GtkTreePath *path; 225 226 path = gtk_tree_model_get_path (tm, 227 iter); 228 ctx->rr = gtk_tree_row_reference_new (tm, 229 path); 230 gtk_tree_path_free (path); 231 } 232 gtk_tree_model_get (tm, 233 iter, 234 AG_PRMC_IS_CHALLENGE, 235 &is_challenge, 236 -1); 237 if (! is_challenge) 238 { 239 GtkWidget *child; 240 241 /* only show 'edit' entry for lines that 242 are for an entire policy */ 243 child = gtk_menu_item_new_with_label (_ ("_Edit policy...")); 244 g_signal_connect (child, 245 "activate", 246 G_CALLBACK (&edit_from_ctx_menu), 247 ctx); 248 gtk_label_set_use_underline (GTK_LABEL ( 249 gtk_bin_get_child (GTK_BIN (child))), 250 TRUE); 251 gtk_widget_show (child); 252 gtk_menu_shell_append (GTK_MENU_SHELL (menu), 253 child); 254 } 255 { 256 GtkWidget *child; 257 const char *label; 258 259 if (is_challenge) 260 label = _ ("Delete challenge"); 261 else 262 label = _ ("Delete policy"); 263 child = gtk_menu_item_new_with_label (label); 264 g_signal_connect (child, 265 "activate", 266 G_CALLBACK (is_challenge 267 ? &delete_challenge_from_ctx_menu 268 : &delete_policy_from_ctx_menu), 269 ctx); 270 gtk_label_set_use_underline (GTK_LABEL ( 271 gtk_bin_get_child (GTK_BIN (child))), 272 TRUE); 273 gtk_widget_show (child); 274 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child); 275 } 276 277 { 278 GtkWidget *child; 279 280 /* Insert a separator */ 281 child = gtk_separator_menu_item_new (); 282 gtk_widget_show (child); 283 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child); 284 } 285 } 286 287 { 288 GtkWidget *child; 289 290 /* only show 'edit' entry for lines that 291 are for an entire policy */ 292 child = gtk_menu_item_new_with_label (_ ("_Add policy...")); 293 g_signal_connect (child, 294 "activate", 295 G_CALLBACK (&add_from_ctx_menu), 296 ctx); 297 gtk_label_set_use_underline (GTK_LABEL ( 298 gtk_bin_get_child (GTK_BIN (child))), 299 TRUE); 300 gtk_widget_show (child); 301 gtk_menu_shell_append (GTK_MENU_SHELL (menu), 302 child); 303 } 304 305 g_signal_connect (menu, 306 "selection-done", 307 G_CALLBACK (&context_popup_selection_done), 308 ctx); 309 return menu; 310 } 311 312 313 /** 314 * We got a button-click on the policy treeview. If it was a 315 * right-click, display the context menu. 316 * 317 * @param widget the GtkTreeView with the search result list 318 * @param event the event, we only care about button events 319 * @param user_data NULL 320 * @return FALSE to propagate the event further, 321 * TRUE to stop the propagation 322 */ 323 gboolean 324 anastasis_gtk_review_policy_treeview_button_press_event_cb (GtkWidget *widget, 325 GdkEvent *event, 326 gpointer user_data) 327 { 328 GtkTreeView *tv = GTK_TREE_VIEW (widget); 329 GdkEventButton *event_button = (GdkEventButton *) event; 330 GtkTreeModel *tm; 331 GtkTreePath *path; 332 GtkTreeIter iter; 333 GtkMenu *menu; 334 335 if ((GDK_BUTTON_PRESS != event->type) || 336 (3 != event_button->button)) 337 return FALSE; /* not a right-click */ 338 if (! gtk_tree_view_get_path_at_pos (tv, 339 event_button->x, 340 event_button->y, 341 &path, 342 NULL, 343 NULL, 344 NULL)) 345 { 346 menu = get_popup (NULL, 347 NULL); 348 } 349 else 350 { 351 tm = gtk_tree_view_get_model (tv); 352 if (! gtk_tree_model_get_iter (tm, 353 &iter, 354 path)) 355 { 356 /* not sure how we got a path but no iter... */ 357 GNUNET_break (0); 358 return FALSE; 359 } 360 gtk_tree_path_free (path); 361 362 menu = get_popup (tm, 363 &iter); 364 } 365 if (NULL == menu) 366 { 367 GNUNET_break (0); 368 return FALSE; 369 } 370 gtk_menu_popup_at_pointer (menu, 371 event); 372 return FALSE; 373 }