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__) 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__) 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 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 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 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__) 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__) 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__) 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__) 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__) 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__) 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__) 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 521 __vi_search(Widget w) 522 { 523 next_func( w ); 524 } 525 526 527 #if defined(SelfTest) 528 529 #if defined(__STDC__) 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 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