UNIXworkcode

/******************************************************************************* * * * windowTitle.c -- Nirvana Editor window title customization * * * * Copyright (C) 2001, Arne Forlie * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * * Written by Arne Forlie, http://arne.forlie.com * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "windowTitle.h" #include "textBuf.h" #include "nedit.h" #include "preferences.h" #include "help.h" #include "../util/prefFile.h" #include "../util/misc.h" #include "../util/DialogF.h" #include "../util/utils.h" #include "../util/fileUtils.h" #include "../util/nedit_malloc.h" #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <sys/param.h> #include "../util/clearcase.h" #include <Xm/Xm.h> #include <Xm/SelectioB.h> #include <Xm/Form.h> #include <Xm/List.h> #include <Xm/SeparatoG.h> #include <Xm/LabelG.h> #include <Xm/PushBG.h> #include <Xm/PushB.h> #include <Xm/ToggleBG.h> #include <Xm/ToggleB.h> #include <Xm/RowColumn.h> #include <Xm/CascadeBG.h> #include <Xm/Frame.h> #include <Xm/Text.h> #include <Xm/TextF.h> #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define WINDOWTITLE_MAX_LEN 500 /* Customize window title dialog information */ static struct { Widget form; Widget shell; WindowInfo* window; Widget previewW; Widget formatW; Widget ccW; Widget fileW; Widget hostW; Widget dirW; Widget statusW; Widget shortStatusW; Widget serverW; Widget nameW; Widget mdirW; Widget ndirW; Widget encW; Widget oDirW; Widget oCcViewTagW; Widget oServerNameW; Widget oFileChangedW; Widget oFileLockedW; Widget oFileReadOnlyW; Widget oServerEqualViewW; char filename[MAXPATHLEN]; char path[MAXPATHLEN]; char viewTag[MAXPATHLEN]; char serverName[MAXPATHLEN]; int isServer; int filenameSet; int lockReasons; int fileChanged; int suppressFormatUpdate; } etDialog = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,"","","","",0,0,0,0,0}; static char* removeSequence(char* sourcePtr, char c) { while (*sourcePtr == c) { sourcePtr++; } return(sourcePtr); } /* ** Two functions for performing safe insertions into a finite ** size buffer so that we don't get any memory overruns. */ static char* safeStrCpy(char* dest, char* destEnd, const char* source) { int len = (int)strlen(source); if (len <= (destEnd - dest)) { strcpy(dest, source); return(dest + len); } else { strncpy(dest, source, destEnd - dest); *destEnd = '\0'; return(destEnd); } } static char* safeCharAdd(char* dest, const char* destEnd, char c) { if (destEnd - dest > 0) { *dest++ = c; *dest = '\0'; } return(dest); } /* ** Remove empty paranthesis pairs and multiple spaces in a row ** with one space. ** Also remove leading and trailing spaces and dashes. */ static void compressWindowTitle(char *title) { /* Compress the title */ int modified; do { char *sourcePtr = title; char *destPtr = sourcePtr; char c = *sourcePtr++; modified = False; /* Remove leading spaces and dashes */ while (c == ' ' || c == '-') { c= *sourcePtr++; } /* Remove empty constructs */ while (c != '\0') { switch (c) { /* remove sequences */ case ' ': case '-': sourcePtr = removeSequence(sourcePtr, c); *destPtr++ = c; /* leave one */ break; /* remove empty paranthesis pairs */ case '(': if (*sourcePtr == ')') { modified = True; sourcePtr++; } else *destPtr++ = c; sourcePtr = removeSequence(sourcePtr, ' '); break; case '[': if (*sourcePtr == ']') { modified = True; sourcePtr++; } else *destPtr++ = c; sourcePtr = removeSequence(sourcePtr, ' '); break; case '{': if (*sourcePtr == '}') { modified = True; sourcePtr++; } else *destPtr++ = c; sourcePtr = removeSequence(sourcePtr, ' '); break; default: *destPtr++ = c; break; } c = *sourcePtr++; *destPtr = '\0'; } /* Remove trailing spaces and dashes */ while (destPtr-- > title) { if (*destPtr != ' ' && *destPtr != '-') break; *destPtr = '\0'; } } while (modified == True); } /* ** Format the windows title using a printf like formatting string. ** The following flags are recognised: ** %c : ClearCase view tag ** %s : server name ** %[n]d : directory, with one optional digit specifying the max number ** of trailing directory components to display. Skipped components are ** replaced by an ellipsis (...). ** %f : file name ** %h : host name ** %S : file status ** %u : user name ** %e : file encoding ** ** if the ClearCase view tag and server name are identical, only the first one ** specified in the formatting string will be displayed. */ char *FormatWindowTitle(const char* filename, const char* path, const char* clearCaseViewTag, const char* serverName, const char* encoding, int isServer, int filenameSet, int lockReasons, int fileChanged, const char* titleFormat) { static char title[WINDOWTITLE_MAX_LEN]; title[WINDOWTITLE_MAX_LEN-1] = 0; char *titlePtr = title; char* titleEnd = title + WINDOWTITLE_MAX_LEN - 1; /* Flags to supress one of these if both are specified and they are identical */ int serverNameSeen = False; int clearCaseViewTagSeen = False; int fileNamePresent = False; int hostNamePresent = False; int userNamePresent = False; int serverNamePresent = False; int clearCasePresent = False; int encodingPresent = False; int fileStatusPresent = False; int dirNamePresent = False; int noOfComponents = -1; int shortStatus = False; size_t enc_len = 0; const char *enc = NULL; *titlePtr = '\0'; /* always start with an empty string */ while (*titleFormat != '\0' && titlePtr < titleEnd) { char c = *titleFormat++; if (c == '%') { c = *titleFormat++; if (c == '\0') { titlePtr = safeCharAdd(titlePtr, titleEnd, '%'); break; } switch (c) { case 'c': /* ClearCase view tag */ clearCasePresent = True; if (clearCaseViewTag != NULL) { if (serverNameSeen == False || strcmp(serverName, clearCaseViewTag) != 0) { titlePtr = safeStrCpy(titlePtr, titleEnd, clearCaseViewTag); clearCaseViewTagSeen = True; } } break; case 's': /* server name */ serverNamePresent = True; if (isServer && serverName[0] != '\0') { /* only applicable for servers */ if (clearCaseViewTagSeen == False || strcmp(serverName, clearCaseViewTag) != 0) { titlePtr = safeStrCpy(titlePtr, titleEnd, serverName); serverNameSeen = True; } } break; case 'd': /* directory without any limit to no. of components */ dirNamePresent = True; if (filenameSet) { titlePtr = safeStrCpy(titlePtr, titleEnd, path); } break; case 'e': /* file encoding */ encodingPresent = True; enc_len = encoding ? strlen(encoding) : 0; enc = encoding; if(enc_len == 0) { enc = GetPrefDefaultCharset(); } titlePtr = safeStrCpy(titlePtr, titleEnd, enc); break; case '0': /* directory with limited no. of components */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (*titleFormat == 'd') { dirNamePresent = True; noOfComponents = c - '0'; titleFormat++; /* delete the argument */ if (filenameSet) { const char* trailingPath = GetTrailingPathComponents(path, noOfComponents); /* prefix with ellipsis if components were skipped */ if (trailingPath > path) { titlePtr = safeStrCpy(titlePtr, titleEnd, "..."); } titlePtr = safeStrCpy(titlePtr, titleEnd, trailingPath); } } break; case 'f': /* file name */ fileNamePresent = True; titlePtr = safeStrCpy(titlePtr, titleEnd, filename); break; case 'h': /* host name */ hostNamePresent = True; titlePtr = safeStrCpy(titlePtr, titleEnd, GetNameOfHost()); break; case 'S': /* file status */ fileStatusPresent = True; if (IS_ANY_LOCKED_IGNORING_USER(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "read only, modified"); else if (IS_ANY_LOCKED_IGNORING_USER(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "read only"); else if (IS_USER_LOCKED(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "locked, modified"); else if (IS_USER_LOCKED(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "locked"); else if (fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "modified"); break; case 'u': /* user name */ userNamePresent = True; titlePtr = safeStrCpy(titlePtr, titleEnd, GetUserName()); break; case '%': /* escaped % */ titlePtr = safeCharAdd(titlePtr, titleEnd, '%'); break; case '*': /* short file status ? */ fileStatusPresent = True; if (*titleFormat == 'S') { ++titleFormat; shortStatus = True; if (IS_ANY_LOCKED_IGNORING_USER(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "RO*"); else if (IS_ANY_LOCKED_IGNORING_USER(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "RO"); else if (IS_USER_LOCKED(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "LO*"); else if (IS_USER_LOCKED(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "LO"); else if (fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "*"); break; } /* fall-through */ default: titlePtr = safeCharAdd(titlePtr, titleEnd, c); break; } } else { titlePtr = safeCharAdd(titlePtr, titleEnd, c); } } compressWindowTitle(title); if (title[0] == 0) { snprintf(&title[0], WINDOWTITLE_MAX_LEN-1, "<empty>"); /* For preview purposes only */ } if (etDialog.form) { /* Prevent recursive callback loop */ etDialog.suppressFormatUpdate = True; /* Sync radio buttons with format string (in case the user entered the format manually) */ XmToggleButtonSetState(etDialog.fileW, fileNamePresent, False); XmToggleButtonSetState(etDialog.statusW, fileStatusPresent, False); XmToggleButtonSetState(etDialog.serverW, serverNamePresent, False); XmToggleButtonSetState(etDialog.ccW, clearCasePresent, False); XmToggleButtonSetState(etDialog.encW, encodingPresent, False); XmToggleButtonSetState(etDialog.dirW, dirNamePresent, False); XmToggleButtonSetState(etDialog.hostW, hostNamePresent, False); XmToggleButtonSetState(etDialog.nameW, userNamePresent, False); XtSetSensitive(etDialog.shortStatusW, fileStatusPresent); if (fileStatusPresent) { XmToggleButtonSetState(etDialog.shortStatusW, shortStatus, False); } /* Directory components are also sensitive to presence of dir */ XtSetSensitive(etDialog.ndirW, dirNamePresent); XtSetSensitive(etDialog.mdirW, dirNamePresent); if (dirNamePresent) /* Avoid erasing number when not active */ { if (noOfComponents >= 0) { char* value = XmTextGetString(etDialog.ndirW); char buf[16]; snprintf(&buf[0], 16, "%d", noOfComponents); if (strcmp(&buf[0], value)) /* Don't overwrite unless diff. */ SetIntText(etDialog.ndirW, noOfComponents); NEditFree(value); } else { XmTextSetString(etDialog.ndirW, ""); } } /* Enable/disable test buttons, depending on presence of codes */ XtSetSensitive(etDialog.oFileChangedW, fileStatusPresent); XtSetSensitive(etDialog.oFileReadOnlyW, fileStatusPresent); XtSetSensitive(etDialog.oFileLockedW, fileStatusPresent && !IS_PERM_LOCKED(etDialog.lockReasons)); XtSetSensitive(etDialog.oServerNameW, serverNamePresent); #ifndef VMS XtSetSensitive(etDialog.oCcViewTagW, clearCasePresent); XtSetSensitive(etDialog.oServerEqualViewW, clearCasePresent && serverNamePresent); #endif /* VMS */ XtSetSensitive(etDialog.oDirW, dirNamePresent); etDialog.suppressFormatUpdate = False; } return(title); } /* a utility that sets the values of all toggle buttons */ static void setToggleButtons(void) { XmToggleButtonSetState(etDialog.oDirW, etDialog.filenameSet == True, False); XmToggleButtonSetState(etDialog.oFileChangedW, etDialog.fileChanged == True, False); XmToggleButtonSetState(etDialog.oFileReadOnlyW, IS_PERM_LOCKED(etDialog.lockReasons), False); XmToggleButtonSetState(etDialog.oFileLockedW, IS_USER_LOCKED(etDialog.lockReasons), False); /* Read-only takes precedence on locked */ XtSetSensitive(etDialog.oFileLockedW, !IS_PERM_LOCKED(etDialog.lockReasons)); #ifdef VMS XmToggleButtonSetState(etDialog.oServerNameW, etDialog.isServer, False); #else XmToggleButtonSetState(etDialog.oCcViewTagW, GetClearCaseViewTag() != NULL, False); XmToggleButtonSetState(etDialog.oServerNameW, etDialog.isServer, False); if (GetClearCaseViewTag() != NULL && etDialog.isServer && GetPrefServerName()[0] != '\0' && strcmp(GetClearCaseViewTag(), GetPrefServerName()) == 0) { XmToggleButtonSetState(etDialog.oServerEqualViewW, True, False); } else { XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False); } #endif /* VMS */ } static void formatChangedCB(Widget w, XtPointer clientData, XtPointer callData) { char *format; int filenameSet = XmToggleButtonGetState(etDialog.oDirW); char *title; const char* serverName; if (etDialog.suppressFormatUpdate) { return; /* Prevent recursive feedback */ } format = XmTextGetString(etDialog.formatW); #ifndef VMS if (XmToggleButtonGetState(etDialog.oServerEqualViewW) && XmToggleButtonGetState(etDialog.ccW)) { serverName = etDialog.viewTag; } else #endif /* VMS */ { serverName = XmToggleButtonGetState(etDialog.oServerNameW) ? etDialog.serverName : ""; } title = FormatWindowTitle( etDialog.filename, etDialog.filenameSet == True ? etDialog.path : "/a/very/long/path/used/as/example/", XmToggleButtonGetState(etDialog.oCcViewTagW) ? etDialog.viewTag : NULL, serverName, NULL, etDialog.isServer, filenameSet, etDialog.lockReasons, XmToggleButtonGetState(etDialog.oFileChangedW), format); NEditFree(format); XmTextFieldSetString(etDialog.previewW, title); } #ifndef VMS static void ccViewTagCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(w) == False) { XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False); } formatChangedCB(w, clientData, callData); } #endif /* VMS */ static void serverNameCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(w) == False) { XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False); } etDialog.isServer = XmToggleButtonGetState(w); formatChangedCB(w, clientData, callData); } static void fileChangedCB(Widget w, XtPointer clientData, XtPointer callData) { etDialog.fileChanged = XmToggleButtonGetState(w); formatChangedCB(w, clientData, callData); } static void fileLockedCB(Widget w, XtPointer clientData, XtPointer callData) { SET_USER_LOCKED(etDialog.lockReasons, XmToggleButtonGetState(w)); formatChangedCB(w, clientData, callData); } static void fileReadOnlyCB(Widget w, XtPointer clientData, XtPointer callData) { SET_PERM_LOCKED(etDialog.lockReasons, XmToggleButtonGetState(w)); formatChangedCB(w, clientData, callData); } #ifndef VMS static void serverEqualViewCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(w) == True) { XmToggleButtonSetState(etDialog.oCcViewTagW, True, False); XmToggleButtonSetState(etDialog.oServerNameW, True, False); etDialog.isServer = True; } formatChangedCB(w, clientData, callData); } #endif /* VMS */ static void applyCB(Widget w, XtPointer clientData, XtPointer callData) { char *format = XmTextGetString(etDialog.formatW); /* pop down the dialog */ /* XtUnmanageChild(etDialog.form); */ if (strcmp(format, GetPrefTitleFormat()) != 0) { SetPrefTitleFormat(format); } NEditFree(format); } static void closeCB(Widget w, XtPointer clientData, XtPointer callData) { /* pop down the dialog */ XtUnmanageChild(etDialog.form); } static void restoreCB(Widget w, XtPointer clientData, XtPointer callData) { XmTextSetString(etDialog.formatW, "{%c} [%s] %f (%S) - %d"); } static void helpCB(Widget w, XtPointer clientData, XtPointer callData) { Help(HELP_CUSTOM_TITLE_DIALOG); } static void wtDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { if (w == etDialog.form) /* Prevent disconnecting the replacing dialog */ etDialog.form = NULL; } static void wtUnmapCB(Widget w, XtPointer clientData, XtPointer callData) { if (etDialog.form == w) /* Prevent destroying the replacing dialog */ XtDestroyWidget(etDialog.form); } static void appendToFormat(const char* string) { char *format = XmTextGetString(etDialog.formatW); char *buf = (char*)NEditMalloc(strlen(string) + strlen(format) + 1); strcpy(buf, format); strcat(buf, string); XmTextSetString(etDialog.formatW, buf); NEditFree(format); NEditFree(buf); } static void removeFromFormat(const char* string) { char *format = XmTextGetString(etDialog.formatW); char* pos; /* There can be multiple occurences */ while ((pos = strstr(format, string))) { /* If the string is preceded or followed by a brace, include the brace(s) for removal */ char* start = pos; char* end = pos + strlen(string); char post = *end; if (post == '}' || post == ')' || post == ']' || post == '>') { end += 1; post = *end; } if (start > format) { char pre = *(start-1); if (pre == '{' || pre == '(' || pre == '[' || pre == '<') start -= 1; } if (start > format) { char pre = *(start-1); /* If there is a space in front and behind, remove one space (there can be more spaces, but in that case it is likely that the user entered them manually); also remove trailing space */ if (pre == ' ' && post == ' ') { end += 1; } else if (pre == ' ' && post == (char)0) { /* Remove (1) trailing space */ start -= 1; } } /* Contract the string: move end to start */ strcpy(start, end); } /* Remove leading and trailing space */ pos = format; while (*pos == ' ') ++pos; strcpy(format, pos); pos = format + strlen(format) - 1; while (pos >= format && *pos == ' ') { --pos; } *(pos+1) = (char)0; XmTextSetString(etDialog.formatW, format); NEditFree(format); } static void toggleFileCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.fileW)) appendToFormat(" %f"); else removeFromFormat("%f"); } static void toggleServerCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.serverW)) appendToFormat(" [%s]"); else removeFromFormat("%s"); } static void toggleHostCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.hostW)) appendToFormat(" [%h]"); else removeFromFormat("%h"); } #ifndef VMS static void toggleClearCaseCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.ccW)) appendToFormat(" {%c}"); else removeFromFormat("%c"); } #endif /* VMS */ static void toggleStatusCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.statusW)) { if (XmToggleButtonGetState(etDialog.shortStatusW)) appendToFormat(" (%*S)"); else appendToFormat(" (%S)"); } else { removeFromFormat("%S"); removeFromFormat("%*S"); } } static void toggleShortStatusCB(Widget w, XtPointer clientData, XtPointer callData) { char *format, *pos; if (etDialog.suppressFormatUpdate) { return; } format = XmTextGetString(etDialog.formatW); if (XmToggleButtonGetState(etDialog.shortStatusW)) { /* Find all %S occurrences and replace them by %*S */ do { pos = strstr(format, "%S"); if (pos) { char* tmp = (char*)NEditMalloc((strlen(format)+2)*sizeof(char)); strncpy(tmp, format, (size_t)(pos-format+1)); tmp[pos-format+1] = 0; strcat(tmp, "*"); strcat(tmp, pos+1); NEditFree(format); format = tmp; } } while (pos); } else { /* Replace all %*S occurences by %S */ do { pos = strstr(format, "%*S"); if (pos) { strcpy(pos+1, pos+2); } } while(pos); } XmTextSetString(etDialog.formatW, format); NEditFree(format); } static void toggleUserCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.nameW)) appendToFormat(" %u"); else removeFromFormat("%u"); } static void toggleEncodingCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.encW)) appendToFormat(" %e"); else removeFromFormat("%e"); } static void toggleDirectoryCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.dirW)) { char buf[20]; buf[19] = 0; int maxComp; char *value = XmTextGetString(etDialog.ndirW); if (*value) { if (sscanf(value, "%d", &maxComp) > 0) { snprintf(&buf[0], 19, " %%%dd ", maxComp); } else { snprintf(&buf[0], 19, " %%d "); /* Should not be necessary */ } } else { snprintf(&buf[0], 19, " %%d "); } NEditFree(value); appendToFormat(buf); } else { int i; removeFromFormat("%d"); for (i=0; i<=9; ++i) { char buf[20]; snprintf(&buf[0], 19, "%%%dd", i); removeFromFormat(buf); } } } static void enterMaxDirCB(Widget w, XtPointer clientData, XtPointer callData) { int maxComp = -1; char *format; char *value; if (etDialog.suppressFormatUpdate) { return; } format = XmTextGetString(etDialog.formatW); value = XmTextGetString(etDialog.ndirW); if (*value) { if (sscanf(value, "%d", &maxComp) <= 0) { /* Don't allow non-digits to be entered */ XBell(XtDisplay(w), 0); XmTextSetString(etDialog.ndirW, ""); } } if (maxComp >= 0) { char *pos; int found = False; char insert[2]; insert[0] = (char)('0' + maxComp); insert[1] = (char)0; /* '0' digit and 0 char ! */ /* Find all %d and %nd occurrences and replace them by the new value */ do { int i; found = False; pos = strstr(format, "%d"); if (pos) { char* tmp = (char*)NEditMalloc((strlen(format)+2)*sizeof(char)); strncpy(tmp, format, (size_t)(pos-format+1)); tmp[pos-format+1] = 0; strcat(tmp, &insert[0]); strcat(tmp, pos+1); NEditFree(format); format = tmp; found = True; } for (i=0; i<=9; ++i) { char buf[20]; snprintf(&buf[0], 20, "%%%dd", i); if (i != maxComp) { pos = strstr(format, &buf[0]); if (pos) { *(pos+1) = insert[0]; found = True; } } } } while (found); } else { int found = True; /* Replace all %nd occurences by %d */ do { int i; found = False; for (i=0; i<=9; ++i) { char buf[20]; char *pos; snprintf(&buf[0], 20, "%%%dd", i); pos = strstr(format, &buf[0]); if (pos) { strcpy(pos+1, pos+2); found = True; } } } while(found); } XmTextSetString(etDialog.formatW, format); NEditFree(format); NEditFree(value); } static void createEditTitleDialog(Widget parent) { #define LEFT_MARGIN_POS 2 #define RIGHT_MARGIN_POS 98 #define V_MARGIN 5 #define RADIO_INDENT 3 Widget buttonForm, formatLbl, previewFrame; Widget previewForm, previewBox, selectFrame, selectBox, selectForm; Widget testLbl, selectLbl; Widget applyBtn, closeBtn, restoreBtn, helpBtn; XmString s1; XmFontList fontList; Arg args[20]; int defaultBtnOffset; Dimension shadowThickness; Dimension radioHeight, textHeight; Pixel background; int ac = 0; XtSetArg(args[ac], XmNautoUnmanage, False); ac++; XtSetArg(args[ac], XmNtitle, "Customize Window Title"); ac++; etDialog.form = CreateFormDialog(parent, "customizeTitle", args, ac); /* * Destroy the dialog every time it is unmapped (otherwise it 'sticks' * to the window for which it was created originally). */ XtAddCallback(etDialog.form, XmNunmapCallback, wtUnmapCB, NULL); XtAddCallback(etDialog.form, XmNdestroyCallback, wtDestroyCB, NULL); etDialog.shell = XtParent(etDialog.form); /* Definition form */ selectFrame = XtVaCreateManagedWidget("selectionFrame", xmFrameWidgetClass, etDialog.form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, V_MARGIN, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); XtVaCreateManagedWidget("titleLabel", xmLabelGadgetClass, selectFrame, XmNlabelString, s1=XmStringCreateSimple("Title definition"), XmNchildType, XmFRAME_TITLE_CHILD, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, NULL); XmStringFree(s1); selectForm = XtVaCreateManagedWidget("selectForm", xmFormWidgetClass, selectFrame , XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, V_MARGIN, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); selectLbl = XtVaCreateManagedWidget("selectLabel", xmLabelGadgetClass, selectForm, XmNlabelString, s1=XmStringCreateSimple("Select title components to include: "), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopOffset, 5, XmNbottomOffset, 5, XmNtopAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); selectBox = XtVaCreateManagedWidget("selectBox", xmFormWidgetClass, selectForm, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNradioBehavior, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectLbl, NULL); etDialog.fileW = XtVaCreateManagedWidget("file", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_FORM, XmNlabelString, s1=XmStringCreateSimple("File name (%f)"), XmNmnemonic, 'F', NULL); XtAddCallback(etDialog.fileW, XmNvalueChangedCallback, toggleFileCB, NULL); XmStringFree(s1); etDialog.statusW = XtVaCreateManagedWidget("status", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.fileW, XmNlabelString, s1=XmStringCreateSimple("File status (%S) "), XmNmnemonic, 't', NULL); XtAddCallback(etDialog.statusW, XmNvalueChangedCallback, toggleStatusCB, NULL); XmStringFree(s1); etDialog.shortStatusW = XtVaCreateManagedWidget("shortStatus", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.statusW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.fileW, XmNlabelString, s1=XmStringCreateSimple("brief"), XmNmnemonic, 'b', NULL); XtAddCallback(etDialog.shortStatusW, XmNvalueChangedCallback, toggleShortStatusCB, NULL); XmStringFree(s1); etDialog.ccW = XtVaCreateManagedWidget("ccView", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.statusW, XmNlabelString, s1=XmStringCreateSimple("ClearCase view tag (%c) "), XmNmnemonic, 'C', NULL); XtAddCallback(etDialog.ccW, XmNvalueChangedCallback, toggleClearCaseCB, NULL); XmStringFree(s1); etDialog.encW = XtVaCreateManagedWidget("encoding", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.ccW, XmNlabelString, s1=XmStringCreateSimple("Encoding (%e)"), XmNmnemonic, 'E', NULL); XtAddCallback(etDialog.encW, XmNvalueChangedCallback, toggleEncodingCB, NULL); XmStringFree(s1); etDialog.dirW = XtVaCreateManagedWidget("directory", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.encW, XmNlabelString, s1=XmStringCreateSimple("Directory (%d),"), XmNmnemonic, 'D', NULL); XtAddCallback(etDialog.dirW, XmNvalueChangedCallback, toggleDirectoryCB, NULL); XmStringFree(s1); XtVaGetValues(etDialog.fileW, XmNheight, &radioHeight, NULL); etDialog.mdirW = XtVaCreateManagedWidget("componentLab", xmLabelGadgetClass, selectBox, XmNheight, radioHeight, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.dirW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.encW, XmNlabelString, s1=XmStringCreateSimple("max. components: "), XmNmnemonic, 'x', NULL); XmStringFree(s1); etDialog.ndirW = XtVaCreateManagedWidget("dircomp", xmTextWidgetClass, selectBox, XmNcolumns, 1, XmNmaxLength, 1, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.mdirW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.encW, NULL); XtAddCallback(etDialog.ndirW, XmNvalueChangedCallback, enterMaxDirCB, NULL); RemapDeleteKey(etDialog.ndirW); XtVaSetValues(etDialog.mdirW, XmNuserData, etDialog.ndirW, NULL); /* mnemonic processing */ XtVaGetValues(etDialog.ndirW, XmNheight, &textHeight, NULL); XtVaSetValues(etDialog.dirW, XmNheight, textHeight, NULL); XtVaSetValues(etDialog.mdirW, XmNheight, textHeight, NULL); etDialog.hostW = XtVaCreateManagedWidget("host", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50 + RADIO_INDENT, XmNtopAttachment, XmATTACH_FORM, XmNlabelString, s1=XmStringCreateSimple("Host name (%h)"), XmNmnemonic, 'H', NULL); XtAddCallback(etDialog.hostW, XmNvalueChangedCallback, toggleHostCB, NULL); XmStringFree(s1); etDialog.nameW = XtVaCreateManagedWidget("name", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50 + RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.hostW, XmNlabelString, s1=XmStringCreateSimple("User name (%u)"), XmNmnemonic, 'U', NULL); XtAddCallback(etDialog.nameW, XmNvalueChangedCallback, toggleUserCB, NULL); XmStringFree(s1); etDialog.serverW = XtVaCreateManagedWidget("server", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50 + RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.nameW, XmNlabelString, s1=XmStringCreateSimple("NEdit server name (%s)"), XmNmnemonic, 's', NULL); XtAddCallback(etDialog.serverW, XmNvalueChangedCallback, toggleServerCB, NULL); XmStringFree(s1); formatLbl = XtVaCreateManagedWidget("formatLbl", xmLabelGadgetClass, selectForm, XmNlabelString, s1=XmStringCreateSimple("Format: "), XmNmnemonic, 'r', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectBox, XmNbottomAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); etDialog.formatW = XtVaCreateManagedWidget("format", xmTextWidgetClass, selectForm, XmNmaxLength, WINDOWTITLE_MAX_LEN, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectBox, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, formatLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, NULL); RemapDeleteKey(etDialog.formatW); XtVaSetValues(formatLbl, XmNuserData, etDialog.formatW, NULL); XtAddCallback(etDialog.formatW, XmNvalueChangedCallback, formatChangedCB, NULL); XtVaGetValues(etDialog.formatW, XmNheight, &textHeight, NULL); XtVaSetValues(formatLbl, XmNheight, textHeight, NULL); previewFrame = XtVaCreateManagedWidget("previewFrame", xmFrameWidgetClass, etDialog.form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectFrame, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); XtVaCreateManagedWidget("previewLabel", xmLabelGadgetClass, previewFrame, XmNlabelString, s1=XmStringCreateSimple("Preview"), XmNchildType, XmFRAME_TITLE_CHILD, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, NULL); XmStringFree(s1); previewForm = XtVaCreateManagedWidget("previewForm", xmFormWidgetClass, previewFrame, XmNleftAttachment, XmATTACH_FORM, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, V_MARGIN, XmNrightAttachment, XmATTACH_FORM, XmNrightPosition, RIGHT_MARGIN_POS, NULL); /* Copy a variable width font from one of the labels to use for the preview (no editing is allowed, and with a fixed size font the preview easily gets partially obscured). Also copy the form background color to make it clear that this field is not editable */ XtVaGetValues(formatLbl, XmNfontList, &fontList, NULL); XtVaGetValues(previewForm, XmNbackground, &background, NULL); etDialog.previewW = XtVaCreateManagedWidget("sample", xmTextFieldWidgetClass, previewForm, XmNeditable, False, XmNcursorPositionVisible, False, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, V_MARGIN, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, V_MARGIN, XmNfontList, fontList, XmNbackground, background, NULL); previewBox = XtVaCreateManagedWidget("previewBox", xmFormWidgetClass, previewForm, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNradioBehavior, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.previewW, NULL); testLbl = XtVaCreateManagedWidget("testLabel", xmLabelGadgetClass, previewBox, XmNlabelString, s1=XmStringCreateSimple("Test settings: "), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopOffset, 5, XmNbottomOffset, 5, XmNtopAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); etDialog.oFileChangedW = XtVaCreateManagedWidget("fileChanged", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, testLbl, XmNlabelString, s1=XmStringCreateSimple("File modified"), XmNmnemonic, 'o', NULL); XtAddCallback(etDialog.oFileChangedW, XmNvalueChangedCallback, fileChangedCB, NULL); XmStringFree(s1); etDialog.oFileReadOnlyW = XtVaCreateManagedWidget("fileReadOnly", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.oFileChangedW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, testLbl, XmNlabelString, s1=XmStringCreateSimple("File read only"), XmNmnemonic, 'n', NULL); XtAddCallback(etDialog.oFileReadOnlyW, XmNvalueChangedCallback, fileReadOnlyCB, NULL); XmStringFree(s1); etDialog.oFileLockedW = XtVaCreateManagedWidget("fileLocked", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.oFileReadOnlyW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, testLbl, XmNlabelString, s1=XmStringCreateSimple("File locked"), XmNmnemonic, 'l', NULL); XtAddCallback(etDialog.oFileLockedW, XmNvalueChangedCallback, fileLockedCB, NULL); XmStringFree(s1); etDialog.oServerNameW = XtVaCreateManagedWidget("servernameSet", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oFileChangedW, XmNlabelString, s1=XmStringCreateSimple("Server name present"), XmNmnemonic, 'v', NULL); XtAddCallback(etDialog.oServerNameW, XmNvalueChangedCallback, serverNameCB, NULL); XmStringFree(s1); etDialog.oCcViewTagW = XtVaCreateManagedWidget("ccViewTagSet", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oServerNameW, XmNlabelString, s1=XmStringCreateSimple("CC view tag present"), #ifdef VMS XmNset, False, #else XmNset, GetClearCaseViewTag() != NULL, #endif /* VMS */ XmNmnemonic, 'w', NULL); #ifdef VMS XtSetSensitive(etDialog.oCcViewTagW, False); #else XtAddCallback(etDialog.oCcViewTagW, XmNvalueChangedCallback, ccViewTagCB, NULL); #endif /* VMS */ XmStringFree(s1); etDialog.oServerEqualViewW = XtVaCreateManagedWidget("serverEqualView", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.oCcViewTagW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oServerNameW, XmNlabelString, s1=XmStringCreateSimple("Server name equals CC view tag "), XmNmnemonic, 'q', NULL); #ifdef VMS XtSetSensitive(etDialog.oServerEqualViewW, False); #else XtAddCallback(etDialog.oServerEqualViewW, XmNvalueChangedCallback, serverEqualViewCB, NULL); #endif /* VMS */ XmStringFree(s1); etDialog.oDirW = XtVaCreateManagedWidget("pathSet", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oCcViewTagW, XmNlabelString, s1=XmStringCreateSimple("Directory present"), XmNmnemonic, 'i', NULL); XtAddCallback(etDialog.oDirW, XmNvalueChangedCallback, formatChangedCB, NULL); XmStringFree(s1); /* Button box */ buttonForm = XtVaCreateManagedWidget("buttonForm", xmFormWidgetClass, etDialog.form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, previewFrame, XmNtopOffset, V_MARGIN, XmNbottomOffset, V_MARGIN, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); applyBtn = XtVaCreateManagedWidget("apply", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Apply"), XmNshowAsDefault, (short)1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 6, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 25, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(applyBtn, XmNactivateCallback, applyCB, NULL); XmStringFree(s1); XtVaGetValues(applyBtn, XmNshadowThickness, &shadowThickness, NULL); defaultBtnOffset = shadowThickness + 4; closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Close"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 52, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 71, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, defaultBtnOffset, NULL); XtAddCallback(closeBtn, XmNactivateCallback, closeCB, NULL); XmStringFree(s1); restoreBtn = XtVaCreateManagedWidget("restore", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Default"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 29, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 48, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, defaultBtnOffset, XmNmnemonic, 'e', NULL); XtAddCallback(restoreBtn, XmNactivateCallback, restoreCB, NULL); XmStringFree(s1); helpBtn = XtVaCreateManagedWidget("help", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Help"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 75, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 94, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, defaultBtnOffset, XmNmnemonic, 'p', NULL); XtAddCallback(helpBtn, XmNactivateCallback, helpCB, NULL); XmStringFree(s1); /* Set initial default button */ XtVaSetValues(etDialog.form, XmNdefaultButton, applyBtn, NULL); XtVaSetValues(etDialog.form, XmNcancelButton, closeBtn, NULL); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(etDialog.form, FALSE); etDialog.suppressFormatUpdate = FALSE; } void EditCustomTitleFormat(WindowInfo *window) { /* copy attributes from current window so that we can use as many * 'real world' defaults as possible when testing the effect * of different formatting strings. */ strcpy(etDialog.path, window->path); strcpy(etDialog.filename, window->filename); #ifndef VMS strcpy(etDialog.viewTag, GetClearCaseViewTag() != NULL ? GetClearCaseViewTag() : "viewtag"); #endif /* VMS */ strcpy(etDialog.serverName, IsServer ? GetPrefServerName() : "servername"); etDialog.isServer = IsServer; etDialog.filenameSet = window->filenameSet; etDialog.lockReasons = window->lockReasons; etDialog.fileChanged = window->fileChanged; if (etDialog.window != window && etDialog.form) { /* Destroy the dialog owned by the other window. Note: don't rely on the destroy event handler to reset the form. Events are handled asynchronously, so the old dialog may continue to live for a while. */ XtDestroyWidget(etDialog.form); etDialog.form = NULL; } etDialog.window = window; /* Create the dialog if it doesn't already exist */ if (etDialog.form == NULL) { createEditTitleDialog(window->shell); } else { /* If the window is already up, just pop it to the top */ if (XtIsManaged(etDialog.form)) { RaiseDialogWindow(XtParent(etDialog.form)); /* force update of the dialog */ setToggleButtons(); formatChangedCB(0, 0, 0); return; } } /* set initial value of format field */ XmTextSetString(etDialog.formatW, (char *)GetPrefTitleFormat()); /* force update of the dialog */ setToggleButtons(); formatChangedCB(0, 0, 0); /* put up dialog and wait for user to press ok or cancel */ ManageDialogCenteredOnPointer(etDialog.form); }