1 /*
2  * Copyright (c) Tony Bybell 2005-2014.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  */
9 
10 #include <config.h>
11 #include "globals.h"
12 #include <gtk/gtk.h>
13 #include "gtk12compat.h"
14 #include "symbol.h"
15 #include "translate.h"
16 #include "debug.h"
17 
18 
19 #ifdef _MSC_VER
20 #define strcasecmp _stricmp
21 #endif
22 
23 /************************ splay ************************/
24 
xl_splay(char * i,xl_Tree * t)25 xl_Tree * xl_splay (char *i, xl_Tree * t) {
26 /* Simple top down splay, not requiring i to be in the tree t.  */
27 /* What it does is described above.                             */
28     xl_Tree N, *l, *r, *y;
29     int dir;
30 
31     if (t == NULL) return t;
32     N.left = N.right = NULL;
33     l = r = &N;
34 
35     for (;;) {
36 	dir = strcasecmp(i, t->item);
37 	if (dir < 0) {
38 	    if (t->left == NULL) break;
39 	    if (strcasecmp(i, t->left->item)<0) {
40 		y = t->left;                           /* rotate right */
41 		t->left = y->right;
42 		y->right = t;
43 		t = y;
44 		if (t->left == NULL) break;
45 	    }
46 	    r->left = t;                               /* link right */
47 	    r = t;
48 	    t = t->left;
49 	} else if (dir > 0) {
50 	    if (t->right == NULL) break;
51 	    if (strcasecmp(i, t->right->item)>0) {
52 		y = t->right;                          /* rotate left */
53 		t->right = y->left;
54 		y->left = t;
55 		t = y;
56 		if (t->right == NULL) break;
57 	    }
58 	    l->right = t;                              /* link left */
59 	    l = t;
60 	    t = t->right;
61 	} else {
62 	    break;
63 	}
64     }
65     l->right = t->left;                                /* assemble */
66     r->left = t->right;
67     t->left = N.right;
68     t->right = N.left;
69     return t;
70 }
71 
72 
xl_insert(char * i,xl_Tree * t,char * trans)73 xl_Tree * xl_insert(char *i, xl_Tree * t, char *trans) {
74 /* Insert i into the tree t, unless it's already there.    */
75 /* Return a pointer to the resulting tree.                 */
76     xl_Tree * n;
77     int dir;
78 
79     n = (xl_Tree *) calloc_2(1, sizeof (xl_Tree));
80     if (n == NULL) {
81 	fprintf(stderr, "xl_insert: ran out of memory, exiting.\n");
82 	exit(255);
83     }
84     n->item = strcpy(malloc_2(strlen(i)+1), i);
85     if(trans) n->trans = strcpy(malloc_2(strlen(trans)+1), trans);
86 
87     if (t == NULL) {
88 	n->left = n->right = NULL;
89 	return n;
90     }
91     t = xl_splay(i,t);
92     dir = strcasecmp(i,t->item);
93     if (dir<0) {
94 	n->left = t->left;
95 	n->right = t;
96 	t->left = NULL;
97 	return n;
98     } else if (dir>0) {
99 	n->right = t->right;
100 	n->left = t;
101 	t->right = NULL;
102 	return n;
103     } else { /* We get here if it's already in the tree */
104              /* Don't add it again                      */
105 	if(n->trans) free_2(n->trans);
106 	free_2(n->item);
107 	free_2(n);
108 	return t;
109     }
110 }
111 
xl_delete(char * i,xl_Tree * t)112 xl_Tree * xl_delete(char *i, xl_Tree * t) {
113 /* Deletes i from the tree if it's there.               */
114 /* Return a pointer to the resulting tree.              */
115     xl_Tree * x;
116     if (t==NULL) return NULL;
117     t = xl_splay(i,t);
118     if (strcmp(i, t->item) == 0) {               /* found it */
119         if (t->left == NULL) {
120             x = t->right;
121         } else {
122             x = xl_splay(i, t->left);
123             x->right = t->right;
124         }
125         if(t->trans) free_2(t->trans);
126         free_2(t->item);
127         free_2(t);
128         return x;
129     }
130     return t;                         /* It wasn't there */
131 }
132 
133 
134 /************************ splay ************************/
135 
136 
init_filetrans_data(void)137 void init_filetrans_data(void)
138 {
139 int i;
140 
141 if(!GLOBALS->filesel_filter) { GLOBALS->filesel_filter = calloc_2(FILE_FILTER_MAX+1, sizeof(char *)); }
142 if(!GLOBALS->xl_file_filter) { GLOBALS->xl_file_filter = calloc_2(FILE_FILTER_MAX+1, sizeof(struct xl_tree_node *)); }
143 
144 for(i=0;i<FILE_FILTER_MAX+1;i++)
145 	{
146 	GLOBALS->filesel_filter[i] = NULL;
147 	GLOBALS->xl_file_filter[i] = NULL;
148 	}
149 }
150 
regen_display(void)151 static void regen_display(void)
152 {
153 GLOBALS->signalwindow_width_dirty=1;
154 MaxSignalLength();
155 signalarea_configure_event(GLOBALS->signalarea, NULL);
156 wavearea_configure_event(GLOBALS->wavearea, NULL);
157 }
158 
159 
remove_file_filter_2(xl_Tree * t)160 static void remove_file_filter_2(xl_Tree *t)
161 {
162 if(t->left) remove_file_filter_2(t->left);
163 if(t->right) remove_file_filter_2(t->right);
164 if(t->item) free_2(t->item);
165 if(t->trans) free_2(t->trans);
166 free_2(t);
167 }
168 
remove_file_filter(int which,int regen)169 static void remove_file_filter(int which, int regen)
170 {
171 if(GLOBALS->xl_file_filter[which])
172 	{
173 	remove_file_filter_2(GLOBALS->xl_file_filter[which]);
174 	GLOBALS->xl_file_filter[which] = NULL;
175 	}
176 
177 if(regen)
178         {
179 	regen_display();
180         }
181 }
182 
load_file_filter(int which,char * name)183 static void load_file_filter(int which, char *name)
184 {
185 FILE *f = fopen(name, "rb");
186 if(!f)
187 	{
188 	status_text("Could not open filter file!\n");
189 	return;
190 	}
191 
192 remove_file_filter(which, 0); /* should never happen from GUI, but possible from save files or other weirdness */
193 
194 while(!feof(f))
195 	{
196 	char *s = fgetmalloc(f);
197 	if(s)
198 		{
199 		char *lhs = s;
200 
201 		while(*lhs && isspace((int)(unsigned char)*lhs)) lhs++;
202 		if(lhs)
203 			{
204 			char *rhs = lhs;
205 
206 			if(*lhs != '#')	/* ignore comments */
207 				{
208 				while(*rhs && !isspace((int)(unsigned char)*rhs)) rhs++;
209 				if(*rhs)
210 					{
211 					char *xlt = rhs+1;
212 					*rhs = 0;
213 
214 					while(*xlt && isspace((int)(unsigned char)*xlt)) xlt++;
215 					if(*xlt)
216 						{
217 						GLOBALS->xl_file_filter[which] =  xl_insert(lhs, GLOBALS->xl_file_filter[which], xlt);
218 						}
219 					}
220 				}
221 			}
222 
223 		free_2(s);
224 		}
225 	}
226 
227 fclose(f);
228 }
229 
230 
load_enums_filter(int which,char * name)231 static void load_enums_filter(int which, char *name)
232 {
233 int argc;
234 char **spl = zSplitTclList(name, &argc);
235 int i;
236 
237 if((!spl)||(!argc)||(argc&1))
238 	{
239 	status_text("Malformed enums list!\n");
240 	return;
241 	}
242 
243 remove_file_filter(which, 0); /* should never happen from GUI, but possible from save files or other weirdness */
244 
245 for(i=0;i<argc;i+=2)
246 	{
247 	char *lhs = spl[i];
248 	char *xlt = spl[i+1];
249 
250 	GLOBALS->xl_file_filter[which] =  xl_insert(lhs, GLOBALS->xl_file_filter[which], xlt);
251 	}
252 free_2(spl);
253 }
254 
255 
install_file_filter(int which)256 int install_file_filter(int which)
257 {
258 int found = 0;
259 
260 if((which<0)||(which>=(FILE_FILTER_MAX+1)))
261 	{
262 	which = 0;
263 	}
264 
265 if(GLOBALS->traces.first)
266         {
267         Trptr t = GLOBALS->traces.first;
268         while(t)
269                 {
270                 if(t->flags&TR_HIGHLIGHT)
271                         {
272                         if(!(t->flags&(TR_BLANK|TR_ANALOG_BLANK_STRETCH)))
273                                 {
274                                 t->f_filter = which;
275 				t->p_filter = 0;
276 				if(!which)
277 					{
278 					t->flags &= (~(TR_FTRANSLATED|TR_PTRANSLATED|TR_ANALOGMASK));
279 					}
280 					else
281 					{
282 					t->flags &= (~(TR_ANALOGMASK));
283 					t->flags |= TR_FTRANSLATED;
284 					}
285                                 found++;
286                                 }
287                         }
288                 t=t->t_next;
289                 }
290         }
291 
292 if(found)
293 	{
294 	regen_display();
295 	}
296 
297 return(found);
298 }
299 
300 /************************************************************************/
301 
302 
303 
destroy_callback(GtkWidget * widget,GtkWidget * nothing)304 static void destroy_callback(GtkWidget *widget, GtkWidget *nothing)
305 {
306 (void)widget;
307 (void)nothing;
308 
309 GLOBALS->is_active_translate_c_5=0;
310 gtk_widget_destroy(GLOBALS->window_translate_c_11);
311 GLOBALS->window_translate_c_11 = NULL;
312 }
313 
ok_callback(GtkWidget * widget,GtkWidget * nothing)314 static void ok_callback(GtkWidget *widget, GtkWidget *nothing)
315 {
316 install_file_filter(GLOBALS->current_filter_translate_c_2);
317 destroy_callback(widget, nothing);
318 }
319 
select_row_callback(GtkWidget * widget,gint row,gint column,GdkEventButton * event,gpointer data)320 static void select_row_callback(GtkWidget *widget, gint row, gint column,
321 	GdkEventButton *event, gpointer data)
322 {
323 (void)widget;
324 (void)row;
325 (void)column;
326 (void)event;
327 (void)data;
328 
329 GLOBALS->current_filter_translate_c_2 = row + 1;
330 }
331 
unselect_row_callback(GtkWidget * widget,gint row,gint column,GdkEventButton * event,gpointer data)332 static void unselect_row_callback(GtkWidget *widget, gint row, gint column,
333 	GdkEventButton *event, gpointer data)
334 {
335 (void)widget;
336 (void)row;
337 (void)column;
338 (void)event;
339 (void)data;
340 
341 GLOBALS->current_filter_translate_c_2 = 0; /* none */
342 }
343 
344 
add_filter_callback_2(GtkWidget * widget,GtkWidget * nothing)345 static void add_filter_callback_2(GtkWidget *widget, GtkWidget *nothing)
346 {
347 (void)widget;
348 (void)nothing;
349 
350 int i;
351 GtkCList *cl;
352 
353 if(!GLOBALS->filesel_ok) { return; }
354 
355 if(*GLOBALS->fileselbox_text)
356 	{
357 	for(i=0;i<GLOBALS->num_file_filters;i++)
358 		{
359 		if(GLOBALS->filesel_filter[i])
360 			{
361 			if(!strcmp(GLOBALS->filesel_filter[i], *GLOBALS->fileselbox_text))
362 				{
363 				status_text("Filter already imported.\n");
364 				if(GLOBALS->is_active_translate_c_5) gdk_window_raise(GLOBALS->window_translate_c_11->window);
365 				return;
366 				}
367 			}
368 		}
369 	}
370 
371 GLOBALS->num_file_filters++;
372 load_file_filter(GLOBALS->num_file_filters, *GLOBALS->fileselbox_text);
373 if(GLOBALS->xl_file_filter[GLOBALS->num_file_filters] && (*GLOBALS->fileselbox_text /* scan-build */))
374 	{
375 	if(GLOBALS->filesel_filter[GLOBALS->num_file_filters]) free_2(GLOBALS->filesel_filter[GLOBALS->num_file_filters]);
376 	GLOBALS->filesel_filter[GLOBALS->num_file_filters] = malloc_2(strlen(*GLOBALS->fileselbox_text) + 1);
377 	strcpy(GLOBALS->filesel_filter[GLOBALS->num_file_filters], *GLOBALS->fileselbox_text);
378 
379 	cl=GTK_CLIST(GLOBALS->clist_translate_c_4);
380 	gtk_clist_freeze(cl);
381 	gtk_clist_append(cl,(gchar **)&(GLOBALS->filesel_filter[GLOBALS->num_file_filters]));
382 
383 	gtk_clist_set_column_width(cl,0,gtk_clist_optimal_column_width(cl,0));
384 	gtk_clist_thaw(cl);
385 	}
386 	else
387 	{
388 	GLOBALS->num_file_filters--;
389 	}
390 
391 if(GLOBALS->is_active_translate_c_5) gdk_window_raise(GLOBALS->window_translate_c_11->window);
392 }
393 
add_filter_callback(GtkWidget * widget,GtkWidget * nothing)394 static void add_filter_callback(GtkWidget *widget, GtkWidget *nothing)
395 {
396 (void)widget;
397 (void)nothing;
398 
399 if(GLOBALS->num_file_filters == FILE_FILTER_MAX)
400 	{
401 	status_text("Max number of file filters installed already.\n");
402 	return;
403 	}
404 
405 fileselbox("Select Filter File",&GLOBALS->fcurr_translate_c_2,GTK_SIGNAL_FUNC(add_filter_callback_2), GTK_SIGNAL_FUNC(NULL),NULL, 0);
406 }
407 
408 /*
409  * mainline..
410  */
trans_searchbox(char * title)411 void trans_searchbox(char *title)
412 {
413     int i;
414 
415     GtkWidget *scrolled_win;
416     GtkWidget *vbox1, *hbox, *hbox0;
417     GtkWidget *button1, *button5, *button6;
418     gchar *titles[]={"Filter Select"};
419     GtkWidget *frame2, *frameh, *frameh0;
420     GtkWidget *table;
421     GtkTooltips *tooltips;
422 
423     if(GLOBALS->is_active_translate_c_5)
424 	{
425 	gdk_window_raise(GLOBALS->window_translate_c_11->window);
426 	return;
427 	}
428 
429     GLOBALS->is_active_translate_c_5=1;
430     GLOBALS->current_filter_translate_c_2 = 0;
431 
432     /* create a new modal window */
433     GLOBALS->window_translate_c_11 = gtk_window_new(GLOBALS->disable_window_manager ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
434     install_focus_cb(GLOBALS->window_translate_c_11, ((char *)&GLOBALS->window_translate_c_11) - ((char *)GLOBALS));
435 
436     gtk_window_set_title(GTK_WINDOW (GLOBALS->window_translate_c_11), title);
437     gtkwave_signal_connect(GTK_OBJECT (GLOBALS->window_translate_c_11), "delete_event",(GtkSignalFunc) destroy_callback, NULL);
438 
439     tooltips=gtk_tooltips_new_2();
440 
441     table = gtk_table_new (256, 1, FALSE);
442     gtk_widget_show (table);
443 
444     vbox1 = gtk_vbox_new (FALSE, 0);
445     gtk_container_border_width (GTK_CONTAINER (vbox1), 3);
446     gtk_widget_show (vbox1);
447 
448 
449     frame2 = gtk_frame_new (NULL);
450     gtk_container_border_width (GTK_CONTAINER (frame2), 3);
451     gtk_widget_show(frame2);
452 
453     gtk_table_attach (GTK_TABLE (table), frame2, 0, 1, 0, 254,
454                         GTK_FILL | GTK_EXPAND,
455                         GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
456 
457     GLOBALS->clist_translate_c_4=gtk_clist_new_with_titles(1,titles);
458     gtk_clist_column_titles_passive(GTK_CLIST(GLOBALS->clist_translate_c_4));
459 
460     gtk_clist_set_selection_mode(GTK_CLIST(GLOBALS->clist_translate_c_4), GTK_SELECTION_EXTENDED);
461     gtkwave_signal_connect_object (GTK_OBJECT (GLOBALS->clist_translate_c_4), "select_row",GTK_SIGNAL_FUNC(select_row_callback),NULL);
462     gtkwave_signal_connect_object (GTK_OBJECT (GLOBALS->clist_translate_c_4), "unselect_row",GTK_SIGNAL_FUNC(unselect_row_callback),NULL);
463 
464     for(i=0;i<GLOBALS->num_file_filters;i++)
465 	{
466 	gtk_clist_append(GTK_CLIST(GLOBALS->clist_translate_c_4),(gchar **)&(GLOBALS->filesel_filter[i+1]));
467 	}
468     gtk_clist_set_column_width(GTK_CLIST(GLOBALS->clist_translate_c_4),0,gtk_clist_optimal_column_width(GTK_CLIST(GLOBALS->clist_translate_c_4),0));
469 
470     gtk_widget_show (GLOBALS->clist_translate_c_4);
471 
472     scrolled_win = gtk_scrolled_window_new (NULL, NULL);
473     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
474                                       GTK_POLICY_AUTOMATIC,
475                                       GTK_POLICY_AUTOMATIC);
476     gtk_widget_set_usize( GTK_WIDGET (scrolled_win), -1, 300);
477     gtk_widget_show(scrolled_win);
478 
479     /* gtk_scrolled_window_add_with_viewport doesn't seen to work right here.. */
480     gtk_container_add (GTK_CONTAINER (scrolled_win), GLOBALS->clist_translate_c_4);
481 
482     gtk_container_add (GTK_CONTAINER (frame2), scrolled_win);
483 
484 
485     frameh0 = gtk_frame_new (NULL);
486     gtk_container_border_width (GTK_CONTAINER (frameh0), 3);
487     gtk_widget_show(frameh0);
488     gtk_table_attach (GTK_TABLE (table), frameh0, 0, 1, 254, 255,
489                         GTK_FILL | GTK_EXPAND,
490                         GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
491 
492 
493     hbox0 = gtk_hbox_new (FALSE, 1);
494     gtk_widget_show (hbox0);
495 
496     button6 = gtk_button_new_with_label (" Add Filter to List ");
497     gtk_container_border_width (GTK_CONTAINER (button6), 3);
498     gtkwave_signal_connect_object (GTK_OBJECT (button6), "clicked",GTK_SIGNAL_FUNC(add_filter_callback),GTK_OBJECT (GLOBALS->window_translate_c_11));
499     gtk_widget_show (button6);
500     gtk_tooltips_set_tip_2(tooltips, button6,
501 		"Bring up a file requester to add a filter to the filter select window.",NULL);
502 
503     gtk_box_pack_start (GTK_BOX (hbox0), button6, TRUE, FALSE, 0);
504     gtk_container_add (GTK_CONTAINER (frameh0), hbox0);
505 
506     frameh = gtk_frame_new (NULL);
507     gtk_container_border_width (GTK_CONTAINER (frameh), 3);
508     gtk_widget_show(frameh);
509     gtk_table_attach (GTK_TABLE (table), frameh, 0, 1, 255, 256,
510                         GTK_FILL | GTK_EXPAND,
511                         GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
512 
513 
514     hbox = gtk_hbox_new (FALSE, 1);
515     gtk_widget_show (hbox);
516 
517     button1 = gtk_button_new_with_label (" OK ");
518     gtk_container_border_width (GTK_CONTAINER (button1), 3);
519     gtkwave_signal_connect_object (GTK_OBJECT (button1), "clicked",GTK_SIGNAL_FUNC(ok_callback),GTK_OBJECT (GLOBALS->window_translate_c_11));
520     gtk_widget_show (button1);
521     gtk_tooltips_set_tip_2(tooltips, button1,
522 		"Add selected signals to end of the display on the main window.",NULL);
523 
524     gtk_box_pack_start (GTK_BOX (hbox), button1, TRUE, FALSE, 0);
525 
526     button5 = gtk_button_new_with_label (" Cancel ");
527     gtk_container_border_width (GTK_CONTAINER (button5), 3);
528     gtkwave_signal_connect_object (GTK_OBJECT (button5), "clicked",GTK_SIGNAL_FUNC(destroy_callback),GTK_OBJECT (GLOBALS->window_translate_c_11));
529     gtk_tooltips_set_tip_2(tooltips, button5,
530 		"Do nothing and return to the main window.",NULL);
531     gtk_widget_show (button5);
532     gtk_box_pack_start (GTK_BOX (hbox), button5, TRUE, FALSE, 0);
533 
534     gtk_container_add (GTK_CONTAINER (frameh), hbox);
535     gtk_container_add (GTK_CONTAINER (GLOBALS->window_translate_c_11), table);
536 
537     gtk_widget_set_usize(GTK_WIDGET(GLOBALS->window_translate_c_11), 400, 400);
538     gtk_widget_show(GLOBALS->window_translate_c_11);
539 }
540 
541 
542 /*
543  * currently only called by parsewavline+tcl
544  */
set_current_translate_generic(char * name,int typ)545 static void set_current_translate_generic(char *name, int typ)
546 {
547 int i;
548 
549 if(typ)
550 	{
551 	for(i=1;i<GLOBALS->num_file_filters+1;i++)
552 		{
553 		if(!strcmp(GLOBALS->filesel_filter[i], name)) { GLOBALS->current_translate_file = i; return; }
554 		}
555 
556 	if(!strcmp(WAVE_TCL_INSTALLED_FILTER, name))
557 		{
558 		GLOBALS->current_translate_file = 0; return;
559 		}
560 	}
561 
562 if(GLOBALS->num_file_filters < FILE_FILTER_MAX)
563 	{
564 	GLOBALS->num_file_filters++;
565 
566 	if(typ)
567 		{
568 		load_file_filter(GLOBALS->num_file_filters, name);
569 		}
570 		else
571 		{
572 		load_enums_filter(GLOBALS->num_file_filters, name);
573 		}
574 
575 	if(!GLOBALS->xl_file_filter[GLOBALS->num_file_filters])
576 		{
577 		GLOBALS->num_file_filters--;
578 		GLOBALS->current_translate_file = 0;
579 		}
580 		else
581 		{
582 		if(GLOBALS->filesel_filter[GLOBALS->num_file_filters]) free_2(GLOBALS->filesel_filter[GLOBALS->num_file_filters]);
583 
584 		if(!typ)
585 			{
586 			name = WAVE_TCL_INSTALLED_FILTER;
587 			}
588 
589 		GLOBALS->filesel_filter[GLOBALS->num_file_filters] = malloc_2(strlen(name) + 1);
590 		strcpy(GLOBALS->filesel_filter[GLOBALS->num_file_filters], name);
591 		GLOBALS->current_translate_file = GLOBALS->num_file_filters;
592 		}
593 	}
594 }
595 
596 
set_current_translate_file(char * name)597 void set_current_translate_file(char *name)
598 {
599 set_current_translate_generic(name, 1); /* use file, not enums */
600 }
601 
set_current_translate_enums(char * lst)602 void set_current_translate_enums(char *lst)
603 {
604 set_current_translate_generic(lst, 0); /* use enums */
605 }
606 
607 
608