93
/* Returns TRUE if row contains a conference object pointer */
95
is_conference(GtkTreeModel *model, GtkTreeIter *iter)
97
gboolean result = FALSE;
98
gtk_tree_model_get(model, iter, COLUMN_IS_CONFERENCE, &result, -1);
103
102
/* Call back when the user click on a call in the list */
105
104
call_selected_cb(GtkTreeSelection *sel, void* data UNUSED)
107
DEBUG("CallTree: Selection callback");
108
GtkTreeModel *model = GTK_TREE_MODEL(active_calltree_tab->store);
106
GtkTreeModel *model = gtk_tree_view_get_model(gtk_tree_selection_get_tree_view(sel));
110
108
GtkTreeIter iter;
112
109
if (!gtk_tree_selection_get_selected(sel, &model, &iter))
115
112
if (active_calltree_tab == history_tab)
116
DEBUG("CallTree: Current call tree is history");
113
DEBUG("Current call tree is history");
117
114
else if (active_calltree_tab == current_calls_tab)
118
DEBUG("CallTree: Current call tree is current calls");
120
// store info for dragndrop
121
GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
122
gchar *string_path = gtk_tree_path_to_string(path);
123
calltree_selected_path_depth = gtk_tree_path_get_depth(path);
125
if (gtk_tree_model_iter_has_child(model, &iter)) {
126
DEBUG("CallTree: Selected a conference");
127
calltree_selected_type = A_CONFERENCE;
131
gtk_tree_model_get_value(model, &iter, COLUMN_ACCOUNT_PTR, &val);
133
calltree_selected_conf = (conference_obj_t*) g_value_get_pointer(&val);
136
if (calltree_selected_conf) {
115
DEBUG("Current call tree is current calls");
117
/* Get ID of selected object, may be a call or a conference */
119
gtk_tree_model_get(model, &iter, COLUMN_ID, &id, -1);
121
if (is_conference(model, &iter)) {
122
DEBUG("Selected a conference");
124
conference_obj_t *calltree_selected_conf = conferencelist_get(active_calltree_tab, id);
127
if (calltree_selected_conf)
137
128
calltab_select_conf(active_calltree_tab, calltree_selected_conf);
138
calltree_selected_call_id = calltree_selected_conf->_confID;
139
calltree_selected_path = string_path;
140
calltree_selected_call = NULL;
142
if (calltree_selected_conf->_im_widget)
143
im_window_show_tab(calltree_selected_conf->_im_widget);
145
DEBUG("CallTree: selected_path %s, selected_conf_id %s, selected_path_depth %d",
146
calltree_selected_path, calltree_selected_call_id, calltree_selected_path_depth);
149
DEBUG("CallTree: Selected a call");
150
calltree_selected_type = A_CALL;
154
gtk_tree_model_get_value(model, &iter, COLUMN_ACCOUNT_PTR, &val);
156
calltree_selected_call = g_value_get_pointer(&val);
159
if (calltree_selected_call) {
160
calltab_select_call(active_calltree_tab, calltree_selected_call);
161
calltree_selected_call_id = calltree_selected_call->_callID;
162
calltree_selected_path = string_path;
163
calltree_selected_conf = NULL;
165
if (calltree_selected_call->_im_widget)
166
im_window_show_tab(calltree_selected_call->_im_widget);
168
DEBUG("CallTree: selected_path %s, selected_call_id %s, selected_path_depth %d",
169
calltree_selected_path, calltree_selected_call_id, calltree_selected_path_depth);
130
DEBUG("Selected a call");
132
callable_obj_t *selected_call = calllist_get_call(active_calltree_tab, id);
136
calltab_select_call(active_calltree_tab, selected_call);
173
139
update_actions();
176
142
/* A row is activated when it is double clicked */
178
row_activated(GtkTreeView *tree_view UNUSED,
179
GtkTreePath *path UNUSED,
180
GtkTreeViewColumn *column UNUSED,
144
row_activated_cb(GtkTreeView *tree_view UNUSED,
145
GtkTreePath *path UNUSED,
146
GtkTreeViewColumn *column UNUSED,
183
DEBUG("CallTree: Double click action");
185
149
if (calltab_get_selected_type(active_calltree_tab) == A_CALL) {
186
DEBUG("CallTree: Selected a call");
150
DEBUG("Selected a call");
187
151
callable_obj_t *selectedCall = calltab_get_selected_call(active_calltree_tab);
189
153
if (selectedCall) {
586
calltree_update_call_recursive(calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent)
531
callable_obj_t *call;
536
const conference_obj_t *conf;
537
} ConferenceRemoveCtx;
540
update_call(GtkTreeModel *model, GtkTreePath *path UNUSED, GtkTreeIter *iter, gpointer data)
588
542
GdkPixbuf *pixbuf = NULL;
589
543
GdkPixbuf *pixbuf_security = NULL;
544
CallUpdateCtx *ctx = (CallUpdateCtx*) data;
545
calltab_t *tab = ctx->tab;
546
callable_obj_t *call = ctx->call;
592
547
GtkTreeStore* store = tab->store;
594
549
gchar* srtp_enabled = NULL;
595
550
gboolean display_sas = TRUE;
596
account_t* account_details=NULL;
598
int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), parent);
601
account_details = account_list_get_by_id(c->_accountID);
603
if (account_details != NULL) {
604
srtp_enabled = g_hash_table_lookup(account_details->properties, ACCOUNT_SRTP_ENABLED);
606
if (g_strcasecmp(g_hash_table_lookup(account_details->properties, ACCOUNT_ZRTP_DISPLAY_SAS),"false") == 0)
609
GHashTable * properties = sflphone_get_ip2ip_properties();
611
if (properties != NULL) {
612
srtp_enabled = g_hash_table_lookup(properties, ACCOUNT_SRTP_ENABLED);
614
if (g_strcasecmp(g_hash_table_lookup(properties, ACCOUNT_ZRTP_DISPLAY_SAS),"false") == 0)
620
for (gint i = 0; i < nbChild; i++) {
622
if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, parent, i)) {
624
if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter))
625
calltree_update_call_recursive(tab, c, &iter);
628
gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, COLUMN_ACCOUNT_PTR, &val);
630
callable_obj_t * iterCall = (callable_obj_t*) g_value_get_pointer(&val);
637
gchar * description = NULL;
638
gchar * audio_codec = call_get_audio_codec(c);
640
if (c->_state == CALL_STATE_TRANSFER)
641
description = calltree_display_call_info(c, DISPLAY_TYPE_CALL_TRANSFER, "");
643
if (c->_sas && display_sas && c->_srtp_state == SRTP_STATE_ZRTP_SAS_UNCONFIRMED && !c->_zrtp_confirmed)
644
description = calltree_display_call_info(c, DISPLAY_TYPE_SAS, "");
646
description = calltree_display_call_info(c, DISPLAY_TYPE_STATE_CODE, audio_codec);
651
if (tab == current_calls_tab) {
652
DEBUG("Receiving in state %d", c->_state);
655
case CALL_STATE_HOLD:
656
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/hold.svg", NULL);
658
case CALL_STATE_INCOMING:
659
case CALL_STATE_RINGING:
660
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/ring.svg", NULL);
662
case CALL_STATE_CURRENT:
663
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL);
665
case CALL_STATE_DIALING:
666
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/dial.svg", NULL);
668
case CALL_STATE_FAILURE:
669
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/fail.svg", NULL);
671
case CALL_STATE_BUSY:
672
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/busy.svg", NULL);
674
case CALL_STATE_TRANSFER:
675
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/transfer.svg", NULL);
677
case CALL_STATE_RECORD:
678
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/icon_rec.svg", NULL);
681
WARN("Update calltree - Should not happen!");
684
switch (c->_srtp_state) {
685
case SRTP_STATE_SDES_SUCCESS:
686
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL);
688
case SRTP_STATE_ZRTP_SAS_UNCONFIRMED:
689
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_unconfirmed.svg", NULL);
691
DEBUG("SAS is ready with value %s", c->_sas);
693
case SRTP_STATE_ZRTP_SAS_CONFIRMED:
694
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL);
696
case SRTP_STATE_ZRTP_SAS_SIGNED:
697
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_certified.svg", NULL);
699
case SRTP_STATE_UNLOCKED:
700
if (g_strcasecmp(srtp_enabled,"true") == 0)
701
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL);
704
WARN("Update calltree srtp state #%d- Should not happen!", c->_srtp_state);
705
if (g_strcasecmp(srtp_enabled, "true") == 0)
706
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL);
709
} else if (tab == history_tab) {
710
// parent is NULL this is not a conference participant
712
pixbuf = history_state_to_pixbuf(c->_history_state);
713
else // parent is not NULL this is a conference participant
714
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL);
717
description = calltree_display_call_info(c, DISPLAY_TYPE_HISTORY, "");
718
gchar * date = get_formatted_start_timestamp(c->_time_start);
719
gchar *duration = get_call_duration(c);
720
gchar *full_duration = g_strconcat(date , duration , NULL);
724
gchar *old_description = description;
725
description = g_strconcat(old_description, full_duration, NULL);
726
g_free(full_duration);
727
g_free(old_description);
730
gtk_tree_store_set(store, &iter,
731
COLUMN_ACCOUNT_PIXBUF, pixbuf,
732
COLUMN_ACCOUNT_DESC, description,
733
COLUMN_ACCOUNT_SECURITY_PIXBUF, pixbuf_security,
734
COLUMN_ACCOUNT_PTR, c,
740
g_object_unref(G_OBJECT(pixbuf));
741
if (pixbuf_security != NULL)
742
g_object_unref(G_OBJECT(pixbuf_security));
551
account_t* account = NULL;
553
account = account_list_get_by_id(call->_accountID);
555
if (account != NULL) {
556
srtp_enabled = account_lookup(account, ACCOUNT_SRTP_ENABLED);
557
display_sas = utf8_case_equal(account_lookup(account, ACCOUNT_ZRTP_DISPLAY_SAS), "true");
559
GHashTable * properties = sflphone_get_ip2ip_properties();
560
if (properties != NULL) {
561
srtp_enabled = g_hash_table_lookup(properties, ACCOUNT_SRTP_ENABLED);
562
display_sas = utf8_case_equal(g_hash_table_lookup(properties, ACCOUNT_ZRTP_DISPLAY_SAS), "true");
567
gtk_tree_model_get(model, iter, COLUMN_ID, &id, -1);
569
callable_obj_t * iterCall = calllist_get_call(tab, id);
572
if (iterCall != call)
576
gchar * description = NULL;
577
gchar * audio_codec = call_get_audio_codec(call);
579
if (call->_state == CALL_STATE_TRANSFER)
580
description = calltree_display_call_info(call, DISPLAY_TYPE_CALL_TRANSFER, "");
582
if (call->_sas && display_sas && call->_srtp_state == SRTP_STATE_ZRTP_SAS_UNCONFIRMED && !call->_zrtp_confirmed)
583
description = calltree_display_call_info(call, DISPLAY_TYPE_SAS, "");
585
description = calltree_display_call_info(call, DISPLAY_TYPE_STATE_CODE, audio_codec);
590
if (tab == current_calls_tab) {
591
DEBUG("Receiving in state %d", call->_state);
593
switch (call->_state) {
594
case CALL_STATE_HOLD:
595
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/hold.svg", NULL);
597
case CALL_STATE_INCOMING:
598
case CALL_STATE_RINGING:
599
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/ring.svg", NULL);
601
case CALL_STATE_CURRENT:
602
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL);
604
case CALL_STATE_DIALING:
605
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/dial.svg", NULL);
607
case CALL_STATE_FAILURE:
608
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/fail.svg", NULL);
610
case CALL_STATE_BUSY:
611
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/busy.svg", NULL);
613
case CALL_STATE_TRANSFER:
614
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/transfer.svg", NULL);
616
case CALL_STATE_RECORD:
617
pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/icon_rec.svg", NULL);
620
WARN("Update calltree - Should not happen!");
623
switch (call->_srtp_state) {
624
case SRTP_STATE_SDES_SUCCESS:
625
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL);
627
case SRTP_STATE_ZRTP_SAS_UNCONFIRMED:
628
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_unconfirmed.svg", NULL);
629
if (call->_sas != NULL)
630
DEBUG("SAS is ready with value %s", call->_sas);
632
case SRTP_STATE_ZRTP_SAS_CONFIRMED:
633
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL);
635
case SRTP_STATE_ZRTP_SAS_SIGNED:
636
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_certified.svg", NULL);
638
case SRTP_STATE_UNLOCKED:
639
if (utf8_case_equal(srtp_enabled, "true"))
640
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL);
643
WARN("Update calltree srtp state #%d- Should not happen!", call->_srtp_state);
644
if (utf8_case_equal(srtp_enabled, "true"))
645
pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL);
648
} else if (tab == history_tab) {
649
pixbuf = history_state_to_pixbuf(call->_history_state);
652
description = calltree_display_call_info(call, DISPLAY_TYPE_HISTORY, "");
653
gchar *date = get_formatted_start_timestamp(call->_time_start);
654
gchar *duration = get_call_duration(call);
655
gchar *full_duration = g_strconcat(date , duration , NULL);
659
gchar *old_description = description;
660
description = g_strconcat(old_description, full_duration, NULL);
661
g_free(full_duration);
662
g_free(old_description);
665
gtk_tree_store_set(store, iter,
666
COLUMN_ACCOUNT_PIXBUF, pixbuf,
667
COLUMN_ACCOUNT_DESC, description,
668
COLUMN_ACCOUNT_SECURITY_PIXBUF, pixbuf_security,
669
COLUMN_ID, call->_callID,
670
COLUMN_IS_CONFERENCE, FALSE,
676
g_object_unref(G_OBJECT(pixbuf));
677
if (pixbuf_security != NULL)
678
g_object_unref(G_OBJECT(pixbuf_security));
682
void calltree_update_call(calltab_t* tab, callable_obj_t * call)
685
ERROR("Call is NULL, ignoring");
688
CallUpdateCtx ctx = {tab, call};
689
GtkTreeStore *store = tab->store;
690
GtkTreeModel *model = GTK_TREE_MODEL(store);
691
gtk_tree_model_foreach(model, update_call, (gpointer) &ctx);
746
692
update_actions();
749
void calltree_update_call(calltab_t* tab, callable_obj_t * c)
751
calltree_update_call_recursive(tab, c, NULL);
754
void calltree_add_call(calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent)
695
void calltree_add_call(calltab_t* tab, callable_obj_t * call, GtkTreeIter *parent)
756
697
g_assert(tab != history_tab);
1048
void calltree_remove_conference_recursive(calltab_t* tab, const conference_obj_t* conf, GtkTreeIter *parent)
994
remove_conference(GtkTreeModel *model, GtkTreePath *path UNUSED, GtkTreeIter *iter, gpointer data)
1050
GtkTreeModel *model = GTK_TREE_MODEL(tab->store);
1051
int nbChildren = gtk_tree_model_iter_n_children(model, parent);
1053
for (int i = 0; i < nbChildren; i++) {
1054
GtkTreeIter iter_parent;
1056
/* if the nth child of parent has one or more children */
1057
if (gtk_tree_model_iter_nth_child(model, &iter_parent, parent, i)) {
1059
if (gtk_tree_model_iter_has_child(model, &iter_parent))
1060
calltree_remove_conference_recursive(tab, conf, &iter_parent);
1064
gtk_tree_model_get_value(model, &iter_parent, COLUMN_ACCOUNT_PTR, &confval);
1066
conference_obj_t *tempconf = (conference_obj_t*) g_value_get_pointer(&confval);
1067
g_value_unset(&confval);
1069
/* if this is the conference we want to remove */
1070
if (tempconf == conf) {
1071
int nbParticipants = gtk_tree_model_iter_n_children(model, &iter_parent);
1072
DEBUG("CallTree: nbParticipants: %d", nbParticipants);
1074
for (int j = 0; j < nbParticipants; j++) {
1075
GtkTreeIter iter_child;
1077
if (gtk_tree_model_iter_nth_child(model, &iter_child, &iter_parent, j)) {
1080
gtk_tree_model_get_value(model, &iter_child, COLUMN_ACCOUNT_PTR, &callval);
1082
callable_obj_t *call = g_value_get_pointer(&callval);
1083
g_value_unset(&callval);
1085
// do not add back call in history calltree when cleaning it
1086
if (call && tab != history_tab)
1087
calltree_add_call(tab, call, NULL);
1091
DEBUG("CallTree: Remove conference %s", conf->_confID);
1092
gtk_tree_store_remove(tab->store, &iter_parent);
996
if (!is_conference(model, iter))
1000
gtk_tree_model_get(model, iter, COLUMN_ID, &conf_id, -1);
1002
ConferenceRemoveCtx * ctx = (ConferenceRemoveCtx *) data;
1003
calltab_t *tab = ctx->tab;
1004
conference_obj_t *tempconf = conferencelist_get(tab, conf_id);
1007
const conference_obj_t *conf = ctx->conf;
1008
/* if this is not the conference we want to remove */
1009
if (tempconf != conf)
1012
int nbParticipants = gtk_tree_model_iter_n_children(model, iter);
1013
DEBUG("nbParticipants: %d", nbParticipants);
1015
for (int j = 0; j < nbParticipants; j++) {
1016
GtkTreeIter iter_child;
1018
if (gtk_tree_model_iter_nth_child(model, &iter_child, iter, j)) {
1020
gtk_tree_model_get(model, &iter_child, COLUMN_ID, &call_id, -1);
1022
callable_obj_t *call = calllist_get_call(tab, call_id);
1025
// do not add back call in history calltree when cleaning it
1026
if (call && tab != history_tab)
1027
calltree_add_call(tab, call, NULL);
1031
gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
1097
1033
if (calltab_get_selected_conf(tab) == conf)
1098
1034
calltab_select_conf(tab, NULL);
1103
1038
void calltree_remove_conference(calltab_t* tab, const conference_obj_t* conf)
1105
DEBUG("CallTree: Remove conference %s", conf->_confID);
1106
calltree_remove_conference_recursive(tab, conf, NULL);
1107
DEBUG("CallTree: Finished Removing conference");
1041
ERROR("Could not remove conference, conference pointer is NULL");
1045
ConferenceRemoveCtx context = {tab, conf};
1046
GtkTreeStore *store = tab->store;
1047
GtkTreeModel *model = GTK_TREE_MODEL(store);
1048
gtk_tree_model_foreach(model, remove_conference, (gpointer) &context);
1051
DEBUG("Finished removing conference %s", conf->_confID);
1110
1054
void calltree_display(calltab_t *tab)
1178
static void drag_end_cb(GtkWidget * widget UNUSED, GdkDragContext * context UNUSED, gpointer data UNUSED)
1180
if (active_calltree_tab == history_tab)
1183
DEBUG("CallTree: Drag end callback");
1184
DEBUG("CallTree: selected_path %s, selected_call_id %s, selected_path_depth %d",
1185
calltree_selected_path, calltree_selected_call_id, calltree_selected_path_depth);
1186
DEBUG("CallTree: dragged path %s, dragged_call_id %s, dragged_path_depth %d",
1187
calltree_dragged_path, calltree_dragged_call_id, calltree_dragged_path_depth);
1189
GtkTreeModel *model = (GtkTreeModel*) current_calls_tab->store;
1190
GtkTreePath *path = gtk_tree_path_new_from_string(calltree_dragged_path);
1191
GtkTreePath *dpath = gtk_tree_path_new_from_string(calltree_dragged_path);
1192
GtkTreePath *spath = gtk_tree_path_new_from_string(calltree_selected_path);
1195
GtkTreeIter parent_conference; // conference for which this call is attached
1199
// Make sure drag n drop does not imply a dialing call for either selected and dragged call
1200
if (calltree_selected_call && (calltree_selected_type == A_CALL)) {
1201
DEBUG("CallTree: Selected a call");
1203
if (calltree_selected_call->_state == CALL_STATE_DIALING ||
1204
calltree_selected_call->_state == CALL_STATE_INVALID ||
1205
calltree_selected_call->_state == CALL_STATE_FAILURE ||
1206
calltree_selected_call->_state == CALL_STATE_BUSY ||
1207
calltree_selected_call->_state == CALL_STATE_TRANSFER) {
1209
DEBUG("CallTree: Selected an invalid call");
1211
calltree_remove_call(current_calls_tab, calltree_selected_call);
1212
calltree_add_call(current_calls_tab, calltree_selected_call, NULL);
1214
calltree_dragged_call = NULL;
1219
if (calltree_dragged_call && (calltree_dragged_type == A_CALL)) {
1221
DEBUG("CallTree: Dragged on a call");
1223
if (calltree_dragged_call->_state == CALL_STATE_DIALING ||
1224
calltree_dragged_call->_state == CALL_STATE_INVALID ||
1225
calltree_dragged_call->_state == CALL_STATE_FAILURE ||
1226
calltree_dragged_call->_state == CALL_STATE_BUSY ||
1227
calltree_dragged_call->_state == CALL_STATE_TRANSFER) {
1229
DEBUG("CallTree: Dragged on an invalid call");
1231
calltree_remove_call(current_calls_tab, calltree_selected_call);
1233
if (calltree_selected_call->_confID) {
1235
gtk_tree_path_up(spath);
1236
gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &parent_conference, spath);
1238
calltree_add_call(current_calls_tab, calltree_selected_call, &parent_conference);
1240
calltree_add_call(current_calls_tab, calltree_selected_call, NULL);
1242
calltree_dragged_call = NULL;
1248
// Make sure a conference is only dragged on another conference
1249
if (calltree_selected_conf && (calltree_selected_type == A_CONFERENCE)) {
1251
DEBUG("CallTree: Selected a conference");
1253
if (!calltree_dragged_conf && (calltree_dragged_type == A_CALL)) {
1255
DEBUG("CallTree: Dragged on a call");
1256
conference_obj_t* conf = calltree_selected_conf;
1258
calltree_remove_conference(current_calls_tab, conf);
1259
calltree_add_conference_to_current_calls(conf);
1261
calltree_dragged_call = NULL;
1267
if (calltree_selected_path_depth == 1) {
1268
if (calltree_dragged_path_depth == 1) {
1269
if (calltree_selected_type == A_CALL && calltree_dragged_type == A_CALL) {
1270
if (gtk_tree_path_compare(dpath, spath) != 0) {
1271
// dragged a single call on a single call
1272
if (calltree_selected_call != NULL && calltree_dragged_call != NULL) {
1273
calltree_remove_call(current_calls_tab, calltree_selected_call);
1274
calltree_add_call(current_calls_tab, calltree_selected_call, NULL);
1275
gtk_menu_popup(GTK_MENU(calltree_popupmenu), NULL, NULL, NULL, NULL,
1279
} else if (calltree_selected_type == A_CALL && calltree_dragged_type == A_CONFERENCE) {
1281
// dragged a single call on a conference
1282
if (!calltree_selected_call) {
1283
DEBUG("Error: call dragged on a conference is null");
1287
g_free(calltree_selected_call->_confID);
1288
calltree_selected_call->_confID = g_strdup(calltree_dragged_call_id);
1290
g_free(calltree_selected_call->_historyConfID);
1291
calltree_selected_call->_historyConfID = g_strdup(calltree_dragged_call_id);
1293
sflphone_add_participant(calltree_selected_call_id, calltree_dragged_call_id);
1294
} else if (calltree_selected_type == A_CONFERENCE && calltree_dragged_type == A_CALL) {
1296
// dragged a conference on a single call
1297
conference_obj_t* conf = calltree_selected_conf;
1299
calltree_remove_conference(current_calls_tab, conf);
1300
calltree_add_conference_to_current_calls(conf);
1302
} else if (calltree_selected_type == A_CONFERENCE && calltree_dragged_type == A_CONFERENCE) {
1304
// dragged a conference on a conference
1305
if (gtk_tree_path_compare(dpath, spath) == 0) {
1307
if (!current_calls_tab) {
1308
DEBUG("Error while joining the same conference\n");
1312
DEBUG("Joined the same conference!\n");
1313
gtk_tree_view_expand_row(GTK_TREE_VIEW(current_calls_tab->view), path, FALSE);
1315
if (!calltree_selected_conf)
1316
DEBUG("Error: selected conference is null while joining 2 conference");
1318
if (!calltree_dragged_conf)
1319
DEBUG("Error: dragged conference is null while joining 2 conference");
1321
DEBUG("Joined conferences %s and %s!\n", calltree_dragged_path, calltree_selected_path);
1322
dbus_join_conference(calltree_selected_conf->_confID, calltree_dragged_conf->_confID);
1326
// TODO: dragged a single call on a NULL element (should do nothing)
1327
// TODO: dragged a conference on a NULL element (should do nothing)
1120
static void cleanup_popup_data(PopupData **data)
1122
if (data && *data) {
1123
g_free((*data)->source_ID);
1124
g_free((*data)->dest_ID);
1131
has_parent(GtkTreeModel *model, GtkTreeIter *child)
1134
return gtk_tree_model_iter_parent(model, &parent, child);
1137
static gboolean try_detach(GtkTreeModel *model, GtkTreeIter *source_iter, GtkTreeIter *dest_iter)
1139
gboolean result = FALSE;
1140
if (has_parent(model, source_iter) && !has_parent(model, dest_iter)) {
1141
GValue source_val = G_VALUE_INIT;
1142
gtk_tree_model_get_value(model, source_iter, COLUMN_ID, &source_val);
1143
const gchar *source_ID = g_value_get_string(&source_val);
1144
sflphone_detach_participant(source_ID);
1146
g_value_unset(&source_val);
1152
handle_drop_into(GtkTreeModel *model, GtkTreeIter *source_iter, GtkTreeIter *dest_iter)
1154
GValue source_val = G_VALUE_INIT;
1155
gtk_tree_model_get_value(model, source_iter, COLUMN_ID, &source_val);
1156
const gchar *source_ID = g_value_get_string(&source_val);
1158
GValue dest_val = G_VALUE_INIT;
1159
gtk_tree_model_get_value(model, dest_iter, COLUMN_ID, &dest_val);
1160
const gchar *dest_ID = g_value_get_string(&dest_val);
1162
gboolean result = FALSE;
1164
if (has_parent(model, source_iter)) {
1165
DEBUG("Source is participant, should only be detached");
1167
} else if (!has_parent(model, dest_iter)) {
1168
if (is_conference(model, dest_iter)) {
1169
if (is_conference(model, source_iter)) {
1170
DEBUG("dropped conference on conference, merging conferences");
1171
dbus_join_conference(source_ID, dest_ID);
1174
DEBUG("dropped call on conference, adding a call to a conference");
1175
sflphone_add_participant(source_ID, dest_ID);
1178
} else if (is_conference(model, source_iter)) {
1179
DEBUG("dropped conference on call, merging call into conference");
1180
sflphone_add_participant(dest_ID, source_ID);
1330
// dragged_path_depth == 2
1331
if (calltree_selected_type == A_CALL && calltree_dragged_type == A_CALL) {
1332
// TODO: dragged a call on a conference call
1333
calltree_remove_call(current_calls_tab, calltree_selected_call);
1334
calltree_add_call(current_calls_tab, calltree_selected_call, NULL);
1336
} else if (calltree_selected_type == A_CONFERENCE && calltree_dragged_type == A_CALL) {
1337
// TODO: dragged a conference on a conference call
1338
calltree_remove_conference(current_calls_tab, calltree_selected_conf);
1339
calltree_add_conference_to_current_calls(calltree_selected_conf);
1342
// TODO: dragged a single call on a NULL element
1343
// TODO: dragged a conference on a NULL element
1183
DEBUG("dropped call on call, creating new conference or transferring");
1184
calltree_remove_call(current_calls_tab, source_ID);
1185
callable_obj_t *source_call = calllist_get_call(current_calls_tab, source_ID);
1186
calltree_add_call(current_calls_tab, source_call, NULL);
1187
cleanup_popup_data(&popup_data);
1188
popup_data = g_new0(PopupData, 1);
1189
popup_data->source_ID = g_strdup(source_ID);
1190
popup_data->dest_ID = g_strdup(dest_ID);
1191
gtk_menu_popup(GTK_MENU(calltree_popupmenu), NULL, NULL, NULL, NULL, 0, 0);
1347
if (calltree_dragged_path_depth == 1) {
1348
if (calltree_selected_type == A_CALL && calltree_dragged_type == A_CALL) {
1350
// dragged a conference call on a call
1351
sflphone_detach_participant(calltree_selected_call_id);
1353
if (calltree_selected_call && calltree_dragged_call)
1354
gtk_menu_popup(GTK_MENU(calltree_popupmenu), NULL, NULL, NULL, NULL,
1357
} else if (calltree_selected_type == A_CALL && calltree_dragged_type == A_CONFERENCE) {
1358
// dragged a conference call on a conference
1359
sflphone_detach_participant(calltree_selected_call_id);
1361
if (calltree_selected_call && calltree_dragged_conf) {
1362
DEBUG("Adding a participant, since dragged call on a conference");
1363
sflphone_add_participant(calltree_selected_call_id, calltree_dragged_call_id);
1366
// dragged a conference call on a NULL element
1367
sflphone_detach_participant(calltree_selected_call_id);
1371
// dragged_path_depth == 2
1372
// dragged a conference call on another conference call (same conference)
1373
// TODO: dragged a conference call on another conference call (different conference)
1375
gtk_tree_path_up(path);
1376
gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &parent_conference, path);
1378
gtk_tree_path_up(dpath);
1379
gtk_tree_path_up(spath);
1381
if (gtk_tree_path_compare(dpath, spath) == 0) {
1383
DEBUG("Dragged a call in the same conference");
1384
calltree_remove_call(current_calls_tab, calltree_selected_call);
1385
calltree_add_call(current_calls_tab, calltree_selected_call, &parent_conference);
1386
gtk_widget_hide(calltree_menu_items);
1387
gtk_menu_popup(GTK_MENU(calltree_popupmenu), NULL, NULL, NULL, NULL,
1390
DEBUG("Dragged a conference call onto another conference call %s, %s", gtk_tree_path_to_string(dpath), gtk_tree_path_to_string(spath));
1392
conference_obj_t *conf = NULL;
1395
if (gtk_tree_model_get_iter(model, &iter, dpath)) {
1396
gtk_tree_model_get_value(model, &iter, COLUMN_ACCOUNT_PTR, &val);
1397
conf = (conference_obj_t*) g_value_get_pointer(&val);
1400
g_value_unset(&val);
1402
sflphone_detach_participant(calltree_selected_call_id);
1405
sflphone_add_participant(calltree_selected_call_id, conf->_confID);
1407
DEBUG("didn't find a conf!");
1410
// TODO: dragged a conference call on another conference call (different conference)
1411
// TODO: dragged a conference call on a NULL element (same conference)
1412
// TODO: dragged a conference call on a NULL element (different conference)
1195
// Happens when we drag a call on anther call which participate to a conference
1196
callable_obj_t *dest_call = calllist_get_call(current_calls_tab, dest_ID);
1198
gchar *conf_ID = dbus_get_conference_id(dest_call->_callID);
1199
if (g_strcmp0(conf_ID, "") != 0) {
1200
sflphone_add_participant(source_ID, conf_ID);
1417
void drag_history_received_cb(GtkWidget *widget, GdkDragContext *context UNUSED, gint x UNUSED, gint y UNUSED, GtkSelectionData *selection_data UNUSED, guint info UNUSED, guint t UNUSED, gpointer data UNUSED)
1419
g_signal_stop_emission_by_name(G_OBJECT(widget), "drag_data_received");
1422
void drag_data_received_cb(GtkWidget *widget, GdkDragContext *context UNUSED, gint x UNUSED, gint y UNUSED, GtkSelectionData *selection_data UNUSED, guint info UNUSED, guint t UNUSED, gpointer data UNUSED)
1205
g_value_unset(&source_val);
1206
g_value_unset(&dest_val);
1210
static gboolean valid_drop(GtkTreeModel *model, GtkTreeIter *source_iter, GtkTreePath *dest_path)
1212
gboolean result = TRUE;
1213
GtkTreePath *source_path = gtk_tree_model_get_path(model, source_iter);
1214
if (!gtk_tree_path_compare(source_path, dest_path)) {
1215
ERROR("invalid drop: source and destination are the same");
1217
} else if (gtk_tree_path_is_ancestor(source_path, dest_path)) {
1218
ERROR("invalid drop: source is ancestor of destination");
1220
} else if (gtk_tree_path_is_descendant(source_path, dest_path)) {
1221
ERROR("invalid drop: source is descendant of destination");
1224
gtk_tree_path_free(source_path);
1229
render_drop(GtkTreeModel *model, GtkTreePath *dest_path, GtkTreeViewDropPosition dest_pos,
1230
GtkTreeIter *source_iter)
1232
GtkTreeIter dest_iter;
1233
if (!gtk_tree_model_get_iter(model, &dest_iter, dest_path)) {
1234
ERROR("Could not get destination iterator");
1238
gboolean result = FALSE;
1240
case GTK_TREE_VIEW_DROP_BEFORE:
1241
case GTK_TREE_VIEW_DROP_AFTER:
1242
DEBUG("dropped at position %d, detaching if appropriate", dest_pos);
1243
result = try_detach(model, source_iter, &dest_iter);
1246
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1247
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1249
if (valid_drop(model, source_iter, dest_path))
1250
result = handle_drop_into(model, source_iter, &dest_iter);
1256
void drag_data_received_cb(GtkWidget *widget, GdkDragContext *context, gint x UNUSED,
1257
gint y UNUSED, GtkSelectionData *selection_data UNUSED, guint target_type UNUSED, guint etime, gpointer data UNUSED)
1424
1259
GtkTreeView *tree_view = GTK_TREE_VIEW(widget);
1425
GtkTreePath *drop_path;
1426
GtkTreeViewDropPosition position;
1429
if (active_calltree_tab == history_tab) {
1430
g_signal_stop_emission_by_name(G_OBJECT(widget), "drag_data_received");
1434
GtkTreeModel* tree_model = gtk_tree_view_get_model(tree_view);
1439
gtk_tree_view_get_drag_dest_row(tree_view, &drop_path, &position);
1443
gtk_tree_model_get_iter(tree_model, &iter, drop_path);
1444
gtk_tree_model_get_value(tree_model, &iter, COLUMN_ACCOUNT_PTR, &val);
1447
if (gtk_tree_model_iter_has_child(tree_model, &iter)) {
1448
DEBUG("CallTree: Dragging on a conference");
1449
calltree_dragged_type = A_CONFERENCE;
1450
calltree_dragged_call = NULL;
1452
DEBUG("CallTree: Dragging on a call");
1453
calltree_dragged_type = A_CALL;
1454
calltree_dragged_conf = NULL;
1459
case GTK_TREE_VIEW_DROP_AFTER:
1460
DEBUG("CallTree: GTK_TREE_VIEW_DROP_AFTER");
1461
calltree_dragged_path = gtk_tree_path_to_string(drop_path);
1462
calltree_dragged_path_depth = gtk_tree_path_get_depth(drop_path);
1463
calltree_dragged_call_id = "NULL";
1464
calltree_dragged_call = NULL;
1465
calltree_dragged_conf = NULL;
1468
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1469
DEBUG("CallTree: GTK_TREE_VIEW_DROP_INTO_OR_AFTER");
1470
calltree_dragged_path = gtk_tree_path_to_string(drop_path);
1471
calltree_dragged_path_depth = gtk_tree_path_get_depth(drop_path);
1473
if (calltree_dragged_type == A_CALL) {
1474
calltree_dragged_call_id = ((callable_obj_t*) g_value_get_pointer(&val))->_callID;
1475
calltree_dragged_call = (callable_obj_t*) g_value_get_pointer(&val);
1477
calltree_dragged_call_id = ((conference_obj_t*) g_value_get_pointer(&val))->_confID;
1478
calltree_dragged_conf = (conference_obj_t*) g_value_get_pointer(&val);
1483
case GTK_TREE_VIEW_DROP_BEFORE:
1484
DEBUG("CallTree: GTK_TREE_VIEW_DROP_BEFORE");
1485
calltree_dragged_path = gtk_tree_path_to_string(drop_path);
1486
calltree_dragged_path_depth = gtk_tree_path_get_depth(drop_path);
1487
calltree_dragged_call_id = "NULL";
1488
calltree_dragged_call = NULL;
1489
calltree_dragged_conf = NULL;
1492
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1493
DEBUG("CallTree: GTK_TREE_VIEW_DROP_INTO_OR_BEFORE");
1494
calltree_dragged_path = gtk_tree_path_to_string(drop_path);
1495
calltree_dragged_path_depth = gtk_tree_path_get_depth(drop_path);
1497
if (calltree_dragged_type == A_CALL) {
1498
calltree_dragged_call_id = ((callable_obj_t*) g_value_get_pointer(&val))->_callID;
1499
calltree_dragged_call = (callable_obj_t*) g_value_get_pointer(&val);
1501
calltree_dragged_call_id = ((conference_obj_t*) g_value_get_pointer(&val))->_confID;
1502
calltree_dragged_conf = (conference_obj_t*) g_value_get_pointer(&val);
1260
GtkTreeModel *model = GTK_TREE_MODEL(gtk_tree_view_get_model(tree_view));
1261
GtkTreeSelection *tree_selection = gtk_tree_view_get_selection(tree_view);
1262
GtkTreeIter source_iter;
1263
if (!gtk_tree_selection_get_selected(tree_selection, NULL, &source_iter)) {
1264
ERROR("No tree element selected");
1267
GtkTreePath *dest_path;
1268
GtkTreeViewDropPosition dest_pos;
1269
if (!gtk_tree_view_get_dest_row_at_pos(tree_view, x, y, &dest_path, &dest_pos)) {
1270
ERROR("No row at given position");
1274
gboolean success = render_drop(model, dest_path, dest_pos, &source_iter);
1275
if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
1276
gtk_drag_finish(context, success, TRUE, etime);
1513
1279
/* Print a string when a menu item is selected */
1515
static void menuitem_response(gchar *string)
1282
menuitem_response(gchar * string)
1517
if (g_strcmp0(string, SFL_CREATE_CONFERENCE) == 0)
1518
dbus_join_participant(calltree_selected_call->_callID,
1519
calltree_dragged_call->_callID);
1520
else if (g_strcmp0(string, SFL_TRANSFER_CALL) == 0) {
1521
DEBUG("Calltree: Transferring call %s, to %s",
1522
calltree_selected_call->_peer_number,
1523
calltree_dragged_call->_peer_number);
1524
dbus_attended_transfer(calltree_selected_call, calltree_dragged_call);
1525
calltree_remove_call(current_calls_tab, calltree_selected_call);
1284
if (g_strcmp0(string, SFL_CREATE_CONFERENCE) == 0) {
1285
dbus_join_participant(popup_data->source_ID,
1286
popup_data->dest_ID);
1287
calltree_remove_call(current_calls_tab, popup_data->source_ID);
1288
calltree_remove_call(current_calls_tab, popup_data->dest_ID);
1290
} else if (g_strcmp0(string, SFL_TRANSFER_CALL) == 0) {
1291
callable_obj_t * source_call = calllist_get_call(current_calls_tab, popup_data->source_ID);
1292
callable_obj_t * dest_call = calllist_get_call(current_calls_tab, popup_data->dest_ID);
1293
DEBUG("Transferring call %s, to %s",
1294
source_call->_peer_number,
1295
dest_call->_peer_number);
1296
dbus_attended_transfer(source_call, dest_call);
1297
calltree_remove_call(current_calls_tab, popup_data->source_ID);
1527
DEBUG("CallTree: Error unknown option selected in menu %s", string);
1299
ERROR("Unknown option in menu %s", string);
1529
// Make sure the create conference opetion will appear next time the menu pops
1301
// Make sure the create conference option will appear next time the menu pops
1530
1302
// The create conference option will hide if tow call from the same conference are draged on each other
1531
1303
gtk_widget_show(calltree_menu_items);
1305
cleanup_popup_data(&popup_data);
1533
1307
DEBUG("%s", string);