File: g_formop.c

package info (click to toggle)
plan 1.10.1-2
  • links: PTS
  • area: main
  • in suites: squeeze, wheezy
  • size: 2,228 kB
  • ctags: 1,995
  • sloc: ansic: 25,050; perl: 1,361; sh: 1,003; makefile: 528; yacc: 121; sed: 17
file content (638 lines) | stat: -rw-r--r-- 18,100 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
/*
 * this file is part of the form editor, it is mostly called by callbacks in
 * formwin.c. It allocates forms and items, finds good defaults for things,
 * and does some form geometry operations. Actual form drawing is done in
 * preview.c (for the edit canvas) and cardwin.c (for final cards).
 *
 *	form_create()			allocate form with default parms
 *	form_delete(form)		free form and all items in it
 *	verify_form(form,bug,shell)	make sure that form is consistent
 *	form_edit_script(form,sh,fn)	start up editor for form script
 *	form_sort(form)			sort form's items by y/x position
 *
 *	item_deselect(form)		deselect all items in canvas
 *	item_create(form, nitem)	allocate item and figure out defaults
 *	item_delete(form, nitem)	free item and remove from form
 */

#include <X11/Xos.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <Xm/Xm.h>
#include "config.h"

#ifdef GROK
#include "proto.h"
#endif
#ifdef PLANGROK
#include "config.h"
#include "cal.h"
#endif
#if defined(GROK) || defined(PLANGROK)
#include "grok.h"
#include "form.h"

#define CHUNK		10		/* alloc 10 new item ptrs at a time */
#define XSNAP(x)	((x)-(x)%form->xg)
#define YSNAP(y)	((y)-(y)%form->yg)

#ifndef GROK
void clone_chart_component(UNUSED CHART *to, UNUSED CHART *from) {}
void del_chart_component(UNUSED ITEM *item) {}
extern ITEM *item_clone(ITEM *);
extern void item_delete(FORM *, int);
#endif

static void		set_form_defaults(FORM *);
extern Widget		toplevel;	/* top-level shell for icon name */


/*------------------------------------------------- operations on form ------*/
/*
 * allocate a new empty form struct, and fill it with reasonable default
 * paramaters.
 */

FORM *form_create(void)
{
	FORM		*form;		/* new form */

	if (!(form = (FORM *)malloc(sizeof(FORM)))) {
		create_error_popup(toplevel, errno, "Can't create form");
		return(0);
	}
	set_form_defaults(form);
	return(form);
}


static void set_form_defaults(
	FORM		*form)		/* for to initialize */
{
	mybzero((void *)form, sizeof(FORM));
	form->cdelim	 = ':';
	form->xg	 = 4;
	form->yg	 = 4;
	form->xs	 = XSNAP(400);
	form->ys	 = YSNAP(200);
	form->autoquery  = -1;
}


/*
 * clone a form. This is done when the form editor is started with a template
 * form, we mustn't overwrite the form currently being displayed in the main
 * menu.
 */

#ifdef GROK
FORM *form_clone(
	FORM		*parent)	/* old form */
{
	FORM		*form;		/* new form */
	int		i;

	if (!(form = (FORM *)malloc(sizeof(FORM)))) {
		create_error_popup(toplevel, errno, "Can't clone form");
		return(0);
	}
	*form = *parent;
	form->path    = mystrdup(parent->path);
	form->name    = mystrdup(parent->name);
	form->dbase   = mystrdup(parent->dbase);
	form->comment = mystrdup(parent->comment);
	form->help    = mystrdup(parent->help);

	if (form->nitems &&
	    !(form->items = (ITEM **)malloc(form->size * sizeof(ITEM *)))) {
		create_error_popup(toplevel, errno, "Can't clone field list");
		form->nitems = 0;
	}
	for (i=0; i < form->nitems; i++)
		form->items[i] = item_clone(parent->items[i]);

	if (form->query) {
		if (!(form->query = malloc(form->nqueries * sizeof(DQUERY)))) {
			create_error_popup(toplevel, errno, "Queries lost");
			form->nqueries = 0;
		}
		for (i=0; i < form->nqueries; i++) {
			form->query[i].suspended = parent->query[i].suspended;
			form->query[i].name = mystrdup(parent->query[i].name);
			form->query[i].query= mystrdup(parent->query[i].query);
		}
	}
	return(form);
}
#endif /* GROK */


