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