gnome: bind to the UserActionModel

GActions call the UserActionModel and the UAM
updates the state of the GActions. This also
solves the problem of the unsyced hold action.

Refs #67159

Change-Id: I70900888deb51275decdff19607a846b191b24d1
diff --git a/src/ring_client.cpp b/src/ring_client.cpp
index 31a512a..c96de19 100644
--- a/src/ring_client.cpp
+++ b/src/ring_client.cpp
@@ -146,62 +146,11 @@
     return 0;
 }
 
-static void
-call_accept(G_GNUC_UNUSED GSimpleAction *action, G_GNUC_UNUSED GVariant *param, G_GNUC_UNUSED gpointer client)
-{
-    g_debug("call accpet action");
-
-    /* TODO: implement using UserActionModel once its fixed */
-
-    QModelIndex idx = CallModel::instance()->selectionModel()->currentIndex();
-    if (idx.isValid()) {
-        Call *call = CallModel::instance()->getCall(idx);
-        call->performAction(Call::Action::ACCEPT);
-    }
-}
-
-static void
-call_hangup(G_GNUC_UNUSED GSimpleAction *action, G_GNUC_UNUSED GVariant *param, G_GNUC_UNUSED gpointer client)
-{
-    g_debug("call hangup action");
-
-    /* TODO: implement using UserActionModel once its fixed */
-
-    QModelIndex idx = CallModel::instance()->selectionModel()->currentIndex();
-    if (idx.isValid()) {
-        Call *call = CallModel::instance()->getCall(idx);
-        call->performAction(Call::Action::REFUSE);
-    }
-}
-
-static void
-call_hold(GSimpleAction *action, GVariant *state, G_GNUC_UNUSED gpointer data)
-{
-    g_debug("call hold action");
-
-    /* TODO: implement using UserActionModel once its fixed */
-
-    /* get the requested state and apply it */
-    gboolean requested = g_variant_get_boolean(state);
-    g_simple_action_set_state(action, g_variant_new_boolean(requested));
-
-    QModelIndex idx = CallModel::instance()->selectionModel()->currentIndex();
-    if (idx.isValid()) {
-        Call *call = CallModel::instance()->getCall(idx);
-        call->performAction(Call::Action::HOLD);
-    }
-}
-
-/* starting glib 2.40 the action() parameter in the action entry (the second one)
- * can be left NULL for stateful boolean actions and they will automatically be
- * toggled; for older versions of glib we must explicitly set a handler to toggle them */
-#if GLIB_CHECK_VERSION(2,40,0)
-
 static const GActionEntry ring_actions[] =
 {
-    { "accept",     call_accept, NULL, NULL,    NULL, {0} },
-    { "hangup",     call_hangup, NULL, NULL,    NULL, {0} },
-    { "hold",       NULL,        NULL, "false", call_hold, {0} },
+    { "accept",     NULL, NULL, NULL,    NULL, {0} },
+    { "hangup",     NULL, NULL, NULL,    NULL, {0} },
+    { "hold",       NULL, NULL, "false", NULL, {0} },
     /* TODO implement the other actions */
     // { "mute_audio", NULL,        NULL, "false", NULL, {0} },
     // { "mute_video", NULL,        NULL, "false", NULL, {0} },
@@ -209,76 +158,7 @@
     // { "record",     NULL,        NULL, "false", NULL, {0} }
 };
 
-#else
-
-/* adapted from glib 2.40, gsimpleaction.c */
-static void
-g_simple_action_change_state(GSimpleAction *simple, GVariant *value)
-{
-    GAction *action = G_ACTION(simple);
-
-    guint change_state_id = g_signal_lookup("change-state", G_OBJECT_TYPE(simple));
-
-    /* If the user connected a signal handler then they are responsible
-    * for handling state changes.
-    */
-    if (g_signal_has_handler_pending(action, change_state_id, 0, TRUE))
-        g_signal_emit(action, change_state_id, 0, value);
-
-    /* If not, then the default behaviour is to just set the state. */
-    else
-        g_simple_action_set_state(simple, value);
-}
-
-/* define activate handler for simple toggle actions for glib < 2.40
- * adapted from glib 2.40, gsimpleaction.c */
-static void
-g_simple_action_toggle(GSimpleAction *action, GVariant *parameter, G_GNUC_UNUSED gpointer user_data)
-{
-    const GVariantType *parameter_type = g_action_get_parameter_type(G_ACTION(action));
-    g_return_if_fail(parameter_type == NULL ?
-                    parameter == NULL :
-                    (parameter != NULL &&
-                    g_variant_is_of_type(parameter, parameter_type)));
-
-    if (parameter != NULL)
-        g_variant_ref_sink(parameter);
-
-    if (g_action_get_enabled(G_ACTION(action))) {
-        /* make sure it is a stateful action and toggle it */
-        GVariant *state = g_action_get_state(G_ACTION(action));
-        if (state) {
-            /* If we have no parameter and this is a boolean action, toggle. */
-            if (parameter == NULL && g_variant_is_of_type(state, G_VARIANT_TYPE_BOOLEAN)) {
-                gboolean was_enabled = g_variant_get_boolean(state);
-                g_simple_action_change_state(action, g_variant_new_boolean(!was_enabled));
-            }
-            /* else, if the parameter and state type are the same, do a change-state */
-            else if (g_variant_is_of_type (state, g_variant_get_type(parameter)))
-                g_simple_action_change_state(action, parameter);
-        }
-        g_variant_unref(state);
-    }
-
-    if (parameter != NULL)
-        g_variant_unref (parameter);
-}
-
-static const GActionEntry ring_actions[] =
-{
-    { "accept",     call_accept,            NULL, NULL,    NULL, {0} },
-    { "hangup",     call_hangup,            NULL, NULL,    NULL, {0} },
-    { "hold",       g_simple_action_toggle, NULL, "false", call_hold, {0} },
-    /* TODO implement the other actions */
-    // { "mute_audio", NULL,        NULL, "false", NULL, {0} },
-    // { "mute_video", NULL,        NULL, "false", NULL, {0} },
-    // { "transfer",   NULL,        NULL, "flase", NULL, {0} },
-    // { "record",     NULL,        NULL, "false", NULL, {0} }
-};
-
-#endif
-
-/* TODO: uncomment when UserActionModel is fixed and used
+/* this union is used to pass the int refering to the Action as a parameter to the GAction callback */
 typedef union _int_ptr_t
 {
     int value;
@@ -297,7 +177,6 @@
 
     uam << a;
 }
