/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* HISTORY
*/
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: text.c /main/7 1996/10/30 10:28:07 cde-osf $"
#endif
#endif
#include "text.h"
/* ===================================================================
* The OK callback for FSB. Check the selected file can be opened.
* If so, close the old file, read the new file.
* Create an unmapped text source with the contents of the file.
*/
void FileOKCallback(Widget fsb, ViewPtr this,
XmFileSelectionBoxCallbackStruct *call_data)
{
FILE * file;
char * path;
char *buffer;
static char no_file[] = "no_file" ;
static XmString no_file_msg = NULL;
XmPushButtonCallbackStruct dummy;
int filesize;
XmStringContext ctxt;
XmStringCharSet charset;
XmStringDirection dir;
Boolean sep;
XmStringInitContext(&ctxt, call_data->value);
XmStringGetNextSegment(ctxt, &path, &charset, &dir, &sep);
XmStringFreeContext(ctxt);
XtFree((char *)charset);
if (((file = OpenFile(path)) == NULL)
|| (buffer = ReadFile(file, &filesize)) == NULL)
{
if (no_file_msg == NULL)
no_file_msg = FetchString(this, no_file);
ViewError(this, no_file_msg, call_data->value);
}
else {
PanePtr pane = this->panes, tmp;
XtPopdown(XtParent(fsb));
while ( pane != NULL) { /* destroy all panes */
XtDestroyWidget(pane->text);
tmp = pane;
pane = pane->next;
XtFree((char *)tmp);
--this->n_panes;
}
this->panes = NULL;
this->current_pane = NULL;
/* Set the new source text */
XmTextSetString(this->text_source, buffer);
XtFree(buffer);
XtFree(path);
CloseFile(file);
NewPaneCallback(this->paned_window, this, &dummy);
XtVaSetValues(this->path,
XmNlabelString, call_data->value,
NULL);
}
}
/* ===================================================================
* The new pane callback. Create a new pane in the pane window.
* Alloc a pane structure, initialize it.
* Set focus to the new pane.
* Allow menu items on panes.
*/
void NewPaneCallback(Widget widget, ViewPtr this,
XmPushButtonCallbackStruct *call_data)
{
PanePtr new;
Arg args[10];
int n = 0;
Dimension height;
short index ;
Widget target = NULL;
new = (PanePtr) XtCalloc(sizeof(Pane), 1);
if (this->panes != NULL)
this->panes->previous = new;
new->next = this->panes;
this->panes = new;
/*
* If not first time, split current pane in 2 to create the new pane
*/
if (this->n_panes == 0) { /* first time, just load the file */
SetSensitive(this->view_cascade, new_pane, True);
SetSensitive(this->view_cascade, search, True);
}
else {
target = XtParent(this->current_pane->text);
}
++this->n_panes;
n = 0;
XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
XtSetArg(args[n], XmNallowResize, True); n++;
new->text = XmCreateScrolledText(this->paned_window, "pane", args, n);
/*
XtAddCallback(new->text,
XmNmodifyVerifyCallback, (XtCallbackProc) NoInsert, this);
*/
XtAddCallback(new->text,
XmNfocusCallback, (XtCallbackProc) ChangeCurrentPane, this);
XmTextSetSource(new->text,
XmTextGetSource(this->text_source), 0, 0);
if (target != NULL) { /* this is not the first pane */
n = 0;
XtSetArg(args[n], XmNpositionIndex, &index); n++;
XtSetArg(args[n], XmNheight, &height); n++;
XtGetValues(target, args, n);
++index;
printf("set source text\n");
n = 0;
XtSetArg(args[n], XmNpositionIndex, index); n++;
XtSetArg(args[n], XmNheight, (Dimension) height/2); n++;
XtSetValues(XtParent(new->text), args, n);
XmTextSetTopCharacter(new->text,
XmTextGetTopCharacter(this->current_pane->text));
XtVaSetValues(target, XmNheight, (Dimension) height/2);
}
printf("source text set\n");
XtManageChild(new->text);
if (this->n_panes == 2)
SetSensitive(this->view_cascade, kill_pane, True);
XmProcessTraversal(new->text, XmTRAVERSE_CURRENT);
this->current_pane = new;
}
/* ===================================================================
* The kill pane callback. Delete a pane in the pane window.
* Free pane structure.
*/
void KillPaneCallback(Widget button, ViewPtr this,
XmPushButtonCallbackStruct *call_data)
{
PanePtr *pane, tmp;
/*
printf("%d panes left\n", this->n_panes-1);
*/
for (pane = &this->panes; *pane != this->current_pane; )
pane = &((*pane)->next);
/*
* Destroy the old one, free memory.
* Do not allow the last pane to be destroyed
* Make destroy command unavailable if last pane.
* Make next or previous pane become current and traverse to it.
*/
tmp = *pane;
*pane = (*pane)->next;
XtDestroyWidget(tmp->text);
XtFree((char *)tmp);
this->current_pane = (*pane == NULL) ? this->panes : *pane;
if ( --this->n_panes < 2 )
SetSensitive(this->view_cascade, kill_pane, False);
XmProcessTraversal(this->current_pane->text, XmTRAVERSE_CURRENT);
}
/* =====================================================================
* Focus has moved. Change current pane.
*/
static void ChangeCurrentPane(Widget text, ViewPtr this,
XmAnyCallbackStruct verify)
{
PanePtr pane = this->panes;
while (pane != NULL) {
if (pane->text == text)
break;
pane = pane->next;
}
this->current_pane = pane;
}
/* ===============================================================
* The Find Callback. The parent widget is passed as client data.
*
*/
void FindCallback(Widget button, ViewPtr this,
XmPushButtonCallbackStruct *call_data)
{
Widget template;
XtCallbackRec ok[2], cancel[2];
#define NUMBOXES 4
#define NUMBUTTONS 2
#define TITLEDFRAME 2
Widget framed[TITLEDFRAME];
Widget frame;
Widget forward, backward;
if ( this->search_box == NULL ) {
Arg args[10];
int n = 0;
search_msg = FetchString(this, search_prompt);
XtSetArg(args[n], XmNautoUnmanage, False); n++;
XtSetArg(args[n], XmNmessageString, search_msg); n++;
ok[0].callback = (XtCallbackProc) SearchSubstring;
ok[0].closure = (XtPointer) this;
ok[1].callback = cancel[1].callback = NULL;
ok[1].closure = cancel[1].closure = NULL;
cancel[0].callback = (XtCallbackProc) CancelSearch;
cancel[0].closure = (XtPointer) this;
XtSetArg(args[n], XmNokCallback, (XtCallbackList) ok); n++;
XtSetArg(args[n], XmNcancelCallback, (XtCallbackList) cancel); n++;
this->search_box = XmCreateTemplateDialog(this->shell, "search_box",
args, n);
n = 0;
template = XmCreateForm(this->search_box, "form", args, n);
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM) ; n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM) ; n++;
this->search_entry = XmCreateTextField(template, "entry", args, n);
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment,XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, this->search_entry); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM) ; n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM) ; n++;
frame = XmCreateFrame(template, "dir_frame", args, n);
n = 0;
XtSetArg(args[n], XmNframeChildType, XmFRAME_TITLE_CHILD); n++;
framed[0] = XmCreateLabel(frame, "title", args, n);
n = 0;
XtSetArg(args[n], XmNframeChildType, XmFRAME_WORKAREA_CHILD); n++;
XtSetArg(args[n], XmNisAligned, True); n++;
XtSetArg(args[n], XmNradioAlwaysOne, True); n++;
XtSetArg(args[n], XmNentryAlignment, XmALIGNMENT_END); n++;
XtSetArg(args[n], XmNentryClass, xmToggleButtonWidgetClass); n++;
XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
this->direction =
framed[1] = XmCreateRadioBox(frame, "direction", args, n);
n = 0;
XtSetArg(args[n], XmNuserData, XmTEXT_FORWARD); n++;
forward = XmCreateToggleButton(framed[1], "forward", args, n);
n = 0;
XtSetArg(args[n], XmNuserData, XmTEXT_BACKWARD); n++;
backward = XmCreateToggleButton(framed[1], "backward", args, n);
XtManageChild(forward);
XtManageChild(backward);
XtManageChildren(framed, TITLEDFRAME);
XmToggleButtonSetState(forward, True, True);
XtManageChild(this->search_entry);
XtManageChild(frame);
XtManageChild(template);
}
if (XtIsManaged(this->search_box))
XtPopup(XtParent(this->search_box), XtGrabNone);
else
XtManageChild(this->search_box);
XmProcessTraversal(this->search_entry, XmTRAVERSE_CURRENT);
#undef NUMBUTTONS
#undef NUMBOXES
#undef TITLEDFRAME
}
/* ===============================================================
* The Find Callback. The View object is passed as client data.
*
*/
static void CancelSearch(Widget button, ViewPtr this,
XmPushButtonCallbackStruct *call_data)
{
XtPopdown(XtParent(this->search_box));
}
/* ===============================================================
* The Find Callback. The parent widget is passed as client data.
*
*/
static void SearchSubstring(Widget button, ViewPtr this,
XmPushButtonCallbackStruct *call_data)
{
#define STRING_MAX_CHARS 1024
char *substring;
/* int status; */
XmTextPosition pos;
/* int last = XmTextFieldGetLastPosition(this->search_entry); */
XmString search = NULL;
XmTextDirection direction;
Widget toggle;
/*
status = XmTextFieldGetSubstring(this->search_entry, 0, last,
STRING_MAX_CHARS, substring);
if (status == XmCOPY_FAILED || status == XmCOPY_TRUNCATED) {
if (no_search_msg == NULL)
no_search_msg = FetchString(this, no_search);
search = XmStringCreateLocalized(substring);
ViewWarning(this, no_search_msg, search);
return;
}
*/
substring = XmTextFieldGetString(this->search_entry);
if (substring == NULL) {
if (no_pattern_msg == NULL)
no_pattern_msg = FetchString(this, no_pattern);
ViewWarning(this, no_pattern_msg, (XmString) NULL);
return;
}
XtVaGetValues(this->direction, XmNmenuHistory, &toggle, NULL);
XtVaGetValues(toggle, XmNuserData, &direction, NULL);
if (XmTextFindString(this->current_pane->text,
XmTextGetInsertionPosition(this->current_pane->text),
substring, direction, &pos))
{
XmTextSetTopCharacter(this->current_pane->text, pos);
XmTextSetInsertionPosition(this->current_pane->text, pos);
XtPopdown(XtParent(this->search_box));
}
else {
if (not_found_msg == NULL)
not_found_msg = FetchString(this, not_found);
search = XmStringCreateLocalized(substring);
ViewWarning(this, not_found_msg, search);
XmStringFree(search);
}
XtFree(substring);
}
/* =====================================================================
* Reject text insertion
*/
static void NoInsert(Widget text, ViewPtr this, XmTextVerifyPtr verify)
{
/*
if (verify->startPos != verify->endPos)
printf("deleting text %d %d\n", verify->startPos, verify->endPos);
if (verify->text != NULL && verify->text->length > 0)
printf("inserting %d characters: '%s'\n",
verify->text->length,
verify->text->ptr);
*/
}