/*
 * destroy a form struct and all its items. The pointer passed is not freed.
 * Make sure to remove all windows that display a view of this form first.
 * Initialize the form with defaults (this is used when reading form file).
 */

void form_delete(
	FORM		*form)		/* form to delete */
{
	DQUERY		*dq;		/* default query entry */
	int		i;

	if (!form)
		return;
	for (i=0; i < form->nitems; i++)
		item_delete(form, i);

	if (form->path)		free((void *)form->path);
	if (form->name)		free((void *)form->name);
	if (form->dbase)	free((void *)form->dbase);
	if (form->comment)	free((void *)form->comment);
	if (form->help)		free((void *)form->help);
	if (form->query) {
		for (i=0; i < form->nqueries; i++) {
			dq = &form->query[i];
			if (dq->name)	free((void *)dq->name);
			if (dq->query)	free((void *)dq->query);
		}
		free((void *)form->query);
	}
	set_form_defaults(form);
}


/*
 * print an error report and return FALSE if there are problems with the
 * form. If there is an error, set *bug to the item# of the first buggy
 * item; otherwise set to form->nitems. This is used to highlight the
 * first incorrect item.
 */

#ifdef GROK
#define ISFLAG(i) (i->type == IT_FLAG || i->type == IT_CHOICE)

