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