1 /*-
2 * Copyright (c) 1996
3 * Rob Zimmermann. All rights reserved.
4 * Copyright (c) 1996
5 * Keith Bostic. All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10 #include "config.h"
11
12 #include <sys/cdefs.h>
13 #if 0
14 #ifndef lint
15 static const char sccsid[] = "Id: m_search.c,v 8.14 2003/11/05 17:10:00 skimo Exp (Berkeley) Date: 2003/11/05 17:10:00 ";
16 #endif /* not lint */
17 #else
18 __RCSID("$NetBSD: m_search.c,v 1.2 2014/01/26 21:43:45 christos Exp $");
19 #endif
20
21 #include <sys/queue.h>
22
23 /* context */
24 #include <X11/X.h>
25 #include <X11/Intrinsic.h>
26 #include <Xm/DialogS.h>
27 #include <Xm/Form.h>
28 #include <Xm/Label.h>
29 #include <Xm/PushBG.h>
30 #include <Xm/TextF.h>
31 #include <Xm/ToggleB.h>
32 #include <Xm/RowColumn.h>
33
34 #include <bitstring.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #undef LOCK_SUCCESS
39 #include "../common/common.h"
40 #include "../ipc/ip.h"
41 #include "m_motif.h"
42
43 extern int vi_ofd;
44
45
46 /* types */
47
48 typedef struct sds {
49 struct sds *next;
50 Widget shell;
51 } save_dialog;
52
53 static save_dialog *dialogs = NULL;
54
55 typedef struct {
56 String name;
57 void (*cb)();
58 } ButtonData;
59
60
61 /* globals and constants */
62
63 static String PatternWidget = "text";
64 static String pattern = NULL;
65
66 static optData search_toggles[] = {
67 { optToggle, "extended", NULL, VI_SEARCH_EXT },
68 { optToggle, "iclower", NULL, VI_SEARCH_ICL },
69 { optToggle, "ignorecase", NULL, VI_SEARCH_IC },
70 { optToggle, "literal", NULL, VI_SEARCH_LIT },
71 { optToggle, "searchincr", NULL, VI_SEARCH_INCR },
72 { optToggle, "wrapscan", NULL, VI_SEARCH_WR },
73 { optTerminator, },
74 };
75
76 static void done_func __P((Widget));
77 static void next_func __P((Widget));
78 static void prev_func __P((Widget));
79 static void search __P((Widget, int));
80
81 static ButtonData button_data[] = {
82 { "Next", next_func },
83 { "Previous", prev_func },
84 { "Cancel", done_func } /* always last */
85 };
86
87
88 /* Xt utilities */
89
90 #if defined(__STDC__)
get_child_widget(Widget parent,String name)91 static Widget get_child_widget( Widget parent, String name )
92 #else
93 static Widget get_child_widget( parent, name )
94 Widget parent;
95 String name;
96 #endif
97 {
98 char buffer[1024];
99
100 strcpy( buffer, "*" );
101 strcat( buffer, name );
102 return XtNameToWidget( parent, buffer );
103 }
104
105
106 /* sync the global state */
107
108 #if defined(__STDC__)
get_state(Widget w)109 static void get_state( Widget w )
110 #else
111 static void get_state( w )
112 Widget w;
113 #endif
114 {
115 #if defined(SelfTest)
116 int i;
117 #endif
118 Widget shell = w;
119
120 /* get all the data from the root of the widget tree */
121 while ( ! XtIsShell(shell) ) shell = XtParent(shell);
122
123 #if defined(SelfTest)
124 /* which flags? */
125 for (i=0; i<XtNumber(toggle_data); i++) {
126 if (( w = get_child_widget( shell, toggle_data[i].name )) != NULL ) {
127 XtVaGetValues( w, XmNset, &toggle_data[i].value, 0 );
128 }
129 }
130 #endif
131
132 /* what's the pattern? */
133 if (( w = get_child_widget( shell, PatternWidget )) != NULL ) {
134 if ( pattern != NULL ) XtFree( pattern );
135 pattern = XmTextFieldGetString( w );
136 }
137 }
138
139
140 /* Translate the user's actions into nvi commands */
141 /*
142 * next_func --
143 * Action for next button.
144 */
145 static void
next_func(Widget w)146 next_func(Widget w)
147 {
148 search(w, 0);
149 }
150
151 /*
152 * prev_func --
153 * Action for previous button.
154 */
155 static void
prev_func(Widget w)156 prev_func(Widget w)
157 {
158 search(w, VI_SEARCH_REV);
159 }
160
161 /*
162 * search --
163 * Perform the search.
164 */
165 static void
search(Widget w,int flags)166 search(Widget w, int flags)
167 {
168 IP_BUF ipb;
169 optData *opt;
170 Widget shell;
171
172 shell = w;
173 while ( ! XtIsShell(shell) ) shell = XtParent(shell);
174
175 /* Get current data from the root of the widget tree?
176 * Do it if we are a child of a dialog shell (assume we
177 * are a 'Find' dialog). Otherwise don't (we are the child
178 * of a menu and being invoked via accelerator)
179 */
180 if (XmIsDialogShell(shell))
181 get_state(w);
182
183 /* no pattern? probably, we haven't posted a search dialog yet.
184 * there ought to be a better thing to do here.
185 */
186 if ( pattern == NULL ) {
187 vi_info_message( w, "No previous string specified" );
188 return;
189 }
190
191 ipb.str1 = pattern;
192 ipb.len1 = strlen(pattern);
193
194 /* Initialize the search flags based on the buttons. */
195 ipb.val1 = flags;
196 for (opt = search_toggles; opt->kind != optTerminator; ++opt)
197 if (opt->value != NULL)
198 ipb.val1 |= opt->flags;
199
200 ipb.code = VI_C_SEARCH;
201 vi_send(vi_ofd, "a1", &ipb);
202 }
203
204 #if defined(__STDC__)
done_func(Widget w)205 static void done_func( Widget w )
206 #else
207 static void done_func( w )
208 Widget w;
209 #endif
210 {
211 save_dialog *ptr;
212
213 #if defined(SelfTest)
214 puts( XtName(w) );
215 #endif
216
217 while ( ! XtIsShell(w) ) w = XtParent(w);
218 XtPopdown( w );
219
220 /* save it for later */
221 ptr = (save_dialog *) malloc( sizeof(save_dialog) );
222 ptr->next = dialogs;
223 ptr->shell = w;
224 dialogs = ptr;
225 }
226
227
228 /* create a set of push buttons */
229
230 #define SpacingRatio 4 /* 3:1 button to spaces */
231
232 #if defined(__STDC__)
create_push_buttons(Widget parent,ButtonData * data,int count)233 static Widget create_push_buttons( Widget parent,
234 ButtonData *data,
235 int count
236 )
237 #else
238 static Widget create_push_buttons( parent, data, count )
239 Widget parent;
240 ButtonData *data;
241 int count;
242 #endif
243 {
244 Widget w, form;
245 int pos = 1, base;
246
247 base = SpacingRatio*count + 1;
248 form = XtVaCreateManagedWidget( "buttons",
249 xmFormWidgetClass,
250 parent,
251 XmNleftAttachment, XmATTACH_FORM,
252 XmNrightAttachment, XmATTACH_FORM,
253 XmNfractionBase, base,
254 XmNshadowType, XmSHADOW_ETCHED_IN,
255 XmNshadowThickness, 2,
256 XmNverticalSpacing, 4,
257 0
258 );
259
260 while ( count-- > 0 ) {
261 w = XtVaCreateManagedWidget(data->name,
262 xmPushButtonGadgetClass,
263 form,
264 XmNtopAttachment, XmATTACH_FORM,
265 XmNbottomAttachment,XmATTACH_FORM,
266 XmNleftAttachment, XmATTACH_POSITION,
267 XmNleftPosition, pos,
268 XmNshowAsDefault, False,
269 XmNrightAttachment, XmATTACH_POSITION,
270 XmNrightPosition, pos+SpacingRatio-1,
271 0
272 );
273 XtAddCallback( w, XmNactivateCallback, data->cb, 0 );
274 pos += SpacingRatio;
275 data++;
276 }
277
278 /* last button is 'cancel' */
279 XtVaSetValues( XtParent(form), XmNcancelButton, w, 0 );
280
281 return form;
282 }
283
284
285 /* create a set of check boxes */
286
287 #if defined(SelfTest)
288
289 #if defined(__STDC__)
create_check_boxes(Widget parent,ToggleData * toggles,int count)290 static Widget create_check_boxes( Widget parent,
291 ToggleData *toggles,
292 int count
293 )
294 #else
295 static Widget create_check_boxes( parent, toggles, count )
296 Widget parent;
297 ToggleData *toggles;
298 int count;
299 #endif
300 {
301 Widget form;
302 int pos = 1, base;
303
304 base = SpacingRatio*count +1;
305 form = XtVaCreateManagedWidget( "toggles",
306 xmFormWidgetClass,
307 parent,
308 XmNleftAttachment, XmATTACH_FORM,
309 XmNrightAttachment, XmATTACH_FORM,
310 XmNfractionBase, base,
311 XmNverticalSpacing, 4,
312 0
313 );
314
315 while ( count-- > 0 ) {
316 XtVaCreateManagedWidget(toggles->name,
317 xmToggleButtonWidgetClass,
318 form,
319 XmNtopAttachment, XmATTACH_FORM,
320 XmNbottomAttachment, XmATTACH_FORM,
321 XmNleftAttachment, XmATTACH_POSITION,
322 XmNleftPosition, pos,
323 XmNrightAttachment, XmATTACH_POSITION,
324 XmNrightPosition, pos+SpacingRatio-1,
325 0
326 );
327 pos += SpacingRatio;
328 ++toggles;
329 }
330
331 return form;
332 }
333
334 #endif
335
336
337 /* Routines to handle the text field widget */
338
339 /* when the user hits 'CR' in a text widget, fire the default pushbutton */
340 #if defined(__STDC__)
text_cr(Widget w,void * ptr,void * ptr2)341 static void text_cr( Widget w, void *ptr, void *ptr2 )
342 #else
343 static void text_cr( w, ptr, ptr2 )
344 Widget w;
345 void *ptr;
346 void *ptr2;
347 #endif
348 {
349 next_func( w );
350 }
351
352
353 #ifdef notdef
354 /*
355 * when the user hits any other character, if we are doing incremental
356 * search, send the updated string to nvi
357 *
358 * XXX
359 * I don't currently see any way to make this work -- incremental search
360 * is going to be really nasty. What makes it worse is that the dialog
361 * box almost certainly obscured a chunk of the text file, so there's no
362 * way to use it even if it works.
363 */
364 #if defined(__STDC__)
value_changed(Widget w,void * ptr,void * ptr2)365 static void value_changed( Widget w, void *ptr, void *ptr2 )
366 #else
367 static void value_changed( w, ptr, ptr2 )
368 Widget w;
369 void *ptr;
370 void *ptr2;
371 #endif
372 {
373 /* get all the data from the root of the widget tree */
374 get_state( w );
375
376 /* send it along? */
377 #if defined(SelfTest)
378 if ( incremental_search ) send_command( w );
379 #else
380 if ( __vi_incremental_search() ) send_command( w );
381 #endif
382 }
383 #endif /* notdef */
384
385
386 /* Draw and display a dialog the describes nvi search capability */
387
388 #if defined(__STDC__)
create_search_dialog(Widget parent,String title)389 static Widget create_search_dialog( Widget parent, String title )
390 #else
391 static Widget create_search_dialog( parent, title )
392 Widget parent;
393 String title;
394 #endif
395 {
396 Widget box, form, label, text, checks, buttons, form2;
397 save_dialog *ptr;
398
399 /* use an existing one? */
400 if ( dialogs != NULL ) {
401 box = dialogs->shell;
402 ptr = dialogs->next;
403 free( dialogs );
404 dialogs = ptr;
405 return box;
406 }
407
408 box = XtVaCreatePopupShell( title,
409 xmDialogShellWidgetClass,
410 parent,
411 XmNtitle, title,
412 XmNallowShellResize, False,
413 0
414 );
415
416 form = XtVaCreateWidget( "form",
417 xmFormWidgetClass,
418 box,
419 XmNverticalSpacing, 4,
420 XmNhorizontalSpacing, 4,
421 0
422 );
423
424 form2 = XtVaCreateManagedWidget( "form",
425 xmFormWidgetClass,
426 form,
427 XmNtopAttachment, XmATTACH_FORM,
428 XmNleftAttachment, XmATTACH_FORM,
429 XmNrightAttachment, XmATTACH_FORM,
430 0
431 );
432
433 label = XtVaCreateManagedWidget( "Pattern:",
434 xmLabelWidgetClass,
435 form2,
436 XmNtopAttachment, XmATTACH_FORM,
437 XmNbottomAttachment,XmATTACH_FORM,
438 XmNleftAttachment, XmATTACH_FORM,
439 0
440 );
441
442 text = XtVaCreateManagedWidget( PatternWidget,
443 xmTextFieldWidgetClass,
444 form2,
445 XmNtopAttachment, XmATTACH_FORM,
446 XmNbottomAttachment,XmATTACH_FORM,
447 XmNleftAttachment, XmATTACH_WIDGET,
448 XmNleftWidget, label,
449 XmNrightAttachment, XmATTACH_FORM,
450 0
451 );
452 #ifdef notdef
453 XtAddCallback( text, XmNvalueChangedCallback, value_changed, 0 );
454 #endif
455 XtAddCallback( text, XmNactivateCallback, text_cr, 0 );
456
457 buttons = create_push_buttons( form, button_data, XtNumber(button_data) );
458 XtVaSetValues( buttons,
459 XmNbottomAttachment, XmATTACH_FORM,
460 0
461 );
462
463 #if defined(SelfTest)
464 checks = create_check_boxes( form, toggle_data, XtNumber(toggle_data) );
465 #else
466 checks = (Widget) __vi_create_search_toggles( form, search_toggles );
467 #endif
468 XtVaSetValues( checks,
469 XmNtopAttachment, XmATTACH_WIDGET,
470 XmNtopWidget, form2,
471 XmNbottomAttachment, XmATTACH_WIDGET,
472 XmNbottomWidget, buttons,
473 0
474 );
475
476 XtManageChild( form );
477 return box;
478 }
479
480
481 /* Module interface to the outside world
482 *
483 * xip_show_search_dialog( parent, title )
484 * pops up a search dialog
485 *
486 * xip_next_search()
487 * simulates a 'next' assuming that a search has been done
488 */
489
490 #if defined(__STDC__)
__vi_show_search_dialog(Widget parent,String title)491 void __vi_show_search_dialog( Widget parent, String title )
492 #else
493 void __vi_show_search_dialog( parent, data, cbs )
494 Widget parent;
495 String title;
496 #endif
497 {
498 Widget db = create_search_dialog( parent, title );
499 Dimension height;
500
501 /* we can handle getting taller and wider or narrower, but not shorter */
502 XtVaGetValues( db, XmNheight, &height, 0 );
503 XtVaSetValues( db, XmNmaxHeight, height, XmNminHeight, height, 0 );
504
505 /* post the dialog */
506 XtPopup( db, XtGrabNone );
507
508 /* request initial focus to the text widget */
509 XmProcessTraversal( get_child_widget( db, PatternWidget ),
510 XmTRAVERSE_CURRENT
511 );
512 }
513
514
515 /*
516 * __vi_search --
517 *
518 * PUBLIC: void __vi_search __P((Widget));
519 */
520 void
__vi_search(Widget w)521 __vi_search(Widget w)
522 {
523 next_func( w );
524 }
525
526
527 #if defined(SelfTest)
528
529 #if defined(__STDC__)
show_search(Widget w,XtPointer data,XtPointer cbs)530 static void show_search( Widget w, XtPointer data, XtPointer cbs )
531 #else
532 static void show_search( w, data, cbs )
533 Widget w;
534 XtPointer data;
535 XtPointer cbs;
536 #endif
537 {
538 __vi_show_search_dialog( data, "Search" );
539 }
540
main(int argc,char * argv[])541 main( int argc, char *argv[] )
542 {
543 XtAppContext ctx;
544 Widget top_level, rc, button;
545 extern exit();
546
547 /* create a top-level shell for the window manager */
548 top_level = XtVaAppInitialize( &ctx,
549 argv[0],
550 NULL, 0, /* options */
551 (ArgcType) &argc,
552 argv, /* might get modified */
553 NULL,
554 NULL
555 );
556
557 rc = XtVaCreateManagedWidget( "rc",
558 xmRowColumnWidgetClass,
559 top_level,
560 0
561 );
562
563 button = XtVaCreateManagedWidget( "Pop up search dialog",
564 xmPushButtonGadgetClass,
565 rc,
566 0
567 );
568 XtAddCallback( button, XmNactivateCallback, show_search, rc );
569
570 button = XtVaCreateManagedWidget( "Quit",
571 xmPushButtonGadgetClass,
572 rc,
573 0
574 );
575 XtAddCallback( button, XmNactivateCallback, exit, 0 );
576
577 XtRealizeWidget(top_level);
578 XtAppMainLoop(ctx);
579 }
580 #endif
581