-*/
 
 static void
 ring_client_startup(GApplication *app)
@@ -309,43 +188,39 @@
     g_action_map_add_action_entries(
         G_ACTION_MAP(app), ring_actions, G_N_ELEMENTS(ring_actions), client);
 
-    /* TODO: Bind actions to the useractionmodel once it is working */
-    // UserActionModel* uam = CallModel::instance()->userActionModel();
-    // QHash<int, GSimpleAction*> actionHash;
-    // actionHash[ (int)UserActionModel::Action::ACCEPT          ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "accept"));
-    // actionHash[ (int)UserActionModel::Action::HOLD            ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "hold"));
-    // // actionHash[ (int)UserActionModel::Action::MUTE_AUDIO      ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "mute_audio"));
-    // // actionHash[ (int)UserActionModel::Action::SERVER_TRANSFER ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "transfer"));
-    // // actionHash[ (int)UserActionModel::Action::RECORD          ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "record"));
-    // actionHash[ (int)UserActionModel::Action::HANGUP          ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "hangup"));
+    /* Bind GActions to the UserActionModel */
+    UserActionModel* uam = CallModel::instance()->userActionModel();
+    QHash<int, GSimpleAction*> actionHash;
+    actionHash[ (int)UserActionModel::Action::ACCEPT          ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "accept"));
+    actionHash[ (int)UserActionModel::Action::HOLD            ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "hold"));
+    /* TODO: add commented actions when ready */
+    // actionHash[ (int)UserActionModel::Action::MUTE_AUDIO      ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "mute_audio"));
+    // actionHash[ (int)UserActionModel::Action::SERVER_TRANSFER ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "transfer"));
+    // actionHash[ (int)UserActionModel::Action::RECORD          ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "record"));
+    actionHash[ (int)UserActionModel::Action::HANGUP          ] = G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "hangup"));
 
-    // for (QHash<int,GSimpleAction*>::const_iterator i = actionHash.begin(); i != actionHash.end(); ++i) {
-    //    GSimpleAction* sa = i.value();
-    //    // UserActionModel::Action a = static_cast<UserActionModel::Action>(i.key());
-    //    // connect(ea, &QAction::triggered, [uam,a](bool) {uam << a;});
-    //    int_ptr_t user_data;
-    //    user_data.value = i.key();
-    //    g_signal_connect(G_OBJECT(sa), "activate", G_CALLBACK(activate_action), user_data.ptr);
+    for (QHash<int,GSimpleAction*>::const_iterator i = actionHash.begin(); i != actionHash.end(); ++i) {
+       GSimpleAction* sa = i.value();
+       int_ptr_t user_data;
+       user_data.value = i.key();
+       g_signal_connect(G_OBJECT(sa), "activate", G_CALLBACK(activate_action), user_data.ptr);
+    }
 
-    // }
-
-    // QObject::connect(uam,&UserActionModel::dataChanged, [actionHash,uam](const QModelIndex& tl, const QModelIndex& br) {
-    //    const int first(tl.row()),last(br.row());
-    //    for(int i = first; i <= last;i++) {
-    //       const QModelIndex& idx = uam->index(i,0);
-    //       GSimpleAction* sa = actionHash[(int)qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION))];
-    //       if (sa) {
-    //          // a->setText   ( idx.data(Qt::DisplayRole).toString()                 );
-    //          // a->setEnabled( idx.flags() & Qt::ItemIsEnabled                      );
-    //          g_simple_action_set_enabled(sa, idx.flags() & Qt::ItemIsEnabled);
-    //          // a->setChecked( idx.data(Qt::CheckStateRole) == Qt::Checked          );
-    //          /* check if statefull action */
-    //          if (g_action_get_state_type(G_ACTION(sa)) != NULL)
-    //             g_simple_action_set_state(sa, g_variant_new_boolean(idx.data(Qt::CheckStateRole) == Qt::Checked));
-    //          // a->setAltIcon( qvariant_cast<QPixmap>(idx.data(Qt::DecorationRole)) );
-    //       }
-    //    }
-    // });
+    /* change the state of the GActions based on the UserActionModel */
+    QObject::connect(uam,&UserActionModel::dataChanged, [actionHash,uam](const QModelIndex& tl, const QModelIndex& br) {
+       const int first(tl.row()),last(br.row());
+       for(int i = first; i <= last;i++) {
+          const QModelIndex& idx = uam->index(i,0);
+          GSimpleAction* sa = actionHash[(int)qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION))];
+          if (sa) {
+            /* enable/disable GAction based on UserActionModel */
+            g_simple_action_set_enabled(sa, idx.flags() & Qt::ItemIsEnabled);
+            /* set the state of the action if its stateful */
+            if (g_action_get_state_type(G_ACTION(sa)) != NULL)
+                g_simple_action_set_state(sa, g_variant_new_boolean(idx.data(Qt::CheckStateRole) == Qt::Checked));
+          }
+       }
+    });
 }
 
 static void