1 /*******************************************************************************
2 *                                                                              *
3 * windowTitle.c -- Nirvana Editor window title customization                   *
4 *                                                                              *
5 * Copyright (C) 2001, Arne Forlie                                              *
6 *                                                                              *
7 * This is free software; you can redistribute it and/or modify it under the    *
8 * terms of the GNU General Public License as published by the Free Software    *
9 * Foundation; either version 2 of the License, or (at your option) any later   *
10 * version. In addition, you may distribute versions of this program linked to  *
11 * Motif or Open Motif. See README for details.                                 *
12 *                                                                              *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        *
15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for    *
16 * more details.                                                                *
17 *                                                                              *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple     *
20 * Place, Suite 330, Boston, MA  02111-1307 USA                                 *
21 *                                                                              *
22 * Nirvana Text Editor                                                          *
23 * July 31, 2001                                                                *
24 *                                                                              *
25 * Written by Arne Forlie, http://arne.forlie.com                               *
26 *                                                                              *
27 *******************************************************************************/
28 
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32 
33 #include "windowTitle.h"
34 #include "textBuf.h"
35 #include "nedit.h"
36 #include "preferences.h"
37 #include "help.h"
38 #include "../util/prefFile.h"
39 #include "../util/misc.h"
40 #include "../util/DialogF.h"
41 #include "../util/utils.h"
42 #include "../util/fileUtils.h"
43 #include "../util/nedit_malloc.h"
44 
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <ctype.h>
48 #include <string.h>
49 #ifdef VMS
50 #include "../util/VMSparam.h"
51 #else
52 #ifndef __MVS__
53 #include <sys/param.h>
54 #endif
55 #include "../util/clearcase.h"
56 #endif /*VMS*/
57 
58 #include <Xm/Xm.h>
59 #include <Xm/SelectioB.h>
60 #include <Xm/Form.h>
61 #include <Xm/List.h>
62 #include <Xm/SeparatoG.h>
63 #include <Xm/LabelG.h>
64 #include <Xm/PushBG.h>
65 #include <Xm/PushB.h>
66 #include <Xm/ToggleBG.h>
67 #include <Xm/ToggleB.h>
68 #include <Xm/RowColumn.h>
69 #include <Xm/CascadeBG.h>
70 #include <Xm/Frame.h>
71 #include <Xm/Text.h>
72 #include <Xm/TextF.h>
73 
74 #ifdef HAVE_DEBUG_H
75 #include "../debug.h"
76 #endif
77 
78 
79 #define WINDOWTITLE_MAX_LEN 500
80 
81 /* Customize window title dialog information */
82 static struct {
83     Widget      form;
84     Widget      shell;
85     WindowInfo* window;
86     Widget      previewW;
87     Widget      formatW;
88 
89     Widget      ccW;
90     Widget      fileW;
91     Widget      hostW;
92     Widget      dirW;
93     Widget      statusW;
94     Widget      shortStatusW;
95     Widget      serverW;
96     Widget      nameW;
97     Widget      mdirW;
98     Widget      ndirW;
99 
100     Widget      oDirW;
101     Widget      oCcViewTagW;
102     Widget      oServerNameW;
103     Widget      oFileChangedW;
104     Widget      oFileLockedW;
105     Widget      oFileReadOnlyW;
106     Widget      oServerEqualViewW;
107 
108     char	filename[MAXPATHLEN];
109     char	path[MAXPATHLEN];
110     char	viewTag[MAXPATHLEN];
111     char	serverName[MAXPATHLEN];
112     int         isServer;
113     int         filenameSet;
114     int         lockReasons;
115     int         fileChanged;
116 
117     int 	suppressFormatUpdate;
118 } etDialog = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
119               NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
120               NULL,NULL,"","","","",0,0,0,0,0};
121 
122 
123 
removeSequence(char * sourcePtr,char c)124 static char* removeSequence(char* sourcePtr, char c)
125 {
126     while (*sourcePtr == c) {
127         sourcePtr++;
128     }
129     return(sourcePtr);
130 }
131 
132 
133 /*
134 ** Two functions for performing safe insertions into a finite
135 ** size buffer so that we don't get any memory overruns.
136 */
safeStrCpy(char * dest,char * destEnd,const char * source)137 static char* safeStrCpy(char* dest, char* destEnd, const char* source)
138 {
139    int len = (int)strlen(source);
140    if (len <= (destEnd - dest)) {
141        strcpy(dest, source);
142        return(dest + len);
143    }
144    else {
145        strncpy(dest, source, destEnd - dest);
146        *destEnd = '\0';
147        return(destEnd);
148    }
149 }
150 
safeCharAdd(char * dest,char * destEnd,char c)151 static char* safeCharAdd(char* dest, char* destEnd, char c)
152 {
153    if (destEnd - dest > 0)
154    {
155       *dest++ = c;
156       *dest = '\0';
157    }
158    return(dest);
159 }
160 
161 /*
162 ** Remove empty paranthesis pairs and multiple spaces in a row
163 ** with one space.
164 ** Also remove leading and trailing spaces and dashes.
165 */
compressWindowTitle(char * title)166 static void compressWindowTitle(char *title)
167 {
168     /* Compress the title */
169     int modified;
170     do {
171         char *sourcePtr = title;
172         char *destPtr   = sourcePtr;
173         char c = *sourcePtr++;
174 
175         modified = False;
176 
177         /* Remove leading spaces and dashes */
178         while (c == ' ' || c == '-') {
179             c= *sourcePtr++;
180         }
181 
182         /* Remove empty constructs */
183         while (c != '\0') {
184             switch (c) {
185                 /* remove sequences */
186                 case ' ':
187                 case '-':
188                     sourcePtr = removeSequence(sourcePtr, c);
189                     *destPtr++ = c; /* leave one */
190                     break;
191 
192                 /* remove empty paranthesis pairs */
193                 case '(':
194                     if (*sourcePtr == ')') {
195                         modified = True;
196                         sourcePtr++;
197                     }
198                     else *destPtr++ = c;
199                     sourcePtr = removeSequence(sourcePtr, ' ');
200                     break;
201 
202                 case '[':
203                     if (*sourcePtr == ']') {
204                         modified = True;
205                         sourcePtr++;
206                     }
207                     else *destPtr++ = c;
208                     sourcePtr = removeSequence(sourcePtr, ' ');
209                     break;
210 
211                 case '{':
212                     if (*sourcePtr == '}') {
213                         modified = True;
214                         sourcePtr++;
215                     }
216                     else *destPtr++ = c;
217                     sourcePtr = removeSequence(sourcePtr, ' ');
218                     break;
219 
220                 default:
221                     *destPtr++ = c;
222                     break;
223             }
224             c = *sourcePtr++;
225             *destPtr = '\0';
226         }
227 
228         /* Remove trailing spaces and dashes */
229         while (destPtr-- > title) {
230             if (*destPtr != ' ' && *destPtr != '-')
231                 break;
232             *destPtr = '\0';
233         }
234     } while (modified == True);
235 }
236 
237 
238 /*
239 ** Format the windows title using a printf like formatting string.
240 ** The following flags are recognised:
241 **  %c    : ClearCase view tag
242 **  %s    : server name
243 **  %[n]d : directory, with one optional digit specifying the max number
244 **          of trailing directory components to display. Skipped components are
245 **          replaced by an ellipsis (...).
246 **  %f    : file name
247 **  %h    : host name
248 **  %S    : file status
249 **  %u    : user name
250 **
251 **  if the ClearCase view tag and server name are identical, only the first one
252 **  specified in the formatting string will be displayed.
253 */
FormatWindowTitle(const char * filename,const char * path,const char * clearCaseViewTag,const char * serverName,int isServer,int filenameSet,int lockReasons,int fileChanged,const char * titleFormat)254 char *FormatWindowTitle(const char* filename,
255                         const char* path,
256                         const char* clearCaseViewTag,
257                         const char* serverName,
258                         int isServer,
259                         int filenameSet,
260                         int lockReasons,
261                         int fileChanged,
262                         const char* titleFormat)
263 {
264     static char title[WINDOWTITLE_MAX_LEN];
265     char *titlePtr = title;
266     char* titleEnd = title + WINDOWTITLE_MAX_LEN - 1;
267 
268 
269     /* Flags to supress one of these if both are specified and they are identical */
270     int serverNameSeen = False;
271     int clearCaseViewTagSeen = False;
272 
273     int fileNamePresent = False;
274     int hostNamePresent = False;
275     int userNamePresent = False;
276     int serverNamePresent = False;
277     int clearCasePresent = False;
278     int fileStatusPresent = False;
279     int dirNamePresent = False;
280     int noOfComponents = -1;
281     int shortStatus = False;
282 
283     *titlePtr = '\0';  /* always start with an empty string */
284 
285     while (*titleFormat != '\0' && titlePtr < titleEnd) {
286         char c = *titleFormat++;
287         if (c == '%') {
288             c = *titleFormat++;
289             if (c == '\0')
290             {
291                 titlePtr = safeCharAdd(titlePtr, titleEnd, '%');
292                 break;
293             }
294             switch (c) {
295                 case 'c': /* ClearCase view tag */
296 		    clearCasePresent = True;
297                     if (clearCaseViewTag != NULL) {
298                         if (serverNameSeen == False ||
299                             strcmp(serverName, clearCaseViewTag) != 0) {
300                             titlePtr = safeStrCpy(titlePtr, titleEnd, clearCaseViewTag);
301                             clearCaseViewTagSeen = True;
302                         }
303                     }
304                     break;
305 
306                 case 's': /* server name */
307 		    serverNamePresent = True;
308                     if (isServer && serverName[0] != '\0') { /* only applicable for servers */
309                         if (clearCaseViewTagSeen == False ||
310                             strcmp(serverName, clearCaseViewTag) != 0) {
311                             titlePtr = safeStrCpy(titlePtr, titleEnd, serverName);
312                             serverNameSeen = True;
313                         }
314                     }
315                     break;
316 
317                 case 'd': /* directory without any limit to no. of components */
318 		    dirNamePresent = True;
319                     if (filenameSet) {
320                        titlePtr = safeStrCpy(titlePtr, titleEnd, path);
321                     }
322                     break;
323 
324                 case '0': /* directory with limited no. of components */
325                 case '1':
326                 case '2':
327                 case '3':
328                 case '4':
329                 case '5':
330                 case '6':
331                 case '7':
332                 case '8':
333                 case '9':
334                     if (*titleFormat == 'd') {
335                         dirNamePresent = True;
336                         noOfComponents = c - '0';
337                         titleFormat++; /* delete the argument */
338 
339                         if (filenameSet) {
340                             const char* trailingPath = GetTrailingPathComponents(path,
341                                                                                 noOfComponents);
342 
343                             /* prefix with ellipsis if components were skipped */
344                             if (trailingPath > path) {
345                                 titlePtr = safeStrCpy(titlePtr, titleEnd, "...");
346                             }
347                             titlePtr = safeStrCpy(titlePtr, titleEnd, trailingPath);
348                         }
349                     }
350                     break;
351 
352                 case 'f': /* file name */
353 		    fileNamePresent = True;
354                     titlePtr = safeStrCpy(titlePtr, titleEnd, filename);
355                     break;
356 
357                 case 'h': /* host name */
358 		    hostNamePresent = True;
359 		    titlePtr = safeStrCpy(titlePtr, titleEnd, GetNameOfHost());
360                     break;
361 
362                 case 'S': /* file status */
363                     fileStatusPresent = True;
364                     if (IS_ANY_LOCKED_IGNORING_USER(lockReasons) && fileChanged)
365                        titlePtr = safeStrCpy(titlePtr, titleEnd, "read only, modified");
366                     else if (IS_ANY_LOCKED_IGNORING_USER(lockReasons))
367                        titlePtr = safeStrCpy(titlePtr, titleEnd, "read only");
368                     else if (IS_USER_LOCKED(lockReasons) && fileChanged)
369                        titlePtr = safeStrCpy(titlePtr, titleEnd, "locked, modified");
370                     else if (IS_USER_LOCKED(lockReasons))
371                        titlePtr = safeStrCpy(titlePtr, titleEnd, "locked");
372                     else if (fileChanged)
373                        titlePtr = safeStrCpy(titlePtr, titleEnd, "modified");
374                     break;
375 
376                 case 'u': /* user name */
377 		    userNamePresent = True;
378                     titlePtr = safeStrCpy(titlePtr, titleEnd, GetUserName());
379                     break;
380 
381                 case '%': /* escaped % */
382                     titlePtr = safeCharAdd(titlePtr, titleEnd, '%');
383                     break;
384 
385 		case '*': /* short file status ? */
386                     fileStatusPresent = True;
387 		    if (*titleFormat && *titleFormat == 'S')
388 		    {
389 			++titleFormat;
390 			shortStatus = True;
391 			if (IS_ANY_LOCKED_IGNORING_USER(lockReasons) && fileChanged)
392                 	   titlePtr = safeStrCpy(titlePtr, titleEnd, "RO*");
393                 	else if (IS_ANY_LOCKED_IGNORING_USER(lockReasons))
394                 	   titlePtr = safeStrCpy(titlePtr, titleEnd, "RO");
395                 	else if (IS_USER_LOCKED(lockReasons) && fileChanged)
396                 	   titlePtr = safeStrCpy(titlePtr, titleEnd, "LO*");
397                 	else if (IS_USER_LOCKED(lockReasons))
398                 	   titlePtr = safeStrCpy(titlePtr, titleEnd, "LO");
399                 	else if (fileChanged)
400                 	   titlePtr = safeStrCpy(titlePtr, titleEnd, "*");
401 			break;
402 		    }
403                     /* fall-through */
404                 default:
405                     titlePtr = safeCharAdd(titlePtr, titleEnd, c);
406                     break;
407             }
408         }
409         else {
410             titlePtr = safeCharAdd(titlePtr, titleEnd, c);
411         }
412     }
413 
414     compressWindowTitle(title);
415 
416     if (title[0] == 0)
417     {
418 	sprintf(&title[0], "<empty>"); /* For preview purposes only */
419     }
420 
421     if (etDialog.form)
422     {
423 	/* Prevent recursive callback loop */
424         etDialog.suppressFormatUpdate = True;
425 
426 	/* Sync radio buttons with format string (in case the user entered
427 	   the format manually) */
428         XmToggleButtonSetState(etDialog.fileW,   fileNamePresent,   False);
429         XmToggleButtonSetState(etDialog.statusW, fileStatusPresent, False);
430         XmToggleButtonSetState(etDialog.serverW, serverNamePresent, False);
431 #ifndef VMS
432         XmToggleButtonSetState(etDialog.ccW,     clearCasePresent,  False);
433 #endif /* VMS */
434         XmToggleButtonSetState(etDialog.dirW,    dirNamePresent,    False);
435         XmToggleButtonSetState(etDialog.hostW,   hostNamePresent,   False);
436         XmToggleButtonSetState(etDialog.nameW,   userNamePresent,   False);
437 
438         XtSetSensitive(etDialog.shortStatusW,    fileStatusPresent);
439 	if (fileStatusPresent)
440 	{
441 	    XmToggleButtonSetState(etDialog.shortStatusW, shortStatus, False);
442 	}
443 
444 	/* Directory components are also sensitive to presence of dir */
445         XtSetSensitive(etDialog.ndirW,    dirNamePresent);
446         XtSetSensitive(etDialog.mdirW,    dirNamePresent);
447 
448         if (dirNamePresent) /* Avoid erasing number when not active */
449         {
450     	   if (noOfComponents >= 0)
451 	   {
452                char* value = XmTextGetString(etDialog.ndirW);
453                char buf[2];
454                sprintf(&buf[0], "%d", noOfComponents);
455                if (strcmp(&buf[0], value)) /* Don't overwrite unless diff. */
456        	           SetIntText(etDialog.ndirW, noOfComponents);
457                NEditFree(value);
458 	   }
459 	   else
460 	   {
461 	       XmTextSetString(etDialog.ndirW, "");
462 	   }
463         }
464 
465 	/* Enable/disable test buttons, depending on presence of codes */
466         XtSetSensitive(etDialog.oFileChangedW,  fileStatusPresent);
467         XtSetSensitive(etDialog.oFileReadOnlyW, fileStatusPresent);
468         XtSetSensitive(etDialog.oFileLockedW,   fileStatusPresent &&
469 						!IS_PERM_LOCKED(etDialog.lockReasons));
470 
471         XtSetSensitive(etDialog.oServerNameW, serverNamePresent);
472 
473 #ifndef VMS
474         XtSetSensitive(etDialog.oCcViewTagW,       clearCasePresent);
475         XtSetSensitive(etDialog.oServerEqualViewW, clearCasePresent &&
476 	                                           serverNamePresent);
477 #endif  /* VMS */
478 
479         XtSetSensitive(etDialog.oDirW,    dirNamePresent);
480 
481         etDialog.suppressFormatUpdate = False;
482     }
483 
484     return(title);
485 }
486 
487 
488 
489 /* a utility that sets the values of all toggle buttons */
setToggleButtons(void)490 static void setToggleButtons(void)
491 {
492     XmToggleButtonSetState(etDialog.oDirW,
493     	    	etDialog.filenameSet == True, False);
494     XmToggleButtonSetState(etDialog.oFileChangedW,
495     	    	etDialog.fileChanged == True, False);
496     XmToggleButtonSetState(etDialog.oFileReadOnlyW,
497     	    	IS_PERM_LOCKED(etDialog.lockReasons), False);
498     XmToggleButtonSetState(etDialog.oFileLockedW,
499     	    	IS_USER_LOCKED(etDialog.lockReasons), False);
500     /* Read-only takes precedence on locked */
501     XtSetSensitive(etDialog.oFileLockedW, !IS_PERM_LOCKED(etDialog.lockReasons));
502 
503 #ifdef VMS
504     XmToggleButtonSetState(etDialog.oServerNameW, etDialog.isServer, False);
505 #else
506     XmToggleButtonSetState(etDialog.oCcViewTagW,
507     	    	GetClearCaseViewTag() != NULL, False);
508     XmToggleButtonSetState(etDialog.oServerNameW,
509     	    	etDialog.isServer, False);
510 
511     if (GetClearCaseViewTag() != NULL && etDialog.isServer
512             && GetPrefServerName()[0] != '\0'
513             && strcmp(GetClearCaseViewTag(), GetPrefServerName()) == 0) {
514         XmToggleButtonSetState(etDialog.oServerEqualViewW, True, False);
515     } else {
516         XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False);
517     }
518 #endif /* VMS */
519 }
520 
formatChangedCB(Widget w,XtPointer clientData,XtPointer callData)521 static void formatChangedCB(Widget w, XtPointer clientData, XtPointer callData)
522 {
523     char *format;
524     int  filenameSet = XmToggleButtonGetState(etDialog.oDirW);
525     char *title;
526     const char* serverName;
527 
528     if (etDialog.suppressFormatUpdate)
529     {
530 	return; /* Prevent recursive feedback */
531     }
532 
533     format = XmTextGetString(etDialog.formatW);
534 
535 #ifndef VMS
536     if (XmToggleButtonGetState(etDialog.oServerEqualViewW) &&
537 	XmToggleButtonGetState(etDialog.ccW)) {
538        serverName = etDialog.viewTag;
539     } else
540 #endif /* VMS */
541     {
542        serverName = XmToggleButtonGetState(etDialog.oServerNameW) ?
543                                        etDialog.serverName : "";
544     }
545 
546     title = FormatWindowTitle(
547                   etDialog.filename,
548                   etDialog.filenameSet == True ?
549                                    etDialog.path :
550                                    "/a/very/long/path/used/as/example/",
551 #ifdef VMS
552 		  NULL,
553 #else
554                   XmToggleButtonGetState(etDialog.oCcViewTagW) ?
555                                    etDialog.viewTag : NULL,
556 #endif /* VMS */
557                   serverName,
558                   etDialog.isServer,
559                   filenameSet,
560                   etDialog.lockReasons,
561                   XmToggleButtonGetState(etDialog.oFileChangedW),
562                   format);
563     NEditFree(format);
564     XmTextFieldSetString(etDialog.previewW, title);
565 }
566 
567 #ifndef VMS
ccViewTagCB(Widget w,XtPointer clientData,XtPointer callData)568 static void ccViewTagCB(Widget w, XtPointer clientData, XtPointer callData)
569 {
570     if (XmToggleButtonGetState(w) == False) {
571         XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False);
572     }
573     formatChangedCB(w, clientData, callData);
574 }
575 #endif /* VMS */
576 
serverNameCB(Widget w,XtPointer clientData,XtPointer callData)577 static void serverNameCB(Widget w, XtPointer clientData, XtPointer callData)
578 {
579     if (XmToggleButtonGetState(w) == False) {
580         XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False);
581     }
582     etDialog.isServer = XmToggleButtonGetState(w);
583     formatChangedCB(w, clientData, callData);
584 }
585 
fileChangedCB(Widget w,XtPointer clientData,XtPointer callData)586 static void fileChangedCB(Widget w, XtPointer clientData, XtPointer callData)
587 {
588     etDialog.fileChanged = XmToggleButtonGetState(w);
589     formatChangedCB(w, clientData, callData);
590 }
591 
fileLockedCB(Widget w,XtPointer clientData,XtPointer callData)592 static void fileLockedCB(Widget w, XtPointer clientData, XtPointer callData)
593 {
594     SET_USER_LOCKED(etDialog.lockReasons, XmToggleButtonGetState(w));
595     formatChangedCB(w, clientData, callData);
596 }
597 
fileReadOnlyCB(Widget w,XtPointer clientData,XtPointer callData)598 static void fileReadOnlyCB(Widget w, XtPointer clientData, XtPointer callData)
599 {
600     SET_PERM_LOCKED(etDialog.lockReasons, XmToggleButtonGetState(w));
601     formatChangedCB(w, clientData, callData);
602 }
603 
604 #ifndef VMS
serverEqualViewCB(Widget w,XtPointer clientData,XtPointer callData)605 static void serverEqualViewCB(Widget w, XtPointer clientData, XtPointer callData)
606 {
607     if (XmToggleButtonGetState(w) == True) {
608         XmToggleButtonSetState(etDialog.oCcViewTagW,  True, False);
609         XmToggleButtonSetState(etDialog.oServerNameW, True, False);
610         etDialog.isServer = True;
611     }
612     formatChangedCB(w, clientData, callData);
613 }
614 #endif /* VMS */
615 
applyCB(Widget w,XtPointer clientData,XtPointer callData)616 static void applyCB(Widget w, XtPointer clientData, XtPointer callData)
617 {
618     char *format = XmTextGetString(etDialog.formatW);
619 
620     /* pop down the dialog */
621 /*    XtUnmanageChild(etDialog.form); */
622 
623     if (strcmp(format, GetPrefTitleFormat()) != 0) {
624         SetPrefTitleFormat(format);
625     }
626     NEditFree(format);
627 }
628 
closeCB(Widget w,XtPointer clientData,XtPointer callData)629 static void closeCB(Widget w, XtPointer clientData, XtPointer callData)
630 {
631     /* pop down the dialog */
632     XtUnmanageChild(etDialog.form);
633 }
634 
restoreCB(Widget w,XtPointer clientData,XtPointer callData)635 static void restoreCB(Widget w, XtPointer clientData, XtPointer callData)
636 {
637     XmTextSetString(etDialog.formatW, "{%c} [%s] %f (%S) - %d");
638 }
639 
helpCB(Widget w,XtPointer clientData,XtPointer callData)640 static void helpCB(Widget w, XtPointer clientData, XtPointer callData)
641 {
642     Help(HELP_CUSTOM_TITLE_DIALOG);
643 }
644 
wtDestroyCB(Widget w,XtPointer clientData,XtPointer callData)645 static void wtDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
646 {
647     if (w == etDialog.form) /* Prevent disconnecting the replacing dialog */
648         etDialog.form = NULL;
649 }
650 
wtUnmapCB(Widget w,XtPointer clientData,XtPointer callData)651 static void wtUnmapCB(Widget w, XtPointer clientData, XtPointer callData)
652 {
653     if (etDialog.form == w)  /* Prevent destroying the replacing dialog */
654         XtDestroyWidget(etDialog.form);
655 }
656 
appendToFormat(const char * string)657 static void appendToFormat(const char* string)
658 {
659     char *format = XmTextGetString(etDialog.formatW);
660     char *buf = (char*)NEditMalloc(strlen(string) + strlen(format) + 1);
661     strcpy(buf, format);
662     strcat(buf, string);
663     XmTextSetString(etDialog.formatW, buf);
664     NEditFree(format);
665     NEditFree(buf);
666 }
667 
removeFromFormat(const char * string)668 static void removeFromFormat(const char* string)
669 {
670     char *format = XmTextGetString(etDialog.formatW);
671     char* pos;
672 
673     /* There can be multiple occurences */
674     while ((pos = strstr(format, string)))
675     {
676 	/* If the string is preceded or followed by a brace, include
677 	   the brace(s) for removal */
678 	char* start = pos;
679 	char* end = pos + strlen(string);
680 	char post = *end;
681 
682 	if (post == '}' || post == ')' || post == ']' || post == '>')
683         {
684 	    end += 1;
685 	    post = *end;
686 	}
687 
688 	if (start > format)
689 	{
690 	    char pre = *(start-1);
691 	    if (pre == '{' || pre == '(' || pre == '[' || pre == '<')
692 		start -= 1;
693 	}
694 	if (start > format)
695 	{
696 	    char pre = *(start-1);
697 	    /* If there is a space in front and behind, remove one space
698 	       (there can be more spaces, but in that case it is likely
699 	       that the user entered them manually); also remove trailing
700 	       space */
701 	    if (pre == ' ' && post == ' ')
702 	    {
703 		end += 1;
704 	    }
705 	    else if (pre == ' ' && post == (char)0)
706 	    {
707 		/* Remove (1) trailing space */
708 		start -= 1;
709 	    }
710 	}
711 
712 	/* Contract the string: move end to start */
713 	strcpy(start, end);
714     }
715 
716     /* Remove leading and trailing space */
717     pos = format;
718     while (*pos == ' ') ++pos;
719     strcpy(format, pos);
720 
721     pos = format + strlen(format) - 1;
722     while (pos >= format && *pos == ' ')
723     {
724 	--pos;
725     }
726     *(pos+1) = (char)0;
727 
728     XmTextSetString(etDialog.formatW, format);
729     NEditFree(format);
730 }
731 
732 
toggleFileCB(Widget w,XtPointer clientData,XtPointer callData)733 static void toggleFileCB(Widget w, XtPointer clientData, XtPointer callData)
734 {
735     if (XmToggleButtonGetState(etDialog.fileW))
736 	appendToFormat(" %f");
737     else
738 	removeFromFormat("%f");
739 }
740 
toggleServerCB(Widget w,XtPointer clientData,XtPointer callData)741 static void toggleServerCB(Widget w, XtPointer clientData, XtPointer callData)
742 {
743     if (XmToggleButtonGetState(etDialog.serverW))
744 	appendToFormat(" [%s]");
745     else
746 	removeFromFormat("%s");
747 }
748 
toggleHostCB(Widget w,XtPointer clientData,XtPointer callData)749 static void toggleHostCB(Widget w, XtPointer clientData, XtPointer callData)
750 {
751     if (XmToggleButtonGetState(etDialog.hostW))
752 	appendToFormat(" [%h]");
753     else
754 	removeFromFormat("%h");
755 }
756 
757 #ifndef VMS
toggleClearCaseCB(Widget w,XtPointer clientData,XtPointer callData)758 static void toggleClearCaseCB(Widget w, XtPointer clientData, XtPointer callData)
759 {
760     if (XmToggleButtonGetState(etDialog.ccW))
761 	appendToFormat(" {%c}");
762     else
763 	removeFromFormat("%c");
764 }
765 #endif /* VMS */
766 
toggleStatusCB(Widget w,XtPointer clientData,XtPointer callData)767 static void toggleStatusCB(Widget w, XtPointer clientData, XtPointer callData)
768 {
769     if (XmToggleButtonGetState(etDialog.statusW))
770     {
771 	if (XmToggleButtonGetState(etDialog.shortStatusW))
772 	    appendToFormat(" (%*S)");
773 	else
774 	    appendToFormat(" (%S)");
775     }
776     else
777     {
778 	removeFromFormat("%S");
779 	removeFromFormat("%*S");
780     }
781 }
782 
toggleShortStatusCB(Widget w,XtPointer clientData,XtPointer callData)783 static void toggleShortStatusCB(Widget w, XtPointer clientData, XtPointer callData)
784 {
785     char *format, *pos;
786 
787     if (etDialog.suppressFormatUpdate)
788     {
789 	return;
790     }
791 
792     format = XmTextGetString(etDialog.formatW);
793 
794     if (XmToggleButtonGetState(etDialog.shortStatusW))
795     {
796 	/* Find all %S occurrences and replace them by %*S */
797 	do
798 	{
799 	    pos = strstr(format, "%S");
800 	    if (pos)
801 	    {
802      	        char* tmp = (char*)NEditMalloc((strlen(format)+2)*sizeof(char));
803 		strncpy(tmp, format, (size_t)(pos-format+1));
804 		tmp[pos-format+1] = 0;
805 		strcat(tmp, "*");
806 		strcat(tmp, pos+1);
807 		NEditFree(format);
808 		format = tmp;
809 	    }
810 	}
811 	while (pos);
812     }
813     else
814     {
815 	/* Replace all %*S occurences by %S */
816 	do
817 	{
818             pos = strstr(format, "%*S");
819 	    if (pos)
820 	    {
821 		strcpy(pos+1, pos+2);
822 	    }
823 	}
824 	while(pos);
825     }
826 
827     XmTextSetString(etDialog.formatW, format);
828     NEditFree(format);
829 }
830 
toggleUserCB(Widget w,XtPointer clientData,XtPointer callData)831 static void toggleUserCB(Widget w, XtPointer clientData, XtPointer callData)
832 {
833     if (XmToggleButtonGetState(etDialog.nameW))
834 	appendToFormat(" %u");
835     else
836 	removeFromFormat("%u");
837 }
838 
toggleDirectoryCB(Widget w,XtPointer clientData,XtPointer callData)839 static void toggleDirectoryCB(Widget w, XtPointer clientData, XtPointer callData)
840 {
841     if (XmToggleButtonGetState(etDialog.dirW))
842     {
843         char buf[20];
844 	int maxComp;
845         char *value = XmTextGetString(etDialog.ndirW);
846 	if (*value)
847 	{
848 	   if (sscanf(value, "%d", &maxComp) > 0)
849 	   {
850 	      sprintf(&buf[0], " %%%dd ", maxComp);
851            }
852 	   else
853 	   {
854    	      sprintf(&buf[0], " %%d "); /* Should not be necessary */
855  	   }
856         }
857 	else
858 	{
859 	   sprintf(&buf[0], " %%d ");
860 	}
861 	NEditFree(value);
862         appendToFormat(buf);
863     }
864     else
865     {
866 	int i;
867 	removeFromFormat("%d");
868 	for (i=0; i<=9; ++i)
869 	{
870 	    char buf[20];
871 	    sprintf(&buf[0], "%%%dd", i);
872 	    removeFromFormat(buf);
873 	}
874     }
875 }
876 
enterMaxDirCB(Widget w,XtPointer clientData,XtPointer callData)877 static void enterMaxDirCB(Widget w, XtPointer clientData, XtPointer callData)
878 {
879     int maxComp = -1;
880     char *format;
881     char *value;
882 
883     if (etDialog.suppressFormatUpdate)
884     {
885 	return;
886     }
887 
888     format = XmTextGetString(etDialog.formatW);
889     value = XmTextGetString(etDialog.ndirW);
890 
891     if (*value)
892     {
893 	if (sscanf(value, "%d", &maxComp) <= 0)
894 	{
895 	   /* Don't allow non-digits to be entered */
896 	   XBell(XtDisplay(w), 0);
897 	   XmTextSetString(etDialog.ndirW, "");
898 	}
899     }
900 
901     if (maxComp >= 0)
902     {
903 	char *pos;
904 	int found = False;
905 	char insert[2];
906         insert[0] = (char)('0' + maxComp);
907         insert[1] = (char)0; /* '0' digit and 0 char ! */
908 
909 	/* Find all %d and %nd occurrences and replace them by the new value */
910 	do
911 	{
912 	    int i;
913 	    found = False;
914 	    pos = strstr(format, "%d");
915 	    if (pos)
916 	    {
917      	        char* tmp = (char*)NEditMalloc((strlen(format)+2)*sizeof(char));
918 		strncpy(tmp, format, (size_t)(pos-format+1));
919 		tmp[pos-format+1] = 0;
920 		strcat(tmp, &insert[0]);
921 		strcat(tmp, pos+1);
922 		NEditFree(format);
923 		format = tmp;
924 		found = True;
925 	    }
926 
927 	    for (i=0; i<=9; ++i)
928 	    {
929         	char buf[20];
930 		sprintf(&buf[0], "%%%dd", i);
931 		if (i != maxComp)
932 		{
933 		    pos = strstr(format, &buf[0]);
934 		    if (pos)
935 		    {
936 			*(pos+1) = insert[0];
937 			found = True;
938 		    }
939 		}
940 	    }
941 	}
942 	while (found);
943     }
944     else
945     {
946 	int found = True;
947 
948 	/* Replace all %nd occurences by %d */
949 	do
950 	{
951    	    int i;
952 	    found = False;
953 	    for (i=0; i<=9; ++i)
954 	    {
955         	char buf[20];
956 		char *pos;
957 		sprintf(&buf[0], "%%%dd", i);
958 		pos = strstr(format, &buf[0]);
959 		if (pos)
960 		{
961 		    strcpy(pos+1, pos+2);
962 		    found = True;
963 		}
964 	    }
965 	}
966 	while(found);
967     }
968 
969     XmTextSetString(etDialog.formatW, format);
970     NEditFree(format);
971     NEditFree(value);
972 }
973 
createEditTitleDialog(Widget parent)974 static void createEditTitleDialog(Widget parent)
975 {
976 #define LEFT_MARGIN_POS 2
977 #define RIGHT_MARGIN_POS 98
978 #define V_MARGIN 5
979 #define RADIO_INDENT 3
980 
981     Widget buttonForm, formatLbl, previewFrame;
982     Widget previewForm, previewBox, selectFrame, selectBox, selectForm;
983     Widget testLbl, selectLbl;
984     Widget applyBtn, closeBtn, restoreBtn, helpBtn;
985     XmString s1;
986     XmFontList fontList;
987     Arg args[20];
988     int defaultBtnOffset;
989     Dimension	shadowThickness;
990     Dimension	radioHeight, textHeight;
991     Pixel background;
992 
993     int ac = 0;
994     XtSetArg(args[ac], XmNautoUnmanage, False); ac++;
995     XtSetArg(args[ac], XmNtitle, "Customize Window Title"); ac++;
996     etDialog.form = CreateFormDialog(parent, "customizeTitle", args, ac);
997 
998     /*
999      * Destroy the dialog every time it is unmapped (otherwise it 'sticks'
1000      * to the window for which it was created originally).
1001      */
1002     XtAddCallback(etDialog.form, XmNunmapCallback, wtUnmapCB, NULL);
1003     XtAddCallback(etDialog.form, XmNdestroyCallback, wtDestroyCB, NULL);
1004 
1005     etDialog.shell = XtParent(etDialog.form);
1006 
1007     /* Definition form */
1008     selectFrame = XtVaCreateManagedWidget("selectionFrame", xmFrameWidgetClass,
1009 	    etDialog.form,
1010 	    XmNleftAttachment, XmATTACH_POSITION,
1011 	    XmNleftPosition, LEFT_MARGIN_POS,
1012 	    XmNtopAttachment, XmATTACH_FORM,
1013 	    XmNtopOffset, V_MARGIN,
1014 	    XmNrightAttachment, XmATTACH_POSITION,
1015 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
1016 
1017     XtVaCreateManagedWidget("titleLabel", xmLabelGadgetClass,
1018     	    selectFrame,
1019     	    XmNlabelString,
1020 	    s1=XmStringCreateSimple("Title definition"),
1021 	    XmNchildType, XmFRAME_TITLE_CHILD,
1022 	    XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, NULL);
1023     XmStringFree(s1);
1024 
1025     selectForm = XtVaCreateManagedWidget("selectForm", xmFormWidgetClass,
1026 	    selectFrame ,
1027 	    XmNleftAttachment, XmATTACH_POSITION,
1028 	    XmNleftPosition, LEFT_MARGIN_POS,
1029 	    XmNtopAttachment, XmATTACH_FORM,
1030 	    XmNtopOffset, V_MARGIN,
1031 	    XmNrightAttachment, XmATTACH_POSITION,
1032 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
1033 
1034     selectLbl = XtVaCreateManagedWidget("selectLabel", xmLabelGadgetClass,
1035     	    selectForm,
1036     	    XmNlabelString, s1=XmStringCreateSimple("Select title components to include:  "),
1037 	    XmNleftAttachment, XmATTACH_POSITION,
1038 	    XmNleftPosition, LEFT_MARGIN_POS,
1039 	    XmNtopOffset, 5,
1040 	    XmNbottomOffset, 5,
1041 	    XmNtopAttachment, XmATTACH_FORM, NULL);
1042     XmStringFree(s1);
1043 
1044     selectBox = XtVaCreateManagedWidget("selectBox", xmFormWidgetClass,
1045     	    selectForm,
1046     	    XmNorientation, XmHORIZONTAL,
1047     	    XmNpacking, XmPACK_TIGHT,
1048     	    XmNradioBehavior, False,
1049 	    XmNleftAttachment, XmATTACH_FORM,
1050 	    XmNrightAttachment, XmATTACH_FORM,
1051 	    XmNtopOffset, 5,
1052 	    XmNtopAttachment, XmATTACH_WIDGET,
1053 	    XmNtopWidget, selectLbl,
1054 	    NULL);
1055 
1056     etDialog.fileW = XtVaCreateManagedWidget("file",
1057     	    xmToggleButtonWidgetClass, selectBox,
1058 	    XmNleftAttachment, XmATTACH_POSITION,
1059 	    XmNleftPosition, RADIO_INDENT,
1060 	    XmNtopAttachment, XmATTACH_FORM,
1061     	    XmNlabelString, s1=XmStringCreateSimple("File name (%f)"),
1062     	    XmNmnemonic, 'F', NULL);
1063     XtAddCallback(etDialog.fileW, XmNvalueChangedCallback, toggleFileCB, NULL);
1064     XmStringFree(s1);
1065 
1066     etDialog.statusW = XtVaCreateManagedWidget("status",
1067     	    xmToggleButtonWidgetClass, selectBox,
1068 	    XmNleftAttachment, XmATTACH_POSITION,
1069 	    XmNleftPosition, RADIO_INDENT,
1070 	    XmNtopAttachment, XmATTACH_WIDGET,
1071 	    XmNtopWidget, etDialog.fileW,
1072     	    XmNlabelString, s1=XmStringCreateSimple("File status (%S) "),
1073     	    XmNmnemonic, 't', NULL);
1074     XtAddCallback(etDialog.statusW, XmNvalueChangedCallback, toggleStatusCB, NULL);
1075     XmStringFree(s1);
1076 
1077     etDialog.shortStatusW = XtVaCreateManagedWidget("shortStatus",
1078     	    xmToggleButtonWidgetClass, selectBox,
1079 	    XmNleftAttachment, XmATTACH_WIDGET,
1080 	    XmNleftWidget, etDialog.statusW,
1081 	    XmNtopAttachment, XmATTACH_WIDGET,
1082 	    XmNtopWidget, etDialog.fileW,
1083     	    XmNlabelString, s1=XmStringCreateSimple("brief"),
1084     	    XmNmnemonic, 'b', NULL);
1085     XtAddCallback(etDialog.shortStatusW, XmNvalueChangedCallback, toggleShortStatusCB, NULL);
1086     XmStringFree(s1);
1087 
1088     etDialog.ccW = XtVaCreateManagedWidget("ccView",
1089     	    xmToggleButtonWidgetClass, selectBox,
1090 	    XmNleftAttachment, XmATTACH_POSITION,
1091 	    XmNleftPosition, RADIO_INDENT,
1092 	    XmNtopAttachment, XmATTACH_WIDGET,
1093 	    XmNtopWidget, etDialog.statusW,
1094     	    XmNlabelString, s1=XmStringCreateSimple("ClearCase view tag (%c) "),
1095     	    XmNmnemonic, 'C', NULL);
1096 #ifdef VMS
1097     XtSetSensitive(etDialog.ccW, False);
1098 #else
1099     XtAddCallback(etDialog.ccW, XmNvalueChangedCallback, toggleClearCaseCB, NULL);
1100 #endif /* VMS */
1101     XmStringFree(s1);
1102 
1103     etDialog.dirW = XtVaCreateManagedWidget("directory",
1104     	    xmToggleButtonWidgetClass, selectBox,
1105 	    XmNleftAttachment, XmATTACH_POSITION,
1106 	    XmNleftPosition, RADIO_INDENT,
1107 	    XmNtopAttachment, XmATTACH_WIDGET,
1108 	    XmNtopWidget, etDialog.ccW,
1109     	    XmNlabelString, s1=XmStringCreateSimple("Directory (%d),"),
1110     	    XmNmnemonic, 'D', NULL);
1111     XtAddCallback(etDialog.dirW, XmNvalueChangedCallback, toggleDirectoryCB, NULL);
1112     XmStringFree(s1);
1113 
1114     XtVaGetValues(etDialog.fileW, XmNheight, &radioHeight, NULL);
1115     etDialog.mdirW = XtVaCreateManagedWidget("componentLab",
1116     	    xmLabelGadgetClass, selectBox,
1117 	    XmNheight, radioHeight,
1118 	    XmNleftAttachment, XmATTACH_WIDGET,
1119 	    XmNleftWidget, etDialog.dirW,
1120 	    XmNtopAttachment, XmATTACH_WIDGET,
1121 	    XmNtopWidget, etDialog.ccW,
1122     	    XmNlabelString, s1=XmStringCreateSimple("max. components: "),
1123     	    XmNmnemonic, 'x', NULL);
1124     XmStringFree(s1);
1125 
1126     etDialog.ndirW = XtVaCreateManagedWidget("dircomp",
1127     	    xmTextWidgetClass, selectBox,
1128    	    XmNcolumns, 1,
1129    	    XmNmaxLength, 1,
1130 	    XmNleftAttachment, XmATTACH_WIDGET,
1131 	    XmNleftWidget, etDialog.mdirW,
1132 	    XmNtopAttachment, XmATTACH_WIDGET,
1133 	    XmNtopWidget, etDialog.ccW,
1134     	    NULL);
1135     XtAddCallback(etDialog.ndirW, XmNvalueChangedCallback, enterMaxDirCB, NULL);
1136     RemapDeleteKey(etDialog.ndirW);
1137     XtVaSetValues(etDialog.mdirW, XmNuserData, etDialog.ndirW, NULL); /* mnemonic processing */
1138 
1139     XtVaGetValues(etDialog.ndirW, XmNheight, &textHeight, NULL);
1140     XtVaSetValues(etDialog.dirW,  XmNheight, textHeight, NULL);
1141     XtVaSetValues(etDialog.mdirW, XmNheight, textHeight, NULL);
1142 
1143     etDialog.hostW = XtVaCreateManagedWidget("host",
1144     	    xmToggleButtonWidgetClass, selectBox,
1145 	    XmNleftAttachment, XmATTACH_POSITION,
1146 	    XmNleftPosition, 50 + RADIO_INDENT,
1147 	    XmNtopAttachment, XmATTACH_FORM,
1148     	    XmNlabelString, s1=XmStringCreateSimple("Host name (%h)"),
1149     	    XmNmnemonic, 'H', NULL);
1150     XtAddCallback(etDialog.hostW, XmNvalueChangedCallback, toggleHostCB, NULL);
1151     XmStringFree(s1);
1152 
1153     etDialog.nameW = XtVaCreateManagedWidget("name",
1154     	    xmToggleButtonWidgetClass, selectBox,
1155 	    XmNleftAttachment, XmATTACH_POSITION,
1156 	    XmNleftPosition, 50 + RADIO_INDENT,
1157 	    XmNtopAttachment, XmATTACH_WIDGET,
1158 	    XmNtopWidget, etDialog.hostW,
1159     	    XmNlabelString, s1=XmStringCreateSimple("User name (%u)"),
1160     	    XmNmnemonic, 'U', NULL);
1161     XtAddCallback(etDialog.nameW, XmNvalueChangedCallback, toggleUserCB, NULL);
1162     XmStringFree(s1);
1163 
1164     etDialog.serverW = XtVaCreateManagedWidget("server",
1165     	    xmToggleButtonWidgetClass, selectBox,
1166 	    XmNleftAttachment, XmATTACH_POSITION,
1167 	    XmNleftPosition, 50 + RADIO_INDENT,
1168 	    XmNtopAttachment, XmATTACH_WIDGET,
1169 	    XmNtopWidget, etDialog.nameW,
1170     	    XmNlabelString, s1=XmStringCreateSimple("NEdit server name (%s)"),
1171     	    XmNmnemonic, 's', NULL);
1172     XtAddCallback(etDialog.serverW, XmNvalueChangedCallback, toggleServerCB, NULL);
1173     XmStringFree(s1);
1174 
1175     formatLbl = XtVaCreateManagedWidget("formatLbl", xmLabelGadgetClass,
1176     	    selectForm,
1177     	    XmNlabelString, s1=XmStringCreateSimple("Format:  "),
1178     	    XmNmnemonic, 'r',
1179 	    XmNleftAttachment, XmATTACH_POSITION,
1180 	    XmNleftPosition, LEFT_MARGIN_POS,
1181 	    XmNtopAttachment, XmATTACH_WIDGET,
1182 	    XmNtopWidget, selectBox,
1183 	    XmNbottomAttachment, XmATTACH_FORM, NULL);
1184     XmStringFree(s1);
1185     etDialog.formatW = XtVaCreateManagedWidget("format", xmTextWidgetClass,
1186     	    selectForm,
1187 	    XmNmaxLength, WINDOWTITLE_MAX_LEN,
1188 	    XmNtopAttachment, XmATTACH_WIDGET,
1189 	    XmNtopWidget, selectBox,
1190 	    XmNtopOffset, 5,
1191 	    XmNleftAttachment, XmATTACH_WIDGET,
1192 	    XmNleftWidget, formatLbl,
1193 	    XmNrightAttachment, XmATTACH_POSITION,
1194 	    XmNrightPosition, RIGHT_MARGIN_POS,
1195 	    XmNbottomAttachment, XmATTACH_FORM,
1196 	    XmNbottomOffset, 5, NULL);
1197     RemapDeleteKey(etDialog.formatW);
1198     XtVaSetValues(formatLbl, XmNuserData, etDialog.formatW, NULL);
1199     XtAddCallback(etDialog.formatW, XmNvalueChangedCallback, formatChangedCB, NULL);
1200 
1201     XtVaGetValues(etDialog.formatW, XmNheight, &textHeight, NULL);
1202     XtVaSetValues(formatLbl,  XmNheight, textHeight, NULL);
1203 
1204     previewFrame = XtVaCreateManagedWidget("previewFrame", xmFrameWidgetClass,
1205 	    etDialog.form,
1206 	    XmNtopAttachment, XmATTACH_WIDGET,
1207 	    XmNtopWidget, selectFrame,
1208 	    XmNleftAttachment, XmATTACH_POSITION,
1209 	    XmNleftPosition, LEFT_MARGIN_POS,
1210 	    XmNrightAttachment, XmATTACH_POSITION,
1211 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
1212 
1213     XtVaCreateManagedWidget("previewLabel", xmLabelGadgetClass,
1214     	    previewFrame,
1215     	    XmNlabelString, s1=XmStringCreateSimple("Preview"),
1216 	    XmNchildType, XmFRAME_TITLE_CHILD,
1217 	    XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, NULL);
1218     XmStringFree(s1);
1219 
1220     previewForm = XtVaCreateManagedWidget("previewForm", xmFormWidgetClass,
1221 	    previewFrame,
1222 	    XmNleftAttachment, XmATTACH_FORM,
1223 	    XmNleftPosition, LEFT_MARGIN_POS,
1224 	    XmNtopAttachment, XmATTACH_FORM,
1225 	    XmNtopOffset, V_MARGIN,
1226 	    XmNrightAttachment, XmATTACH_FORM,
1227 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
1228 
1229     /* Copy a variable width font from one of the labels to use for the
1230        preview (no editing is allowed, and with a fixed size font the
1231        preview easily gets partially obscured). Also copy the form background
1232        color to make it clear that this field is not editable */
1233     XtVaGetValues(formatLbl, XmNfontList, &fontList, NULL);
1234     XtVaGetValues(previewForm, XmNbackground, &background, NULL);
1235 
1236     etDialog.previewW = XtVaCreateManagedWidget("sample",
1237             xmTextFieldWidgetClass, previewForm,
1238             XmNeditable, False,
1239             XmNcursorPositionVisible, False,
1240             XmNtopAttachment, XmATTACH_FORM,
1241             XmNleftAttachment, XmATTACH_FORM,
1242             XmNleftOffset, V_MARGIN,
1243             XmNrightAttachment, XmATTACH_FORM,
1244             XmNrightOffset, V_MARGIN,
1245             XmNfontList, fontList,
1246             XmNbackground, background,
1247             NULL);
1248 
1249     previewBox = XtVaCreateManagedWidget("previewBox", xmFormWidgetClass,
1250     	    previewForm,
1251     	    XmNorientation, XmHORIZONTAL,
1252     	    XmNpacking, XmPACK_TIGHT,
1253     	    XmNradioBehavior, False,
1254 	    XmNleftAttachment, XmATTACH_FORM,
1255 	    XmNrightAttachment, XmATTACH_FORM,
1256 	    XmNtopAttachment, XmATTACH_WIDGET,
1257 	    XmNtopWidget, etDialog.previewW, NULL);
1258 
1259     testLbl = XtVaCreateManagedWidget("testLabel", xmLabelGadgetClass,
1260     	    previewBox,
1261     	    XmNlabelString, s1=XmStringCreateSimple("Test settings:  "),
1262 	    XmNleftAttachment, XmATTACH_POSITION,
1263 	    XmNleftPosition, LEFT_MARGIN_POS,
1264 	    XmNtopOffset, 5,
1265 	    XmNbottomOffset, 5,
1266 	    XmNtopAttachment, XmATTACH_FORM, NULL);
1267     XmStringFree(s1);
1268 
1269     etDialog.oFileChangedW = XtVaCreateManagedWidget("fileChanged",
1270     	    xmToggleButtonWidgetClass, previewBox,
1271 	    XmNleftAttachment, XmATTACH_POSITION,
1272 	    XmNleftPosition, RADIO_INDENT,
1273 	    XmNtopAttachment, XmATTACH_WIDGET,
1274 	    XmNtopWidget, testLbl,
1275     	    XmNlabelString, s1=XmStringCreateSimple("File modified"),
1276     	    XmNmnemonic, 'o', NULL);
1277     XtAddCallback(etDialog.oFileChangedW, XmNvalueChangedCallback, fileChangedCB, NULL);
1278     XmStringFree(s1);
1279 
1280     etDialog.oFileReadOnlyW = XtVaCreateManagedWidget("fileReadOnly",
1281     	    xmToggleButtonWidgetClass, previewBox,
1282 	    XmNleftAttachment, XmATTACH_WIDGET,
1283 	    XmNleftWidget, etDialog.oFileChangedW,
1284 	    XmNtopAttachment, XmATTACH_WIDGET,
1285 	    XmNtopWidget, testLbl,
1286     	    XmNlabelString, s1=XmStringCreateSimple("File read only"),
1287     	    XmNmnemonic, 'n', NULL);
1288     XtAddCallback(etDialog.oFileReadOnlyW, XmNvalueChangedCallback, fileReadOnlyCB, NULL);
1289     XmStringFree(s1);
1290 
1291     etDialog.oFileLockedW = XtVaCreateManagedWidget("fileLocked",
1292     	    xmToggleButtonWidgetClass, previewBox,
1293 	    XmNleftAttachment, XmATTACH_WIDGET,
1294 	    XmNleftWidget, etDialog.oFileReadOnlyW,
1295 	    XmNtopAttachment, XmATTACH_WIDGET,
1296 	    XmNtopWidget, testLbl,
1297     	    XmNlabelString, s1=XmStringCreateSimple("File locked"),
1298     	    XmNmnemonic, 'l', NULL);
1299     XtAddCallback(etDialog.oFileLockedW, XmNvalueChangedCallback, fileLockedCB, NULL);
1300     XmStringFree(s1);
1301 
1302     etDialog.oServerNameW = XtVaCreateManagedWidget("servernameSet",
1303     	    xmToggleButtonWidgetClass, previewBox,
1304 	    XmNleftAttachment, XmATTACH_POSITION,
1305 	    XmNleftPosition, RADIO_INDENT,
1306 	    XmNtopAttachment, XmATTACH_WIDGET,
1307 	    XmNtopWidget, etDialog.oFileChangedW,
1308     	    XmNlabelString, s1=XmStringCreateSimple("Server name present"),
1309     	    XmNmnemonic, 'v', NULL);
1310     XtAddCallback(etDialog.oServerNameW, XmNvalueChangedCallback, serverNameCB, NULL);
1311     XmStringFree(s1);
1312 
1313     etDialog.oCcViewTagW = XtVaCreateManagedWidget("ccViewTagSet",
1314     	    xmToggleButtonWidgetClass, previewBox,
1315 	    XmNleftAttachment, XmATTACH_POSITION,
1316 	    XmNleftPosition, RADIO_INDENT,
1317 	    XmNtopAttachment, XmATTACH_WIDGET,
1318 	    XmNtopWidget, etDialog.oServerNameW,
1319     	    XmNlabelString, s1=XmStringCreateSimple("CC view tag present"),
1320 #ifdef VMS
1321    	    XmNset, False,
1322 #else
1323    	    XmNset, GetClearCaseViewTag() != NULL,
1324 #endif /* VMS */
1325     	    XmNmnemonic, 'w', NULL);
1326 #ifdef VMS
1327     XtSetSensitive(etDialog.oCcViewTagW, False);
1328 #else
1329     XtAddCallback(etDialog.oCcViewTagW, XmNvalueChangedCallback, ccViewTagCB, NULL);
1330 #endif /* VMS */
1331     XmStringFree(s1);
1332 
1333     etDialog.oServerEqualViewW = XtVaCreateManagedWidget("serverEqualView",
1334     	    xmToggleButtonWidgetClass, previewBox,
1335 	    XmNleftAttachment, XmATTACH_WIDGET,
1336     	    XmNleftWidget, etDialog.oCcViewTagW,
1337 	    XmNtopAttachment, XmATTACH_WIDGET,
1338 	    XmNtopWidget, etDialog.oServerNameW,
1339     	    XmNlabelString, s1=XmStringCreateSimple("Server name equals CC view tag  "),
1340     	    XmNmnemonic, 'q', NULL);
1341 #ifdef VMS
1342     XtSetSensitive(etDialog.oServerEqualViewW, False);
1343 #else
1344     XtAddCallback(etDialog.oServerEqualViewW, XmNvalueChangedCallback, serverEqualViewCB, NULL);
1345 #endif /* VMS */
1346     XmStringFree(s1);
1347 
1348     etDialog.oDirW = XtVaCreateManagedWidget("pathSet",
1349     	    xmToggleButtonWidgetClass, previewBox,
1350 	    XmNleftAttachment, XmATTACH_POSITION,
1351 	    XmNleftPosition, RADIO_INDENT,
1352 	    XmNtopAttachment, XmATTACH_WIDGET,
1353 	    XmNtopWidget, etDialog.oCcViewTagW,
1354     	    XmNlabelString, s1=XmStringCreateSimple("Directory present"),
1355     	    XmNmnemonic, 'i', NULL);
1356     XtAddCallback(etDialog.oDirW, XmNvalueChangedCallback, formatChangedCB, NULL);
1357     XmStringFree(s1);
1358 
1359     /* Button box */
1360     buttonForm = XtVaCreateManagedWidget("buttonForm", xmFormWidgetClass,
1361 	    etDialog.form,
1362 	    XmNleftAttachment, XmATTACH_POSITION,
1363 	    XmNleftPosition, LEFT_MARGIN_POS,
1364 	    XmNtopAttachment, XmATTACH_WIDGET,
1365 	    XmNtopWidget, previewFrame,
1366 	    XmNtopOffset, V_MARGIN,
1367 	    XmNbottomOffset, V_MARGIN,
1368 	    XmNbottomAttachment, XmATTACH_FORM,
1369 	    XmNrightAttachment, XmATTACH_POSITION,
1370 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
1371 
1372     applyBtn = XtVaCreateManagedWidget("apply", xmPushButtonWidgetClass,
1373             buttonForm,
1374     	    XmNhighlightThickness, 2,
1375             XmNlabelString, s1=XmStringCreateSimple("Apply"),
1376             XmNshowAsDefault, (short)1,
1377     	    XmNleftAttachment, XmATTACH_POSITION,
1378     	    XmNleftPosition, 6,
1379     	    XmNrightAttachment, XmATTACH_POSITION,
1380     	    XmNrightPosition, 25,
1381     	    XmNbottomAttachment, XmATTACH_FORM,
1382 	    NULL);
1383     XtAddCallback(applyBtn, XmNactivateCallback, applyCB, NULL);
1384     XmStringFree(s1);
1385     XtVaGetValues(applyBtn, XmNshadowThickness, &shadowThickness, NULL);
1386     defaultBtnOffset = shadowThickness + 4;
1387 
1388     closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass,
1389             buttonForm,
1390     	    XmNhighlightThickness, 2,
1391     	    XmNlabelString, s1=XmStringCreateSimple("Close"),
1392     	    XmNleftAttachment, XmATTACH_POSITION,
1393     	    XmNleftPosition, 52,
1394     	    XmNrightAttachment, XmATTACH_POSITION,
1395     	    XmNrightPosition, 71,
1396     	    XmNbottomAttachment, XmATTACH_FORM,
1397             XmNbottomOffset, defaultBtnOffset,
1398 	    NULL);
1399     XtAddCallback(closeBtn, XmNactivateCallback, closeCB, NULL);
1400     XmStringFree(s1);
1401 
1402     restoreBtn = XtVaCreateManagedWidget("restore", xmPushButtonWidgetClass,
1403             buttonForm,
1404     	    XmNhighlightThickness, 2,
1405     	    XmNlabelString, s1=XmStringCreateSimple("Default"),
1406     	    XmNleftAttachment, XmATTACH_POSITION,
1407     	    XmNleftPosition, 29,
1408     	    XmNrightAttachment, XmATTACH_POSITION,
1409     	    XmNrightPosition, 48,
1410     	    XmNbottomAttachment, XmATTACH_FORM,
1411             XmNbottomOffset, defaultBtnOffset,
1412 	    XmNmnemonic, 'e', NULL);
1413     XtAddCallback(restoreBtn, XmNactivateCallback, restoreCB, NULL);
1414     XmStringFree(s1);
1415 
1416     helpBtn = XtVaCreateManagedWidget("help", xmPushButtonWidgetClass,
1417             buttonForm,
1418     	    XmNhighlightThickness, 2,
1419     	    XmNlabelString, s1=XmStringCreateSimple("Help"),
1420     	    XmNleftAttachment, XmATTACH_POSITION,
1421     	    XmNleftPosition, 75,
1422     	    XmNrightAttachment, XmATTACH_POSITION,
1423     	    XmNrightPosition, 94,
1424     	    XmNbottomAttachment, XmATTACH_FORM,
1425             XmNbottomOffset, defaultBtnOffset,
1426 	    XmNmnemonic, 'p', NULL);
1427     XtAddCallback(helpBtn, XmNactivateCallback, helpCB, NULL);
1428     XmStringFree(s1);
1429 
1430     /* Set initial default button */
1431     XtVaSetValues(etDialog.form, XmNdefaultButton, applyBtn, NULL);
1432     XtVaSetValues(etDialog.form, XmNcancelButton, closeBtn, NULL);
1433 
1434     /* Handle mnemonic selection of buttons and focus to dialog */
1435     AddDialogMnemonicHandler(etDialog.form, FALSE);
1436 
1437     etDialog.suppressFormatUpdate = FALSE;
1438 }
1439 
EditCustomTitleFormat(WindowInfo * window)1440 void EditCustomTitleFormat(WindowInfo *window)
1441 {
1442     /* copy attributes from current window so that we can use as many
1443      * 'real world' defaults as possible when testing the effect
1444      * of different formatting strings.
1445      */
1446     strcpy(etDialog.path, window->path);
1447     strcpy(etDialog.filename, window->filename);
1448 #ifndef VMS
1449     strcpy(etDialog.viewTag, GetClearCaseViewTag() != NULL ?
1450                              GetClearCaseViewTag() :
1451                              "viewtag");
1452 #endif /* VMS */
1453     strcpy(etDialog.serverName, IsServer ?
1454                              GetPrefServerName() :
1455                              "servername");
1456     etDialog.isServer    = IsServer;
1457     etDialog.filenameSet = window->filenameSet;
1458     etDialog.lockReasons = window->lockReasons;
1459     etDialog.fileChanged = window->fileChanged;
1460 
1461     if (etDialog.window != window && etDialog.form)
1462     {
1463        /* Destroy the dialog owned by the other window.
1464           Note: don't rely on the destroy event handler to reset the
1465                 form. Events are handled asynchronously, so the old dialog
1466                 may continue to live for a while. */
1467        XtDestroyWidget(etDialog.form);
1468        etDialog.form = NULL;
1469     }
1470 
1471     etDialog.window      = window;
1472 
1473     /* Create the dialog if it doesn't already exist */
1474     if (etDialog.form == NULL)
1475     {
1476         createEditTitleDialog(window->shell);
1477     }
1478     else
1479     {
1480         /* If the window is already up, just pop it to the top */
1481         if (XtIsManaged(etDialog.form)) {
1482 
1483 	    RaiseDialogWindow(XtParent(etDialog.form));
1484 
1485             /* force update of the dialog */
1486             setToggleButtons();
1487             formatChangedCB(0, 0, 0);
1488 	    return;
1489         }
1490     }
1491 
1492     /* set initial value of format field */
1493     XmTextSetString(etDialog.formatW, (char *)GetPrefTitleFormat());
1494 
1495     /* force update of the dialog */
1496     setToggleButtons();
1497     formatChangedCB(0, 0, 0);
1498 
1499     /* put up dialog and wait for user to press ok or cancel */
1500     ManageDialogCenteredOnPointer(etDialog.form);
1501 }
1502