1 /*
2  * Motif
3  *
4  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22 */
23 /*
24  * HISTORY
25 */
26 #ifdef REV_INFO
27 #ifndef lint
28 static char rcsid[] = "$XConsortium: text.c /main/7 1996/10/30 10:28:07 cde-osf $"
29 #endif
30 #endif
31 
32 #include "text.h"
33 
34 /* ===================================================================
35  * The OK callback for FSB. Check the selected file can be opened.
36  * If so, close the old file, read the new file.
37  * Create an unmapped text source with the contents of the file.
38  */
39 void FileOKCallback(Widget fsb, ViewPtr this,
40 			XmFileSelectionBoxCallbackStruct *call_data)
41 {
42    FILE * file;
43    char * path;
44    char *buffer;
45    static char no_file[] = "no_file" ;
46    static XmString no_file_msg = NULL;
47    XmPushButtonCallbackStruct dummy;
48    int filesize;
49    XmStringContext ctxt;
50    XmStringCharSet charset;
51    XmStringDirection dir;
52    Boolean sep;
53 
54 
55    XmStringInitContext(&ctxt, call_data->value);
56    XmStringGetNextSegment(ctxt, &path, &charset, &dir, &sep);
57    XmStringFreeContext(ctxt);
58    XtFree((char *)charset);
59    if (((file = OpenFile(path)) == NULL)
60        || (buffer = ReadFile(file, &filesize)) == NULL)
61      {
62 	 if (no_file_msg == NULL)
63 	   no_file_msg = FetchString(this, no_file);
64 	 ViewError(this, no_file_msg, call_data->value);
65       }
66    else {
67       PanePtr pane = this->panes, tmp;
68 
69       XtPopdown(XtParent(fsb));
70       while ( pane != NULL) { /* destroy all panes */
71 	 XtDestroyWidget(pane->text);
72 	 tmp = pane;
73 	 pane = pane->next;
74 	 XtFree((char *)tmp);
75 	 --this->n_panes;
76       }
77       this->panes = NULL;
78       this->current_pane = NULL;
79       /* Set the new source text */
80       XmTextSetString(this->text_source, buffer);
81       XtFree(buffer);
82       XtFree(path);
83       CloseFile(file);
84       NewPaneCallback(this->paned_window, this, &dummy);
85       XtVaSetValues(this->path,
86 		    XmNlabelString, call_data->value,
87 		    NULL);
88    }
89 }
90 
91 /* ===================================================================
92  * The new pane callback. Create a new pane in the pane window.
93  * Alloc a pane structure, initialize it.
94  * Set focus to the new pane.
95  * Allow menu items on panes.
96  */
97 
NewPaneCallback(Widget widget,ViewPtr this,XmPushButtonCallbackStruct * call_data)98 void NewPaneCallback(Widget widget, ViewPtr this,
99 			    XmPushButtonCallbackStruct *call_data)
100 {
101    PanePtr new;
102    Arg args[10];
103    int n = 0;
104    Dimension height;
105    short index ;
106    Widget target = NULL;
107 
108    new = (PanePtr) XtCalloc(sizeof(Pane), 1);
109    if (this->panes != NULL)
110      this->panes->previous = new;
111    new->next = this->panes;
112    this->panes = new;
113 
114 /*
115  * If not first time, split current pane in 2 to create the new pane
116  */
117    if (this->n_panes == 0) { /* first time, just load the file */
118       SetSensitive(this->view_cascade, new_pane, True);
119       SetSensitive(this->view_cascade, search, True);
120    }
121    else {
122       target = XtParent(this->current_pane->text);
123    }
124    ++this->n_panes;
125    n = 0;
126    XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
127    XtSetArg(args[n], XmNallowResize, True); n++;
128    new->text = XmCreateScrolledText(this->paned_window, "pane", args, n);
129 /*
130    XtAddCallback(new->text,
131 		 XmNmodifyVerifyCallback, (XtCallbackProc) NoInsert, this);
132 */
133    XtAddCallback(new->text,
134 		 XmNfocusCallback, (XtCallbackProc) ChangeCurrentPane, this);
135    XmTextSetSource(new->text,
136 		   XmTextGetSource(this->text_source), 0, 0);
137    if (target != NULL) { /* this is not the first pane */
138       n = 0;
139       XtSetArg(args[n], XmNpositionIndex, &index); n++;
140       XtSetArg(args[n], XmNheight, &height); n++;
141       XtGetValues(target, args, n);
142       ++index;
143       printf("set source text\n");
144       n = 0;
145       XtSetArg(args[n], XmNpositionIndex, index); n++;
146       XtSetArg(args[n], XmNheight, (Dimension) height/2); n++;
147       XtSetValues(XtParent(new->text), args, n);
148       XmTextSetTopCharacter(new->text,
149 			    XmTextGetTopCharacter(this->current_pane->text));
150       XtVaSetValues(target, XmNheight, (Dimension) height/2, NULL);
151    }
152    printf("source text set\n");
153    XtManageChild(new->text);
154 
155    if  (this->n_panes == 2)
156      SetSensitive(this->view_cascade, kill_pane, True);
157 
158    XmProcessTraversal(new->text, XmTRAVERSE_CURRENT);
159    this->current_pane = new;
160 }
161 
162 /* ===================================================================
163  * The kill pane callback. Delete a pane in the pane window.
164  * Free pane structure.
165  */
166 
KillPaneCallback(Widget button,ViewPtr this,XmPushButtonCallbackStruct * call_data)167 void KillPaneCallback(Widget button, ViewPtr this,
168 			     XmPushButtonCallbackStruct *call_data)
169 {
170    PanePtr *pane, tmp;
171 
172 /*
173    printf("%d panes left\n", this->n_panes-1);
174  */
175    for (pane = &this->panes; *pane != this->current_pane; )
176      pane = &((*pane)->next);
177 /*
178  * Destroy the old one, free memory.
179  * Do not allow the last pane to be destroyed
180  * Make destroy command unavailable if last pane.
181  * Make next or previous pane become current and traverse to it.
182  */
183 
184    tmp = *pane;
185    *pane = (*pane)->next;
186    XtDestroyWidget(tmp->text);
187    XtFree((char *)tmp);
188    this->current_pane = (*pane == NULL) ? this->panes : *pane;
189    if ( --this->n_panes < 2 )
190       SetSensitive(this->view_cascade, kill_pane, False);
191 
192    XmProcessTraversal(this->current_pane->text, XmTRAVERSE_CURRENT);
193 }
194 
195 /* =====================================================================
196  * Focus has moved. Change current pane.
197  */
198 
ChangeCurrentPane(Widget text,ViewPtr this,XmAnyCallbackStruct verify)199 static void ChangeCurrentPane(Widget text, ViewPtr this,
200 			      XmAnyCallbackStruct verify)
201 {
202    PanePtr pane = this->panes;
203 
204    while (pane != NULL) {
205       if (pane->text == text)
206 	break;
207       pane = pane->next;
208    }
209    this->current_pane = pane;
210 }
211 
212 /* ===============================================================
213  *   The Find Callback. The parent widget is passed as client data.
214  *
215  */
216 
FindCallback(Widget button,ViewPtr this,XmPushButtonCallbackStruct * call_data)217 void FindCallback(Widget button, ViewPtr this,
218 			  XmPushButtonCallbackStruct *call_data)
219 {
220   Widget template;
221   XtCallbackRec ok[2], cancel[2];
222 #define NUMBOXES 4
223 #define NUMBUTTONS 2
224 #define TITLEDFRAME 2
225   Widget framed[TITLEDFRAME];
226   Widget frame;
227   Widget forward, backward;
228 
229   if ( this->search_box == NULL ) {
230      Arg args[10];
231      int n = 0;
232 
233      search_msg = FetchString(this, search_prompt);
234      XtSetArg(args[n], XmNautoUnmanage, False); n++;
235      XtSetArg(args[n], XmNmessageString, search_msg); n++;
236      ok[0].callback = (XtCallbackProc) SearchSubstring;
237      ok[0].closure = (XtPointer) this;
238      ok[1].callback = cancel[1].callback = NULL;
239      ok[1].closure = cancel[1].closure = NULL;
240      cancel[0].callback = (XtCallbackProc) CancelSearch;
241      cancel[0].closure = (XtPointer) this;
242      XtSetArg(args[n], XmNokCallback, (XtCallbackList) ok);  n++;
243      XtSetArg(args[n], XmNcancelCallback, (XtCallbackList) cancel);  n++;
244      this->search_box = XmCreateTemplateDialog(this->shell, "search_box",
245 					       args, n);
246      n = 0;
247      template = XmCreateForm(this->search_box, "form", args, n);
248      n = 0;
249      XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
250      XtSetArg(args[n], XmNrightAttachment,  XmATTACH_FORM) ; n++;
251      XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM) ; n++;
252      this->search_entry = XmCreateTextField(template, "entry", args, n);
253      n = 0;
254      XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
255      XtSetArg(args[n], XmNbottomAttachment,XmATTACH_WIDGET); n++;
256      XtSetArg(args[n], XmNbottomWidget, this->search_entry); n++;
257      XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM) ; n++;
258      XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM) ; n++;
259      frame = XmCreateFrame(template, "dir_frame", args, n);
260      n = 0;
261      XtSetArg(args[n], XmNframeChildType, XmFRAME_TITLE_CHILD); n++;
262      framed[0] = XmCreateLabel(frame, "title", args, n);
263      n = 0;
264      XtSetArg(args[n], XmNframeChildType, XmFRAME_WORKAREA_CHILD); n++;
265      XtSetArg(args[n], XmNisAligned, True); n++;
266      XtSetArg(args[n], XmNradioAlwaysOne, True); n++;
267      XtSetArg(args[n], XmNentryAlignment, XmALIGNMENT_END); n++;
268      XtSetArg(args[n], XmNentryClass, xmToggleButtonWidgetClass); n++;
269      XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
270      this->direction =
271        framed[1] = XmCreateRadioBox(frame, "direction", args, n);
272      n = 0;
273      XtSetArg(args[n], XmNuserData, XmTEXT_FORWARD); n++;
274      forward = XmCreateToggleButton(framed[1], "forward", args, n);
275      n = 0;
276      XtSetArg(args[n], XmNuserData, XmTEXT_BACKWARD); n++;
277      backward = XmCreateToggleButton(framed[1], "backward", args, n);
278      XtManageChild(forward);
279      XtManageChild(backward);
280      XtManageChildren(framed, TITLEDFRAME);
281      XmToggleButtonSetState(forward, True, True);
282      XtManageChild(this->search_entry);
283      XtManageChild(frame);
284      XtManageChild(template);
285   }
286   if (XtIsManaged(this->search_box))
287     XtPopup(XtParent(this->search_box), XtGrabNone);
288   else
289     XtManageChild(this->search_box);
290   XmProcessTraversal(this->search_entry, XmTRAVERSE_CURRENT);
291 
292 #undef NUMBUTTONS
293 #undef NUMBOXES
294 #undef TITLEDFRAME
295 }
296 
297 
298 /* ===============================================================
299  *   The Find Callback. The View object is passed as client data.
300  *
301  */
302 
CancelSearch(Widget button,ViewPtr this,XmPushButtonCallbackStruct * call_data)303 static void CancelSearch(Widget button, ViewPtr this,
304 			    XmPushButtonCallbackStruct *call_data)
305 {
306    XtPopdown(XtParent(this->search_box));
307 }
308 
309 /* ===============================================================
310  *   The Find Callback. The parent widget is passed as client data.
311  *
312  */
313 
SearchSubstring(Widget button,ViewPtr this,XmPushButtonCallbackStruct * call_data)314 static void SearchSubstring(Widget button, ViewPtr this,
315 			    XmPushButtonCallbackStruct *call_data)
316 {
317 #define STRING_MAX_CHARS 1024
318    char *substring;
319 /*   int status; */
320    XmTextPosition pos;
321 /*   int last = XmTextFieldGetLastPosition(this->search_entry); */
322    XmString search = NULL;
323    XmTextDirection direction;
324    Widget toggle;
325 
326 /*
327 
328    status = XmTextFieldGetSubstring(this->search_entry, 0, last,
329 				    STRING_MAX_CHARS, substring);
330    if (status == XmCOPY_FAILED || status == XmCOPY_TRUNCATED) {
331       if (no_search_msg == NULL)
332 	no_search_msg = FetchString(this, no_search);
333       search =  XmStringCreateLocalized(substring);
334       ViewWarning(this, no_search_msg, search);
335       return;
336    }
337 */
338    substring = XmTextFieldGetString(this->search_entry);
339    if (substring == NULL) {
340       if (no_pattern_msg == NULL)
341 	no_pattern_msg = FetchString(this, no_pattern);
342       ViewWarning(this, no_pattern_msg, (XmString) NULL);
343       return;
344    }
345    XtVaGetValues(this->direction, XmNmenuHistory, &toggle, NULL);
346    XtVaGetValues(toggle, XmNuserData, &direction, NULL);
347    if (XmTextFindString(this->current_pane->text,
348 			XmTextGetInsertionPosition(this->current_pane->text),
349 			substring, direction, &pos))
350      {
351 	XmTextSetTopCharacter(this->current_pane->text, pos);
352 	XmTextSetInsertionPosition(this->current_pane->text, pos);
353 	XtPopdown(XtParent(this->search_box));
354      }
355    else {
356       if (not_found_msg == NULL)
357 	not_found_msg = FetchString(this, not_found);
358       search =  XmStringCreateLocalized(substring);
359       ViewWarning(this, not_found_msg, search);
360       XmStringFree(search);
361    }
362    XtFree(substring);
363 }
364 
365 /* =====================================================================
366  * Reject text insertion
367  */
368 
NoInsert(Widget text,ViewPtr this,XmTextVerifyPtr verify)369 static void NoInsert(Widget text, ViewPtr this, XmTextVerifyPtr verify)
370 {
371 /*
372  if (verify->startPos != verify->endPos)
373      printf("deleting text %d %d\n", verify->startPos, verify->endPos);
374    if (verify->text != NULL && verify->text->length > 0)
375      printf("inserting %d characters: '%s'\n",
376 	    verify->text->length,
377 	    verify->text->ptr);
378 */
379 }
380 
381