BOOL verify_form(
	FORM		*form,		/* form to verify */
	int		*bug,		/* retuirned buggy item # */
	Widget		shell)		/* error popup parent */
{
	int		nitem, ni;	/* item counter */
	ITEM		*item, *it;	/* item pointer */
	int		nq;		/* query pointer */
	DQUERY		*dq;		/* query pointer */
	char		name[256];	/* current item's name */
	char		msg[16384];	/* error messages */
	int		i0, i = 0;	/* next free byte in msg[] */
	int		sumwidth = 0;	/* total length of summary */

	if (bug)
		*bug = form->nitems;
	if (!form->name || !*form->name) {
		sprintf(msg+i, "Form has no name\n");
		i += strlen(msg+i);
	}
	if (!form->dbase || !*form->dbase) {
		sprintf(msg+i, "Form has no database%s\n",
					form->name ? "using form name" : "");
		i += strlen(msg+i);
		form->dbase = mystrdup(form->name);
	}
	if (form->cdelim < 1) {
		sprintf(msg+i, "Illegal field delimiter, using TAB\n");
		i += strlen(msg+i);
		form->cdelim = '\t';
	}
	for (nitem=0; nitem < form->nitems; nitem++) {
		i0 = i;
		item = form->items[nitem];
		sumwidth += item->sumwidth;
		sprintf(name, "Field \"%s\" (#%d)",
					item->name ? item->name : "", nitem);
		if (!item->name || !*item->name) {
			char newname[40];
			sprintf(newname, "item%d", nitem);
			sprintf(msg+i, "%s has no internal name, using %s\n",
								name, newname);
			i += strlen(msg+i);
			item->name = mystrdup(newname);
		}
		if (item->xs <= 0 || item->ys <= 0) {
			if (!item->xs) item->xs = 10;
			if (!item->ys) item->ys = 10;
			sprintf(msg+i, "%s has zero size, setting to %d %d\n",
						name, item->xs, item->ys);
			i += strlen(msg+i);
		}
		if (!item->label && item->type != IT_VIEW) {
			sprintf(msg+i, "%s has no label, using \"%s\"\n",
								name, name);
			i += strlen(msg+i);
			item->label = mystrdup(name);
		}
		if (!item->flagcode && ISFLAG(item)) {
			sprintf(msg+i, "%s has no flag code\n", name);
			i += strlen(msg+i);
		}
		if (!item->pressed && item->type == IT_BUTTON) {
			sprintf(msg+i, "%s has no button action\n", name);
			i += strlen(msg+i);
		}
		if (!item->database && item->type == IT_VIEW) {
			sprintf(msg+i, "%s has no query database\n", name);
			i += strlen(msg+i);
		}
		if (!item->query && item->type == IT_VIEW) {
			sprintf(msg+i, "%s has no query\n", name);
			i += strlen(msg+i);
		}
		for (nq=0; nq < form->nqueries; nq++) {
		    dq = &form->query[nq];
		    if (!dq->suspended) {
			if (!dq->name) {
				sprintf(msg+i, "Query %d has no name\n", nq+1);
				i += strlen(msg+i);
			}
			if (!dq->query) {
				sprintf(msg+i, "Query %d has no query\n",nq+1);
				i += strlen(msg+i);
			}
		    }
		}
		for (ni=nitem+1; ni < form->nitems; ni++) {
			it = form->items[ni];
			if (item->type == IT_CHOICE && it->type == IT_CHOICE) {
				BOOL eq  = !strcmp(item->name, it->name);
				BOOL sam = FALSE;
				char *m  = 0;
				if      ((item->column   == it->column) != eq)
					m = "dbase column";
				else if ((item->sumcol   == it->sumcol) != eq)
					m = "summary column";
				else if ((item->sumwidth == it->sumwidth)!=eq)
					m = "summary width";
				else if ((item->flagcode == it->flagcode)&&eq){
					m = "flag code";
					sam = TRUE;
				}
				if (m && (eq || sam)) {
					sprintf(msg+i,
		       "(choice) has %s internal name as #%d, but has %s %s\n",
						eq  ? "same" : "different", ni,
						sam ? "same" : "different", m);
					i += strlen(msg+i);
				}
				continue;
			}
			if (item->name	&& it->name
					&& !strcmp(item->name, it->name)) {
				sprintf(msg+i,"%s has same name as field #%d\n"
								,name, ni);
				i += strlen(msg+i);
			}
			if (IN_DBASE(item->type) && IN_DBASE(it->type)
					&& item->column == it->column
					&& (!ISFLAG(item) || !ISFLAG(it))) {
				sprintf(msg+i,
			   "%s uses same dbase column as field \"%s\" (#%d)\n",
					name, it->name ? it->name : "", ni);
				i += strlen(msg+i);
			}
			if (IN_DBASE(item->type) && IN_DBASE(it->type)
					&& item->sumwidth>0 && it->sumwidth>0
					&& item->sumcol == it->sumcol) {
				sprintf(msg+i,
			 "%s uses same summary column as field \"%s\" (#%d)\n",
					name, it->name ? it->name : "", ni);
				i += strlen(msg+i);
			}
			if (i > sizeof(msg)-1024) {
				sprintf(msg+i, "Too many errors, aborted.");
				break;
			}
		}
		if (i > sizeof(msg)-1024) {
			sprintf(msg+i, "Too many errors, aborted.");
			break;
		}
		if (i > i0 && bug && *bug == form->nitems)
			*bug = nitem;
	}
	if (form->nitems && sumwidth == 0) {
		sprintf(msg+i, "Summary is empty, all summary widths are 0\n");
		i += strlen(msg+i);
	}
	if (i)
		create_error_popup(shell, 0, msg);
	else {
		for (i=nitem=0; nitem < form->nitems; nitem++) {
			item = form->items[nitem];
			if (item->type == IT_NOTE && item->maxlen <= 100) {
				sprintf(msg+i,
		"Warning: note field \"%s\" (#%d) has short max length %d",
					item->name ? item->name : "", nitem,
					item->maxlen);
				i += strlen(msg+i);
			}
		}
		if (i)
			create_error_popup(shell, 0, msg);
		i = 0;
	}
	return(!i);
}


/*
 * the database is procedural, and the edit button was pressed. Start up an
 * editor window with fname, up to the first blank (this is useful for passing
 * cmd line options later).
 */

void form_edit_script(
	FORM		*form,		/* form to edit */
	Widget		shell,		/* error popup parent */
	char		*fname)		/* file name of script (dbase name) */
{
	char		path[1024], *p, *q;

	if (!fname || !*fname) {
		create_error_popup(shell, 0,
"Please specify a database name first.\n\
The database name will be used as script name.");
		return;
	}
	form->proc = TRUE;
	fillout_formedit_widget_by_code(0x105);

	for (p=fname, q=path; *p && *p != ' ' && *p != '\t'; p++, q++)
		*q = *p;
	*q = 0;
	fname = resolve_tilde(path, "db");
	edit_file(fname, FALSE, TRUE, "Procedural Database", "procdbedit");
}


/*
 * sort the form's items by y, then x position (lower left corner). Later
 * traversal in order can then be done simply by going down the list.
 */

static int icompare(
	MYCONST void	*u,
	MYCONST void	*v)
{
	ITEM		*iu = *(ITEM **)u;
	ITEM		*iv = *(ITEM **)v;

	return(iu->y+iu->ys == iv->y+iv->ys ? iu->x+iu->xs - iv->x-iv->xs
					    : iu->y+iu->ys - iv->y-iv->ys);
}


