/* Written by Paula Ferguson.
* Copyright 1994, O'Reilly & Associates, Inc.
* Permission to use, copy, and modify this program without
* restriction is hereby granted, as long as this copyright
* notice appears in each copy of the program source code.
* This program is freely distributable without licensing fees and
* is provided without guarantee or warrantee expressed or implied.
* This program is -not- in the public domain.
*/
/* editor_help.c -- create an editor application that contains drop sites
* that understand file data. A file can be dragged from another
* application and dropped in the text entry area or the filename status
* area. The filename status area provides drop site help information.
*/
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/LabelG.h>
#include <Xm/PushBG.h>
#include <Xm/RowColumn.h>
#include <Xm/MainW.h>
#include <Xm/Form.h>
#include <Xm/MessageB.h>
#include <Xm/FileSB.h>
#include <Xm/SeparatoG.h>
#include <Xm/DragDrop.h>
#include <X11/Xos.h>
#include
#include
#include
#define FILE_OPEN 0
#define FILE_SAVE 1
#define FILE_EXIT 2
#define EDIT_CUT 0
#define EDIT_COPY 1
#define EDIT_PASTE 2
#define EDIT_CLEAR 3
#define SEARCH_FIND_NEXT 0
#define SEARCH_SHOW_ALL 1
#define SEARCH_REPLACE 2
#define SEARCH_CLEAR 3
/* global variables */
void (*drop_proc) ();
Widget text_edit, search_text, replace_text, text_output;
Widget toplevel, file_label;
char *help_str =
"This drop action will copy the file\n\
into the text entry area and display\n\
the filename in the status area. To\n\
accept the drop, press the OK button;\n\
otherwise, press Cancel.";
int main(argc, argv)
int argc;
char *argv[];
{
XtAppContext app_context;
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME;
Widget main_window, menubar, form, search_panel;
Widget sep1, sep2;
void file_cb(), edit_cb(), search_cb();
Arg args[10];
int n = 0;
XmString open_, save, exit, exit_acc, file, edit, cut,
clear, copy, paste, search, next, find, replace;
Cardinal numImportTargets;
Atom *importTargets, *newTargets;
Atom importList[2];
void HandleDropLabel(), HandleDropText();
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app_context, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
dpy = XtDisplay (toplevel);
FILE_CONTENTS = XmInternAtom (dpy, "FILE_CONTENTS", False);
FILE_NAME = XmInternAtom (dpy, "FILE_NAME", False);
main_window = XtVaCreateWidget ("main_window",
xmMainWindowWidgetClass, toplevel, NULL);
/* Create a simple MenuBar that contains three menus */
file = XmStringCreateLocalized ("File");
edit = XmStringCreateLocalized ("Edit");
search = XmStringCreateLocalized ("Search");
menubar = XmVaCreateSimpleMenuBar (main_window, "menubar",
XmVaCASCADEBUTTON, file, 'F',
XmVaCASCADEBUTTON, edit, 'E',
XmVaCASCADEBUTTON, search, 'S',
NULL);
XmStringFree (file);
XmStringFree (edit);
XmStringFree (search);
/* First menu is the File menu -- callback is file_cb() */
open_ = XmStringCreateLocalized ("Open...");
save = XmStringCreateLocalized ("Save...");
exit = XmStringCreateLocalized ("Exit");
exit_acc = XmStringCreateLocalized ("Ctrl+C");
XmVaCreateSimplePulldownMenu (menubar, "file_menu", 0, file_cb,
XmVaPUSHBUTTON, open_, 'O', NULL, NULL,
XmVaPUSHBUTTON, save, 'S', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, exit, 'x', "Ctrlc", exit_acc,
NULL);
XmStringFree (open_);
XmStringFree (save);
XmStringFree (exit);
XmStringFree (exit_acc);
/* ...create the "Edit" menu -- callback is edit_cb() */
cut = XmStringCreateLocalized ("Cut");
copy = XmStringCreateLocalized ("Copy");
clear = XmStringCreateLocalized ("Clear");
paste = XmStringCreateLocalized ("Paste");
XmVaCreateSimplePulldownMenu (menubar, "edit_menu", 1, edit_cb,
XmVaPUSHBUTTON, cut, 't', NULL, NULL,
XmVaPUSHBUTTON, copy, 'C', NULL, NULL,
XmVaPUSHBUTTON, paste, 'P', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, clear, 'l', NULL, NULL,
NULL);
XmStringFree (cut);
XmStringFree (copy);
XmStringFree (paste);
/* create the "Search" menu -- callback is search_cb() */
next = XmStringCreateLocalized ("Find Next");
find = XmStringCreateLocalized ("Show All");
replace = XmStringCreateLocalized ("Replace Text");
XmVaCreateSimplePulldownMenu (menubar, "search_menu", 2, search_cb,
XmVaPUSHBUTTON, next, 'N', NULL, NULL,
XmVaPUSHBUTTON, find, 'A', NULL, NULL,
XmVaPUSHBUTTON, replace, 'R', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, clear, 'C', NULL, NULL,
NULL);
XmStringFree (next);
XmStringFree (find);
XmStringFree (replace);
XmStringFree (clear);
XtManageChild (menubar);
/* create a form work are */
form = XtVaCreateWidget ("form",
xmFormWidgetClass, main_window, NULL);
/* create horizontal RowColumn inside the form */
search_panel = XtVaCreateWidget ("search_panel",
xmRowColumnWidgetClass, form,
XmNorientation, XmHORIZONTAL,
XmNpacking, XmPACK_TIGHT,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL);
/* Create two TextField widgets with Labels... */
XtVaCreateManagedWidget ("Search Pattern:",
xmLabelGadgetClass, search_panel, NULL);
search_text = XtVaCreateManagedWidget ("search_text",
xmTextFieldWidgetClass, search_panel, NULL);
XtVaCreateManagedWidget (" Replace Pattern:",
xmLabelGadgetClass, search_panel, NULL);
replace_text = XtVaCreateManagedWidget ("replace_text",
xmTextFieldWidgetClass, search_panel, NULL);
XtManageChild (search_panel);
text_output = XtVaCreateManagedWidget ("text_output",
xmTextFieldWidgetClass, form,
XmNeditable, False,
XmNcursorPositionVisible, False,
XmNshadowThickness, 0,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
NULL);
sep2 = XtVaCreateManagedWidget ("sep2",
xmSeparatorGadgetClass, form,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, text_output,
NULL);
/* create file status area */
file_label = XtVaCreateManagedWidget ("Filename:",
xmLabelGadgetClass, form,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, sep2,
NULL);
/* register the file status label as a drop site */
n = 0;
importList[0] = FILE_CONTENTS;
importList[1] = FILE_NAME;
XtSetArg (args[n], XmNimportTargets, importList); n++;
XtSetArg (args[n], XmNnumImportTargets, XtNumber (importList)); n++;
XtSetArg (args[n], XmNdropSiteOperations, XmDROP_COPY); n++;
XtSetArg (args[n], XmNdropProc, HandleDropLabel); n++;
XmDropSiteRegister (file_label, args, n);
sep1 = XtVaCreateManagedWidget ("sep1",
xmSeparatorGadgetClass, form,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, file_label,
NULL);
/* create text entry area */
n = 0;
XtSetArg (args[n], XmNrows, 10); n++;
XtSetArg (args[n], XmNcolumns, 80); n++;
XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNtopWidget, search_panel); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNbottomWidget, sep1); n++;
text_edit = XmCreateScrolledText (form, "text_edit", args, n);
XtManageChild (text_edit);
/* retrieve drop site info so that we can modify it */
n = 0;
XtSetArg (args[n], XmNimportTargets, &importTargets); n++;
XtSetArg (args[n], XmNnumImportTargets, &numImportTargets); n++;
XtSetArg (args[n], XmNdropProc, &drop_proc); n++;
XmDropSiteRetrieve (text_edit, args, n);
/* add FILE_CONTENTS and FILE_NAME to the list of targets */
newTargets = (Atom *) XtMalloc (sizeof (Atom) * (numImportTargets + 2));
for (n = 0; n < numImportTargets; n++)
newTargets[n] = importTargets[n];
newTargets[n] = FILE_CONTENTS;
newTargets[n+1] = FILE_NAME;
/* update the drop site */
n = 0;
XtSetArg (args[n], XmNimportTargets, newTargets); n++;
XtSetArg (args[n], XmNnumImportTargets, numImportTargets + 2); n++;
XtSetArg (args[n], XmNdropProc, HandleDropText); n++;
XmDropSiteUpdate (text_edit, args, n);
XtManageChild (form);
XtManageChild (main_window);
XtRealizeWidget (toplevel);
XtAppMainLoop (app_context);
}
/* HandleDropLabel() -- start the data transfer when data is dropped in
* the filename status area.
*/
void
HandleDropLabel(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME;
XmDropProcCallback DropData;
XmDropTransferEntryRec transferEntries[2];
XmDropTransferEntry transferList;
Arg args[10];
int n, i;
Widget dc;
Cardinal numExportTargets;
Atom *exportTargets;
Boolean file_name = False;
static XmDropProcCallbackStruct client;
static Widget dialog = NULL;
XmString message;
void HandleDropOK(), HandleDropCancel();
void TransferProc();
/* intern the Atoms for data targets */
dpy = XtDisplay (toplevel);
FILE_CONTENTS = XmInternAtom (dpy, "FILE_CONTENTS", False);
FILE_NAME = XmInternAtom (dpy, "FILE_NAME", False);
DropData = (XmDropProcCallback) call_data;
dc = DropData->dragContext;
/* retrieve the data targets and search for FILE_NAME */
n = 0;
XtSetArg (args[n], XmNexportTargets, &exportTargets); n++;
XtSetArg (args[n], XmNnumExportTargets, &numExportTargets); n++;
XtGetValues (dc, args, n);
for (i = 0; i < numExportTargets; i++) {
if (exportTargets[i] == FILE_NAME) {
file_name = True;
break;
}
}
/* if one of the targets is not FILE_NAME, transfer fails */
if (!file_name) {
n = 0;
XtSetArg (args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
XtSetArg (args[n], XmNnumDropTransfers, 0); n++;
}
/* check if the user has requested help */
else if (DropData->dropAction == XmDROP_HELP) {
/* create a dialog if it doesn't already exist */
if (!dialog) {
n = 0;
message = XmStringCreateLtoR (help_str, XmFONTLIST_DEFAULT_TAG);
XtSetArg (args[n], XmNdialogStyle,
XmDIALOG_FULL_APPLICATION_MODAL); n++;
XtSetArg (args[n], XmNtitle, "Drop Help"); n++;
XtSetArg (args[n], XmNmessageString, message); n++;
dialog = XmCreateInformationDialog (toplevel, "help", args, n);
XmStringFree (message);
XtUnmanageChild (XmMessageBoxGetChild
(dialog, XmDIALOG_HELP_BUTTON));
XtAddCallback (dialog, XmNokCallback, HandleDropOK,
(XtPointer) &client);
XtAddCallback (dialog, XmNcancelCallback, HandleDropCancel,
(XtPointer) &client);
}
/* set up the callback structure for when the user proceeds
* with the drop and pass it as client data to the callbacks
* for the buttons.
*/
client.dragContext = dc;
client.x = DropData->x;
client.y = DropData->y;
client.dropSiteStatus = DropData->dropSiteStatus;
client.operation = DropData->operation;
client.operations = DropData->operations;
XtManageChild (dialog);
return;
}
else if (DropData->operation != XmDROP_COPY) {
/* if the operation is not a copy, the transfer fails */
n = 0;
XtSetArg (args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
XtSetArg (args[n], XmNnumDropTransfers, 0); n++;
}
else {
/* set up transfer requests since this is a normal drop */
n = 0;
transferEntries[0].target = FILE_CONTENTS;
transferEntries[0].client_data = (XtPointer) text_edit;
transferEntries[1].target = FILE_NAME;
transferEntries[1].client_data = (XtPointer) file_label;
transferList = transferEntries;
XtSetArg (args[n], XmNdropTransfers, transferEntries); n++;
XtSetArg (args[n], XmNnumDropTransfers,
XtNumber (transferEntries)); n++;
XtSetArg (args[n], XmNtransferProc, TransferProc); n++;
}
XmDropTransferStart (dc, args, n);
}
/* HandleDropOK() -- callback routine for OK button in drop site help
* dialog that processes the drop as normal.
*/
void
HandleDropOK(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME;
XmDropProcCallbackStruct *DropData;
XmDropTransferEntryRec transferEntries[2];
XmDropTransferEntry transferList;
Arg args[10];
int n;
Widget dc;
void TransferProc();
/* intern the Atoms for data targets */
dpy = XtDisplay (toplevel);
FILE_CONTENTS = XmInternAtom (dpy, "FILE_CONTENTS", False);
FILE_NAME = XmInternAtom (dpy, "FILE_NAME", False);
/* get the callback structure passed via client data */
DropData = (XmDropProcCallbackStruct *) client_data;
dc = DropData->dragContext;
n = 0;
/* if operation is not a copy, the transfer fails */
if (DropData->operation != XmDROP_COPY) {
XtSetArg (args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
XtSetArg (args[n], XmNnumDropTransfers, 0); n++;
}
else {
/* set up transfer requests to process data transfer */
transferEntries[0].target = FILE_CONTENTS;
transferEntries[0].client_data = (XtPointer) text_edit;
transferEntries[1].target = FILE_NAME;
transferEntries[1].client_data = (XtPointer) file_label;
transferList = transferEntries;
XtSetArg (args[n], XmNdropTransfers, transferEntries); n++;
XtSetArg (args[n], XmNnumDropTransfers,
XtNumber (transferEntries)); n++;
XtSetArg (args[n], XmNtransferProc, TransferProc); n++;
}
XmDropTransferStart (dc, args, n);
}
/* HandleDropCancel() -- callback routine for Cancel button in drop site
* help dialog that cancels the transfer.
*/
void
HandleDropCancel(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
XmDropProcCallbackStruct *DropData;
Arg args[10];
int n;
Widget dc;
/* get the callback structures passed via client data */
DropData = (XmDropProcCallbackStruct *) client_data;
dc = DropData->dragContext;
/* user has canceled the transfer, so it fails */
n = 0;
XtSetArg (args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
XtSetArg (args[n], XmNnumDropTransfers, 0); n++;
XmDropTransferStart (dc, args, n);
}
/* HandleDropText() -- start the data transfer when data is dropped in
* the text entry area.
*/
void
HandleDropText(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME;
XmDropProcCallback DropData;
XmDropTransferEntryRec transferEntries[2];
XmDropTransferEntry transferList;
Arg args[10];
int n, i;
Widget dc;
Cardinal numExportTargets;
Atom *exportTargets;
Boolean file_contents = False;
void TransferProc();
/* intern the Atoms for data targets */
dpy = XtDisplay (toplevel);
FILE_CONTENTS = XmInternAtom (dpy, "FILE_CONTENTS", False);
FILE_NAME = XmInternAtom (dpy, "FILE_NAME", False);
DropData = (XmDropProcCallback) call_data;
dc = DropData->dragContext;
/* retrieve the data targets and search for FILE_CONTENTS */
n = 0;
XtSetArg (args[n], XmNexportTargets, &exportTargets); n++;
XtSetArg (args[n], XmNnumExportTargets, &numExportTargets); n++;
XtGetValues (dc, args, n);
for (i = 0; i < numExportTargets; i++) {
if (exportTargets[i] == FILE_CONTENTS) {
file_contents = True;
break;
}
}
if (file_contents) {
/* make sure we have a drop that is a copy operation.
* if not, set the status to failure.
*/
n = 0;
if ((DropData->dropAction != XmDROP) ||
(DropData->operation != XmDROP_COPY)) {
XtSetArg (args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
XtSetArg (args[n], XmNnumDropTransfers, 0); n++;
}
else {
/* set up transfer requests for drop site */
transferEntries[0].target = FILE_CONTENTS;
transferEntries[0].client_data = (XtPointer) text_edit;
transferEntries[1].target = FILE_NAME;
transferEntries[1].client_data = (XtPointer) file_label;
transferList = transferEntries;
XtSetArg (args[n], XmNdropTransfers, transferEntries); n++;
XtSetArg (args[n], XmNnumDropTransfers,
XtNumber (transferEntries)); n++;
XtSetArg (args[n], XmNtransferProc, TransferProc); n++;
}
XmDropTransferStart (dc, args, n);
}
else
(*drop_proc) (widget, client_data, call_data);
}
/* TransferProc() -- handle data transfer of converted data from drag
* source to drop site.
*/
void
TransferProc(widget, client_data, seltype, type, value, length, format)
Widget widget;
XtPointer client_data;
Atom *seltype;
Atom *type;
XtPointer value;
unsigned long *length;
int format;
{
Display *dpy;
Atom FILE_CONTENTS, FILE_NAME;
Widget w;
XmString string;
char label[256];
/*char *label[256];*/
/* intern the Atoms for data targets */
dpy = XtDisplay (toplevel);
FILE_CONTENTS = XmInternAtom (dpy, "FILE_CONTENTS", False);
FILE_NAME = XmInternAtom (dpy, "FILE_NAME", False);
w = (Widget) client_data;
if (*type == FILE_CONTENTS)
XmTextSetString (w, value);
else if (*type == FILE_NAME) {
sprintf (label, "Filename: %s", value);
string = XmStringCreateLocalized (label);
XtVaSetValues (w, XmNlabelString, string, NULL);
XmStringFree (string);
}
}
/* callback routine for "OK" button in FileSelectionDialogs */
void
file_select_cb(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
char buf[256], *filename, *text;
struct stat statb;
long len;
FILE *fp;
int reason = (int) client_data;
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *) call_data;
if (!XmStringGetLtoR (cbs->value, XmFONTLIST_DEFAULT_TAG, &filename))
return; /* must have been an internal error */
if (*filename == NULL) {
XtFree (filename);
XBell (XtDisplay (text_edit), 50);
XmTextSetString (text_output, "Choose a file.");
return; /* nothing typed */
}
if (reason == FILE_SAVE) {
if (!(fp = fopen (filename, "w"))) {
perror (filename);
sprintf (buf, "Can't save to %s.", filename);
XmTextSetString (text_output, buf);
XtFree (filename);
return;
}
/* saving -- get text from Text widget... */
text = XmTextGetString (text_edit);
len = XmTextGetLastPosition (text_edit);
/* write it to file (check for error) */
if (fwrite (text, sizeof (char), len, fp) != len)
strcpy (buf, "Warning: did not write entire file!");
else {
/* make sure a newline terminates file */
if (text[len-1] != '\n')
fputc ('\n', fp);
sprintf (buf, "Saved %ld bytes to %s.", len, filename);
}
}
else { /* reason == FILE_OPEN */
/* make sure the file is a regular text file and open it */
if (stat (filename, &statb) == -1 ||
(statb.st_mode & S_IFMT) != S_IFREG ||
!(fp = fopen (filename, "r"))) {
perror (filename);
sprintf (buf, "Can't read %s.", filename);
XmTextSetString (text_output, buf);
XtFree (filename);
return;
}
/* put the contents of the file in the Text widget by
* allocating enough space for the entire file, reading the
* file into the space, and using XmTextSetString() to show
* the file.
*/
len = statb.st_size;
if (!(text = XtMalloc ((unsigned)(len+1)))) /* +1 for NULL */
sprintf (buf, "%s: XtMalloc(%ld) failed", len, filename);
else {
if (fread (text, sizeof (char), len, fp) != len)
sprintf (buf, "Warning: did not read entire file!");
else
sprintf (buf, "Loaded %ld bytes from %s.", len, filename);
text[len] = 0; /* NULL-terminate */
XmTextSetString (text_edit, text);
}
}
XmTextSetString (text_output, buf); /* purge output message */
/* free all allocated space. */
XtFree (text);
XtFree (filename);
fclose (fp);
XtUnmanageChild (dialog);
}
/* callback routine for "Cancel" button in FileSelectionDialogs */
void
popdown_cb (w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
XtUnmanageChild (w);
}
/* a menu item from the "File" pulldown menu was selected */
void
file_cb(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
static Widget open_dialog, save_dialog;
Widget dialog = NULL;
XmString button, title;
int reason = (int) client_data;
if (reason == FILE_EXIT)
exit (0);
XmTextSetString (text_output, NULL); /* clear message area */
if (reason == FILE_OPEN && open_dialog)
dialog = open_dialog;
else if (reason == FILE_SAVE && save_dialog)
dialog = save_dialog;
if (dialog) {
XtManageChild (dialog);
/* make sure that dialog is raised to top of window stack */
XMapRaised (XtDisplay (dialog), XtWindow (XtParent (dialog)));
return;
}
dialog = XmCreateFileSelectionDialog (text_edit, "Files", NULL, 0);
XtAddCallback (dialog, XmNcancelCallback, popdown_cb, NULL);
XtAddCallback (dialog, XmNokCallback, file_select_cb, reason);
if (reason == FILE_OPEN) {
button = XmStringCreateLocalized ("Open");
title = XmStringCreateLocalized ("Open File");
open_dialog = dialog;
}
else { /* reason == FILE_SAVE */
button = XmStringCreateLocalized ("Save");
title = XmStringCreateLocalized ("Save File");
save_dialog = dialog;
}
XtVaSetValues (dialog,
XmNokLabelString, button,
XmNdialogTitle, title,
NULL);
XmStringFree (button);
XmStringFree (title);
XtManageChild (dialog);
}
/* a menu item from the "Search" pulldown menu was selected */
void
search_cb(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
char *search_pat, *p, *string, *new_pat, buf[256];
XmTextPosition pos = 0;
int len, nfound = 0;
int search_len, pattern_len;
int reason = (int) client_data;
Boolean found = False;
XmTextSetString (text_output, NULL); /* clear message area */
if (reason == SEARCH_CLEAR) {
pos = XmTextGetLastPosition (text_edit);
XmTextSetHighlight (text_edit, 0, pos, XmHIGHLIGHT_NORMAL);
return;
}
if (!(string = XmTextGetString (text_edit)) || !*string) {
XmTextSetString (text_output, "No text to search.");
return;
}
if (!(search_pat = XmTextGetString (search_text)) || !*search_pat) {
XmTextSetString (text_output, "Specify a search pattern.");
XtFree (string);
return;
}
new_pat = XmTextGetString (replace_text);
search_len = strlen (search_pat);
pattern_len = strlen (new_pat);
if (reason == SEARCH_FIND_NEXT) {
pos = XmTextGetCursorPosition (text_edit) + 1;
found = XmTextFindString (text_edit, pos, search_pat,
XmTEXT_FORWARD, &pos);
if (!found)
found = XmTextFindString (text_edit, 0, search_pat,
XmTEXT_FORWARD, &pos);
if (found)
nfound++;
}
else { /* reason == SEARCH_SHOW_ALL || reason == SEARCH_REPLACE */
do {
found = XmTextFindString (text_edit, pos, search_pat,
XmTEXT_FORWARD, &pos);
if (found) {
nfound++;
if (reason == SEARCH_SHOW_ALL)
XmTextSetHighlight (text_edit, pos, pos + search_len,
XmHIGHLIGHT_SELECTED);
else
XmTextReplace (text_edit, pos, pos + search_len, new_pat);
pos++;
}
}
while (found);
}
if (nfound == 0)
XmTextSetString (text_output, "Pattern not found.");
else {
switch (reason) {
case SEARCH_FIND_NEXT :
sprintf (buf, "Pattern found at position %ld.", pos);
XmTextSetInsertionPosition (text_edit, pos);
break;
case SEARCH_SHOW_ALL :
sprintf (buf, "Found %d occurrences.", nfound);
break;
case SEARCH_REPLACE :
sprintf (buf, "Made %d replacements.", nfound);
break;
}
XmTextSetString (text_output, buf);
}
XtFree (string);
XtFree (search_pat);
XtFree (new_pat);
}
/* the callback routine for the items in the edit menu */
void
edit_cb(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Boolean result = True;
int reason = (int) client_data;
XEvent *event = ((XmPushButtonCallbackStruct *) call_data)->event;
Time when;
XmTextSetString (text_output, NULL); /* clear message area */
if (event != NULL &&
reason == EDIT_CUT || reason == EDIT_COPY || reason == EDIT_CLEAR) {
switch (event->type) {
case ButtonRelease :
when = event->xbutton.time;
break;
case KeyRelease :
when = event->xkey.time;
break;
default:
when = CurrentTime;
break;
}
}
switch (reason) {
case EDIT_CUT :
result = XmTextCut (text_edit, when);
break;
case EDIT_COPY :
result = XmTextCopy (text_edit, when);
break;
case EDIT_PASTE :
result = XmTextPaste (text_edit);
XmTextClearSelection (text_edit, when);
break;
case EDIT_CLEAR :
XmTextClearSelection (text_edit, when);
break;
}
if (result == False)
XmTextSetString (text_output, "There is no selection.");
}