Don't quit if getpwuid() fails. It can fail if some nameservices are not
[nedit.git] / util / managedList.c
blobf82a80215837ffbcbbf3271f5706fa0068296f40
1 static const char CVSID[] = "$Id: managedList.c,v 1.11 2003/03/18 10:58:20 edg Exp $";
2 /*******************************************************************************
3 * *
4 * managedList.c -- User interface for reorderable list of records *
5 * *
6 * Copyright (C) 1999 Mark Edel *
7 * *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
11 * version. *
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 *
16 * for 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 * November, 1995 *
24 * *
25 * Written by Mark Edel *
26 * *
27 *******************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
33 #include "managedList.h"
34 #include "misc.h"
36 #include <stdio.h>
37 #include <string.h>
39 #include <X11/Intrinsic.h>
40 #include <Xm/Form.h>
41 #include <Xm/List.h>
42 #include <Xm/PushB.h>
43 #include <Xm/RowColumn.h>
45 #ifdef HAVE_DEBUG_H
46 #include "../debug.h"
47 #endif
49 /* Common data between the managed list callback functions */
50 typedef struct {
51 Widget listW, deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
52 void *(*getDialogDataCB)(void *, int, int *, void *);
53 void *getDialogDataArg;
54 void (*setDialogDataCB)(void *, void *);
55 void *setDialogDataArg;
56 void *(*copyItemCB)(void *);
57 void (*freeItemCB)(void *);
58 int (*deleteConfirmCB)(int, void *);
59 void *deleteConfirmArg;
60 int maxItems;
61 int *nItems;
62 void **itemList;
63 int lastSelection;
64 } managedListData;
66 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData);
67 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData);
68 static void copyCB(Widget w, XtPointer clientData, XtPointer callData);
69 static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData);
70 static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData);
71 static int incorporateDialogData(managedListData *ml, int listPos,
72 int explicit);
73 static void updateDialogFromList(managedListData *ml, int selection);
74 static void updateListWidgetItem(managedListData *ml, int listPos);
75 static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData);
76 static int selectedListPosition(managedListData *ml);
77 static void selectItem(Widget listW, int itemIndex, int updateDialog);
80 ** Create a user interface to help manage a list of arbitrary data records
81 ** which users can edit, add, delete, and reorder.
83 ** The caller creates the overall dialog for presenting the data to the user,
84 ** but embeds the list and button widgets created here (and list management
85 ** code they activate) to handle the organization of the overall list.
87 ** This routine creates a form widget containing the buttons and list widget
88 ** with which the user interacts with the list data. ManageListAndButtons
89 ** can be used alternatively to take advantage of the management code with a
90 ** different arrangement of the widgets (this routine puts buttons in a
91 ** column on the left, list on the right) imposed here.
93 ** "args" and "argc" are passed to the form widget creation routine, so that
94 ** attachments can be specified for embedding the form in a dialog.
96 ** See ManageListAndButtons for a description of the remaining arguments.
98 Widget CreateManagedList(Widget parent, char *name, Arg *args,
99 int argC, void **itemList, int *nItems, int maxItems, int nColumns,
100 void *(*getDialogDataCB)(void *, int, int *, void *),
101 void *getDialogDataArg, void (*setDialogDataCB)(void *, void *),
102 void *setDialogDataArg, void (*freeItemCB)(void *))
104 int ac;
105 Arg al[20];
106 XmString s1;
107 Widget form, rowCol, listW;
108 Widget deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
109 XmString *placeholderTable;
110 char *placeholderStr;
112 form = XmCreateForm(parent, name, args, argC);
113 XtManageChild(form);
114 rowCol = XtVaCreateManagedWidget("mlRowCol", xmRowColumnWidgetClass, form,
115 XmNpacking, XmPACK_COLUMN,
116 XmNleftAttachment, XmATTACH_FORM,
117 XmNtopAttachment, XmATTACH_FORM,
118 XmNbottomAttachment, XmATTACH_FORM, NULL);
119 deleteBtn = XtVaCreateManagedWidget("delete", xmPushButtonWidgetClass,
120 rowCol, XmNlabelString, s1=XmStringCreateSimple("Delete"), NULL);
121 XmStringFree(s1);
122 copyBtn = XtVaCreateManagedWidget("copy", xmPushButtonWidgetClass, rowCol,
123 XmNlabelString, s1=XmStringCreateSimple("Copy"), NULL);
124 XmStringFree(s1);
125 moveUpBtn = XtVaCreateManagedWidget("moveUp", xmPushButtonWidgetClass,
126 rowCol, XmNlabelString, s1=XmStringCreateSimple("Move ^"), NULL);
127 XmStringFree(s1);
128 moveDownBtn = XtVaCreateManagedWidget("moveDown", xmPushButtonWidgetClass,
129 rowCol, XmNlabelString, s1=XmStringCreateSimple("Move v"), NULL);
130 XmStringFree(s1);
132 /* AFAIK the only way to make a list widget n-columns wide is to make up
133 a fake initial string of that width, and create it with that */
134 placeholderStr = XtMalloc(nColumns+1);
135 memset(placeholderStr, 'm', nColumns);
136 placeholderStr[nColumns] = '\0';
137 placeholderTable = StringTable(1, placeholderStr);
138 XtFree(placeholderStr);
140 ac = 0;
141 XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmAS_NEEDED); ac++;
142 XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++;
143 XtSetArg(al[ac], XmNitems, placeholderTable); ac++;
144 XtSetArg(al[ac], XmNitemCount, 1); ac++;
145 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
146 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
147 XtSetArg(al[ac], XmNleftWidget, rowCol); ac++;
148 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
149 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
150 listW = XmCreateScrolledList(form, "list", al, ac);
151 XtManageChild(listW);
152 FreeStringTable(placeholderTable);
154 return ManageListAndButtons(listW, deleteBtn, copyBtn, moveUpBtn,
155 moveDownBtn, itemList, nItems, maxItems, getDialogDataCB,
156 getDialogDataArg, setDialogDataCB, setDialogDataArg, freeItemCB);
160 ** Manage a list widget and a set of buttons which represent a list of
161 ** records. The caller provides facilities for editing the records
162 ** individually, and this code handles the organization of the overall list,
163 ** such that the user can modify, add, and delete records, and re-order the
164 ** list.
166 ** The format for the list of records managed by this code should be an
167 ** array of size "maxItems" of pointers to record structures. The records
168 ** themselves can be of any format, but the first field of the structure
169 ** must be a pointer to a character string which will be displayed as the
170 ** item name in the list. The list "itemList", and the number of items
171 ** "nItems" are automatically updated by the list management routines as the
172 ** user makes changes.
174 ** The caller must provide routines for transferring data to and from the
175 ** dialog fields dedicated to displaying and editing records in the list.
176 ** The callback "setDialogDataCB" must take the contents of the item pointer
177 ** passed to it, and display the data it contains, erasing any previously
178 ** displayed data. The format of the setDialogData callback is:
180 ** void setDialogDataCB(void *item, void *cbArg)
182 ** item: a pointer to the record to be displayed
184 ** cbArg: an arbitrary argument passed on to the callback routine
186 ** The callback "setDialogDataCB" must allocate (with XtMalloc) and return a
187 ** new record reflecting the current contents of the dialog fields. It may
188 ** do error checking on the data that the user has entered, and can abort
189 ** whatever operation triggered the request by setting "abort" to True.
190 ** This routine is called in a variety of contexts, such as the user
191 ** clicking on a list item, or requesting that a copy be made of the current
192 ** list item. To aide in communicating errors to the user, the boolean value
193 ** "explicitRequest" distinguishes between the case where the user has
194 ** specifically requested that the fields be read, and the case where he
195 ** may be surprised that errors are being reported, and require further
196 ** explanation. The format of the getDialogData callback is:
198 ** void *getDialogDataCB(void *oldItem, int explicitRequest, int *abort,
199 ** void *cbArg)
201 ** oldItem: a pointer to the existing record being modified in the
202 ** dialog, or NULL, if the user is modifying the "New" item.
204 ** explicitRequest: True if the user directly asked for the records
205 ** to be changed (as with an OK or Apply button). If a less direct
206 ** process resulted in the request, the user might need extra
207 ** explanation and possibly a chance to proceed using the existing
208 ** stored data (to use the data from oldItem, the routine should
209 ** make a new copy).
211 ** abort: Can be set to True if the dialog fields contain errors.
212 ** Setting abort to True, stops whetever process made the request
213 ** for updating the data in the list from the displayed data, and
214 ** forces the user to remain focused on the currently displayed
215 ** item until he either gives up or gets it right.
217 ** cbArg: arbitrary data, passed on from where the callback was
218 ** established in the list creation routines
220 ** The return value should be an allocated
222 ** The callback "freeItemCB" should free the item passed to it:
224 ** void freeItemCB(void *item, void *cbArg)
226 ** item: a pointer to the record to be freed
228 ** The difference between ManageListAndButtons and CreateManagedList, is that
229 ** in this routine, the caller creates the list and button widgets and passes
230 ** them here so that they be arranged explicitly, rather than relying on the
231 ** default style imposed by CreateManagedList. ManageListAndButtons simply
232 ** attaches the appropriate callbacks to process mouse and keyboard input from
233 ** the widgets.
235 Widget ManageListAndButtons(Widget listW, Widget deleteBtn, Widget copyBtn,
236 Widget moveUpBtn, Widget moveDownBtn, void **itemList, int *nItems,
237 int maxItems, void *(*getDialogDataCB)(void *, int, int *, void *),
238 void *getDialogDataArg, void (*setDialogDataCB)(void *, void *),
239 void *setDialogDataArg, void (*freeItemCB)(void *))
241 managedListData *ml;
243 /* Create a managedList data structure to hold information about the
244 widgets, callbacks, and current state of the list */
245 ml = (managedListData *)XtMalloc(sizeof(managedListData));
246 ml->listW = listW;
247 ml->deleteBtn = deleteBtn;
248 ml->copyBtn = copyBtn;
249 ml->moveUpBtn = moveUpBtn;
250 ml->moveDownBtn = moveDownBtn;
251 ml->getDialogDataCB = NULL;
252 ml->getDialogDataArg = setDialogDataArg;
253 ml->setDialogDataCB = NULL;
254 ml->setDialogDataArg = setDialogDataArg;
255 ml->freeItemCB = freeItemCB;
256 ml->deleteConfirmCB = NULL;
257 ml->deleteConfirmArg = NULL;
258 ml->nItems = nItems;
259 ml->maxItems = maxItems;
260 ml->itemList = itemList;
261 ml->lastSelection = 1;
263 /* Make the managed list data structure accessible from the list widget
264 pointer, and make sure it gets freed when the list is destroyed */
265 XtVaSetValues(ml->listW, XmNuserData, ml, NULL);
266 XtAddCallback(ml->listW, XmNdestroyCallback, destroyCB, ml);
268 /* Add callbacks for button and list actions */
269 XtAddCallback(ml->deleteBtn, XmNactivateCallback, deleteCB, ml);
270 XtAddCallback(ml->copyBtn, XmNactivateCallback, copyCB, ml);
271 XtAddCallback(ml->moveUpBtn, XmNactivateCallback, moveUpCB, ml);
272 XtAddCallback(ml->moveDownBtn, XmNactivateCallback, moveDownCB, ml);
273 XtAddCallback(ml->listW, XmNbrowseSelectionCallback, listSelectionCB, ml);
275 /* Initialize the list and buttons (don't set up the callbacks until
276 this is done, so they won't get called on creation) */
277 updateDialogFromList(ml, -1);
278 ml->getDialogDataCB = getDialogDataCB;
279 ml->setDialogDataCB = setDialogDataCB;
281 return ml->listW;
285 ** Update the currently selected list item from the dialog fields, using
286 ** the getDialogDataCB callback. "explicitRequest" is a boolean value
287 ** passed to on to the getDialogDataCB callback to help set the tone for
288 ** how error messages are presented (see ManageListAndButtons for more
289 ** information).
291 int UpdateManagedList(Widget listW, int explicitRequest)
293 managedListData *ml;
295 /* Recover the pointer to the managed list structure from the widget's
296 userData pointer */
297 XtVaGetValues(listW, XmNuserData, &ml, NULL);
299 /* Make the update */
300 return incorporateDialogData(ml, selectedListPosition(ml), explicitRequest);
304 ** Update the displayed list and data to agree with a data list which has
305 ** been changed externally (not by the ManagedList list manager).
307 void ChangeManagedListData(Widget listW)
309 managedListData *ml;
311 /* Recover the pointer to the managed list structure from the widget's
312 userData pointer */
313 XtVaGetValues(listW, XmNuserData, &ml, NULL);
315 updateDialogFromList(ml, -1);
319 ** Change the selected item in the managed list given the index into the
320 ** list being managed.
322 void SelectManagedListItem(Widget listW, int itemIndex)
324 selectItem(listW, itemIndex, True);
328 ** Return the index of the item currently selected in the list
330 int ManagedListSelectedIndex(Widget listW)
332 managedListData *ml;
334 XtVaGetValues(listW, XmNuserData, &ml, NULL);
335 return selectedListPosition(ml)-2;
339 ** Add a delete-confirmation callback to a managed list. This will be called
340 ** when the user presses the Delete button on the managed list. The callback
341 ** can put up a dialog, and optionally abort the operation by returning False.
343 void AddDeleteConfirmCB(Widget listW, int (*deleteConfirmCB)(int, void *),
344 void *deleteConfirmArg)
346 managedListData *ml;
348 XtVaGetValues(listW, XmNuserData, &ml, NULL);
349 ml->deleteConfirmCB = deleteConfirmCB;
350 ml->deleteConfirmArg = deleteConfirmArg;
354 ** Called on destruction of the list widget
356 static void destroyCB(Widget w, XtPointer clientData, XtPointer callData)
358 /* Free the managed list data structure */
359 XtFree((char *)clientData);
363 ** Button callbacks: deleteCB, copyCB, moveUpCB, moveDownCB
365 static void deleteCB(Widget w, XtPointer clientData, XtPointer callData)
367 managedListData *ml = (managedListData *)clientData;
368 int i, ind, listPos;
370 /* get the selected list position and the item to be deleted */
371 listPos = selectedListPosition(ml);
372 ind = listPos-2;
374 /* if there's a delete confirmation callback, call it first, and allow
375 it to request that the operation be aborted */
376 if (ml->deleteConfirmCB != NULL)
377 if (!(*ml->deleteConfirmCB)(ind, ml->deleteConfirmArg))
378 return;
380 /* free the item and remove it from the list */
381 (*ml->freeItemCB)(ml->itemList[ind]);
382 for (i=ind; i<*ml->nItems-1; i++)
383 ml->itemList[i] = ml->itemList[i+1];
384 (*ml->nItems)--;
386 /* update the list widget and move the selection to the previous item
387 in the list and display the fields appropriate for that entry */
388 updateDialogFromList(ml, ind-1);
391 static void copyCB(Widget w, XtPointer clientData, XtPointer callData)
393 managedListData *ml = (managedListData *)clientData;
394 int i, listPos, abort = False;
395 void *item;
397 /* get the selected list position and the item to be copied */
398 listPos = selectedListPosition(ml);
399 if (listPos == 1)
400 return; /* can't copy "new" */
402 /* Bring the entry up to date (could result in operation being canceled) */
403 item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], False, &abort,
404 ml->getDialogDataArg);
405 if (abort)
406 return;
407 if (item != NULL) {
408 (*ml->freeItemCB)(ml->itemList[listPos-2]);
409 ml->itemList[listPos-2] = item;
412 /* Make a copy by requesting the data again.
413 In case getDialogDataCB() returned a fallback value, the dialog may
414 not be in sync with the internal list. If we _explicitly_ request the
415 data again, we could get an invalid answer. Therefore, we first update
416 the dialog to make sure that we can copy the right data. */
417 updateDialogFromList(ml, listPos-2);
418 item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], True, &abort,
419 ml->getDialogDataArg);
420 if (abort)
421 return;
423 /* add the item to the item list */
424 for (i= *ml->nItems; i>=listPos; i--)
425 ml->itemList[i] = ml->itemList[i-1];
426 ml->itemList[listPos-1] = item;
427 (*ml->nItems)++;
429 /* redisplay the list widget and select the new item */
430 updateDialogFromList(ml, listPos-1);
433 static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData)
435 managedListData *ml = (managedListData *)clientData;
436 int ind, listPos;
437 void *temp;
439 /* get the item index currently selected in the menu item list */
440 listPos = selectedListPosition(ml);
441 ind = listPos-2;
443 /* Bring the item up to date with the dialog fields (It would be better
444 if this could be avoided, because user errors will be flagged here,
445 but it's not worth re-writing everything for such a trivial point) */
446 if (!incorporateDialogData(ml, ml->lastSelection, False))
447 return;
449 /* shuffle the item up in the menu item list */
450 temp = ml->itemList[ind];
451 ml->itemList[ind] = ml->itemList[ind-1];
452 ml->itemList[ind-1] = temp;
454 /* update the list widget and keep the selection on moved item */
455 updateDialogFromList(ml, ind-1);
458 static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData)
460 managedListData *ml = (managedListData *)clientData;
461 int ind, listPos;
462 void *temp;
464 /* get the item index currently selected in the menu item list */
465 listPos = selectedListPosition(ml);
466 ind = listPos-2;
468 /* Bring the item up to date with the dialog fields (I wish this could
469 be avoided) */
470 if (!incorporateDialogData(ml, ml->lastSelection, False))
471 return;
473 /* shuffle the item down in the menu item list */
474 temp = ml->itemList[ind];
475 ml->itemList[ind] = ml->itemList[ind+1];
476 ml->itemList[ind+1] = temp;
478 /* update the list widget and keep the selection on moved item */
479 updateDialogFromList(ml, ind+1);
483 ** Called when the user clicks on an item in the list widget
485 static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData)
487 managedListData *ml = (managedListData *)clientData;
488 int ind, listPos = ((XmListCallbackStruct *)callData)->item_position;
490 /* Save the current dialog fields before overwriting them. If there's an
491 error, force the user to go back to the old selection and fix it
492 before proceeding */
493 if (ml->getDialogDataCB != NULL && ml->lastSelection != 0) {
494 if (!incorporateDialogData(ml, ml->lastSelection, False)) {
495 XmListDeselectAllItems(ml->listW);
496 XmListSelectPos(ml->listW, ml->lastSelection, False);
497 return;
499 /* reselect item because incorporateDialogData can alter selection */
500 selectItem(ml->listW, listPos-2, False);
502 ml->lastSelection = listPos;
504 /* Dim or un-dim buttons at bottom of dialog based on whether the
505 selected item is a menu entry, or "New" */
506 if (listPos == 1) {
507 XtSetSensitive(ml->copyBtn, False);
508 XtSetSensitive(ml->deleteBtn, False);
509 XtSetSensitive(ml->moveUpBtn, False);
510 XtSetSensitive(ml->moveDownBtn, False);
511 } else {
512 XtSetSensitive(ml->copyBtn, True);
513 XtSetSensitive(ml->deleteBtn, True);
514 XtSetSensitive(ml->moveUpBtn, listPos != 2);
515 XtSetSensitive(ml->moveDownBtn, listPos != *ml->nItems+1);
518 /* get the index of the item currently selected in the item list */
519 ind = listPos - 2;
521 /* tell the caller to show the new item */
522 if (ml->setDialogDataCB != NULL)
523 (*ml->setDialogDataCB)(listPos==1 ? NULL : ml->itemList[ind],
524 ml->setDialogDataArg);
528 ** Incorporate the current contents of the dialog fields into the list
529 ** being managed, and if necessary change the display in the list widget.
530 ** The data is obtained by calling the getDialogDataCB callback, which
531 ** is allowed to reject whatever request triggered the update. If the
532 ** request is rejected, the return value from this function will be False.
534 static int incorporateDialogData(managedListData *ml, int listPos, int explicit)
536 int abort = False;
537 void *item;
539 /* Get the current contents of the dialog fields. Callback will set
540 abort to True if canceled */
541 item = (*ml->getDialogDataCB)(listPos == 1 ? NULL : ml->itemList[
542 listPos-2], explicit, &abort, ml->getDialogDataArg);
543 if (abort)
544 return False;
545 if (item == NULL) /* don't modify if fields are empty */
546 return True;
548 /* If the item is "new" add a new entry to the list, otherwise,
549 modify the entry with the text fields from the dialog */
550 if (listPos == 1) {
551 ml->itemList[(*ml->nItems)++] = item;
552 updateDialogFromList(ml, *ml->nItems - 1);
553 } else {
554 (*ml->freeItemCB)(ml->itemList[listPos-2]);
555 ml->itemList[listPos-2] = item;
556 updateListWidgetItem(ml, listPos);
558 return True;
562 ** Update the list widget to reflect the current contents of the managed item
563 ** list, set the item that should now be highlighted, and call getDisplayed
564 ** on the newly selected item to fill in the dialog fields.
566 static void updateDialogFromList(managedListData *ml, int selection)
568 int i;
569 XmString *stringTable;
571 /* On many systems under Motif 1.1 the list widget can't handle items
572 being changed while anything is selected! */
573 XmListDeselectAllItems(ml->listW);
575 /* Fill in the list widget with the names from the item list */
576 stringTable = (XmString *)XtMalloc(sizeof(XmString) * (*ml->nItems+1));
577 stringTable[0] = XmStringCreateSimple("New");
578 for (i=0; i < *ml->nItems; i++)
579 stringTable[i+1] = XmStringCreateSimple(*(char **)ml->itemList[i]);
580 XtVaSetValues(ml->listW, XmNitems, stringTable,
581 XmNitemCount, *ml->nItems+1, NULL);
582 for (i=0; i < *ml->nItems+1; i++)
583 XmStringFree(stringTable[i]);
584 XtFree((char *)stringTable);
586 /* Select the requested item (indirectly filling in the dialog fields),
587 but don't trigger an update of the last selected item from the current
588 dialog fields */
589 ml->lastSelection = 0;
590 selectItem(ml->listW, selection, True);
594 ** Update one item of the managed list widget to reflect the current contents
595 ** of the managed item list.
597 static void updateListWidgetItem(managedListData *ml, int listPos)
599 int savedPos;
600 XmString newString[1];
602 /* save the current selected position (Motif sometimes does stupid things
603 to the selection when a change is made, like selecting the new item
604 if it matches the name of currently selected one) */
605 savedPos = selectedListPosition(ml);
606 XmListDeselectAllItems(ml->listW);
608 /* update the list */
609 newString[0] = XmStringCreateSimple(*(char **)ml->itemList[listPos-2]);
610 XmListReplaceItemsPos(ml->listW, newString, 1, listPos);
611 XmStringFree(newString[0]);
613 /* restore the selected position */
614 XmListSelectPos(ml->listW, savedPos, False);
618 ** Get the position of the selection in the menu item list widget
620 static int selectedListPosition(managedListData *ml)
622 int listPos;
623 int *posList = NULL, posCount = 0;
625 if (!XmListGetSelectedPos(ml->listW, &posList, &posCount)) {
626 fprintf(stderr, "Internal error (nothing selected)");
627 return 1;
629 listPos = *posList;
630 XtFree((char *)posList);
631 if (listPos < 1 || listPos > *ml->nItems+1) {
632 fprintf(stderr, "Internal error (XmList bad value)");
633 return 1;
635 return listPos;
639 ** Select an item in the list given the list (array) index value.
640 ** If updateDialog is True, trigger a complete dialog update, which
641 ** could potentially reject the change.
643 static void selectItem(Widget listW, int itemIndex, int updateDialog)
645 int topPos, nVisible, selection = itemIndex+2;
647 /* Select the item */
648 XmListDeselectAllItems(listW);
649 XmListSelectPos(listW, selection, updateDialog);
651 /* If the selected item is not visible, scroll the list */
652 XtVaGetValues(listW, XmNtopItemPosition, &topPos, XmNvisibleItemCount,
653 &nVisible, NULL);
654 if (selection < topPos)
655 XmListSetPos(listW, selection);
656 else if (selection >= topPos + nVisible)
657 XmListSetPos(listW, selection - nVisible + 1);