void form_sort(
	FORM		*form)		/* form to sort */
{
	if (!form || !form->items || !form->nitems)
		return;
	qsort((void *)form->items, form->nitems, sizeof(ITEM *), icompare);
}
#endif /* GROK */


/*------------------------------------------------- operations on form items */
/*
 * deselect all items. The caller must make sure to set curr_item to the
 * number of items in the current form (which means no selection). Here, only
 * the selected flags are cleared. This happens when Unselect is pressed, but
 * also if an item is added (we only want the added one selected afterwards).
 */

#ifdef GROK
void item_deselect(
	FORM		*form)		/* describes form and all items in it*/
{
	ITEM		*item;		/* new item struct */
	int		i;		/* index of item */

	for (i=0; i < form->nitems; i++) {
		item = form->items[i];
		if (item->selected) {
			item->selected = FALSE;
			redraw_canvas_item(item);
		}
	}
}
#endif /* GROK */


/*
 * insert an item into the form, at the current field <nitem>. Fields are
 * stored in the form, which contains an array of pointers that point to
 * the field data structures. That way, we don't need to re-allocate the
 * form struct itself, and items can be easily re-arranged.
 * This assumes that fe_item_deselect has been called.
 * Provide reasonable defaults for the new field.
 */

BOOL item_create(
	FORM		*form,		/* describes form and all items in it*/
	int		nitem)		/* the current item, insert point */
{
	ITEM		*item;		/* new item struct */
	ITEM		*prev;		/* prev item, plundered for defaults */
	int		i, j, n, t;	/* various counters */
	char		buf[80];	/* temp for default strings */

							/* allocate array */
	if (!form->items || form->nitems >= form->size) {
		i = (form->size + CHUNK) * sizeof(ITEM *);
		if (!(form->items = (ITEM **)(form->items
					? realloc((void *)form->items, i)
					: malloc(i)))) {
			create_error_popup(toplevel, errno,
					"Can't create field");
			return(FALSE);
		}
		form->size += CHUNK;
	}
							/* allocate item */
	if (!(item = (ITEM *)malloc(sizeof(ITEM)))) {
		create_error_popup(toplevel, errno, "Can't create field");
		return(FALSE);
	}
	for (i=form->nitems-1; i >= nitem; i--)
		form->items[i+1] = form->items[i];
	form->items[nitem] = item;
	form->nitems++;
							/* defaults */
	if (nitem < form->nitems-1) {
		(void)memcpy(item, form->items[nitem+1], sizeof(ITEM));
		item->name	   = mystrdup(item->name);
		item->flagcode	   = mystrdup(item->flagcode);
		item->label	   = mystrdup(item->label);
		item->gray_if	   = mystrdup(item->gray_if);
		item->freeze_if	   = mystrdup(item->freeze_if);
		item->invisible_if = mystrdup(item->invisible_if);
		item->skip_if	   = mystrdup(item->skip_if);
		item->idefault	   = mystrdup(item->idefault);
		item->pattern	   = mystrdup(item->pattern);
		item->pressed	   = mystrdup(item->pressed);
		item->added	   = mystrdup(item->added);
		item->database	   = mystrdup(item->database);
		item->query	   = mystrdup(item->query);
	} else {
		mybzero((void *)item, sizeof(ITEM));
		item->type	   = IT_INPUT;
		item->selected	   = TRUE;
		item->labeljust	   = J_LEFT;
		item->inputjust	   = J_LEFT;
		item->column       = 1;
		item->minlen	   = 1;
		item->maxlen	   = 100;
		item->ch_xmax	   = 1;
		item->ch_ymax	   = 1;
		item->qsummary	   = TRUE;
		item->qlast	   = TRUE;
		item->x 	   = XSNAP(8) + form->xg;
		item->xs	   = XSNAP(form->xs - 32);
		item->xm	   = XSNAP(item->xs / 4);
		item->y 	   = YSNAP(8) + form->xg;
		item->ys	   = YSNAP(24) + form->yg;
		item->ym	   = item->ys;
		if (nitem) {
			prev = form->items[nitem-1];
			for (i=0; i < form->nitems; i++)
				if (form->items[i]->type == item->type) {
					prev = form->items[i];
					item->xs = prev->xs;
					item->ys = prev->xs;
					item->xm = prev->ym;
					item->ym = prev->ym;
					break;
				}
			item->labelfont = prev->labelfont;
			item->inputfont = prev->inputfont;
		}
	}
							/* move to bottom */
	for (i=0; i < form->nitems; i++) {
		j = form->items[i]->y + form->items[i]->ys;
		j = YSNAP(j + 8);
		if (i != nitem && j > item->y)
			item->y = j;
	}
							/* find unused column*/
	item->column = 0;
	if (item->type == IT_CHOICE || item->type == IT_FLAG)
		item->flagcode = 0;
	else {
		if (IN_DBASE(item->type)) {
			n = form->nitems;
			for (i=0; i < n; i++)
				for (j=0; j < n; j++) {
					t = form->items[j]->type;
					if (IN_DBASE(t) &&
					    form->items[j] != item &&
					    form->items[j]->column ==
					   		 item->column) {
						item->column++;
						break;
					}
				}
		}
		sprintf(buf, "item%d", (int)item->column);
		item->name = mystrdup(buf);
	}
	return(TRUE);
}


/*
 * delete a field from the form definition.
 */

void item_delete(
	FORM		*form,		/* describes form and all items in it*/
	int		nitem)		/* the current item, insert point */
{
	ITEM		*item = form->items[nitem];
	int		i;

	if (item->name)		free((void *)item->name);
	if (item->label)	free((void *)item->label);
	if (item->flagcode)	free((void *)item->flagcode);
	if (item->gray_if)	free((void *)item->gray_if);
	if (item->freeze_if)	free((void *)item->freeze_if);
	if (item->invisible_if)	free((void *)item->invisible_if);
	if (item->skip_if)	free((void *)item->skip_if);
	if (item->idefault)	free((void *)item->idefault);
	if (item->pattern)	free((void *)item->pattern);
	if (item->pressed)	free((void *)item->pressed);
	if (item->added)	free((void *)item->added);
	if (item->ch_xexpr)	free((void *)item->ch_xexpr);
	if (item->ch_yexpr)	free((void *)item->ch_yexpr);
	if (item->ch_bar)	free((void *)item->ch_bar);
	if (item->database)	free((void *)item->database);
	if (item->query)	free((void *)item->query);

	for (i=0; i < item->ch_ncomp; i++) {
		item->ch_curr = i;
		del_chart_component(item);
	}
	if (item->ch_comp)
		free((void *)item->ch_comp);
	free((void *)item);

	for (i=nitem; i < form->nitems-1; i++)
		form->items[i] = form->items[i+1];
	form->nitems--;
}


/*
 * clone a field from the form definition. This is used when the form is
 * cloned when the form editor starts up with the form that is also being
 * displayed (never operate on the displayed form directly).
 */

ITEM *item_clone(
	ITEM		*parent)	/* item to clone */
{
	ITEM		*item;		/* target item */
	int		i;

	if (!(item = (ITEM *)malloc(sizeof(ITEM)))) {
		create_error_popup(toplevel, errno, "Can't clone field");
		return(0);
	}
	*item = *parent;
	item->name	   = mystrdup(parent->name);
	item->label	   = mystrdup(parent->label);
	item->flagcode	   = mystrdup(parent->flagcode);
	item->gray_if	   = mystrdup(parent->gray_if);
	item->freeze_if	   = mystrdup(parent->freeze_if);
	item->invisible_if = mystrdup(parent->invisible_if);
	item->skip_if	   = mystrdup(parent->skip_if);
	item->idefault	   = mystrdup(parent->idefault);
	item->pattern	   = mystrdup(parent->pattern);
	item->pressed	   = mystrdup(parent->pressed);
	item->added	   = mystrdup(parent->added);
	item->ch_xexpr	   = mystrdup(parent->ch_xexpr);
	item->ch_yexpr	   = mystrdup(parent->ch_yexpr);
	item->database	   = mystrdup(parent->database);
	item->query	   = mystrdup(parent->query);
	item->ch_bar	   = 0;
	item->ch_nbars	   = 0;

	if (item->ch_comp) {
		item->ch_comp = (CHART*)malloc(item->ch_ncomp * sizeof(CHART));
		for (i=0; i < item->ch_ncomp; i++)
			clone_chart_component(&item->ch_comp[i],
					    &parent->ch_comp[i]);
	}
	return(item);
}

#endif /* GROK || PLANGROK */