#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "managedList.h"
#include "misc.h"
#include "DialogF.h"
#include "nedit_malloc.h"
#include <stdio.h>
#include <string.h>
#include <X11/Intrinsic.h>
#include <Xm/Form.h>
#include <Xm/List.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
typedef struct {
Widget listW, deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
void *(*getDialogDataCB)(
void *,
int,
int *,
void *);
void *getDialogDataArg;
void (*setDialogDataCB)(
void *,
void *);
void *setDialogDataArg;
void *(*copyItemCB)(
void *);
void (*freeItemCB)(
void *);
int (*deleteConfirmCB)(
int,
void *);
void *deleteConfirmArg;
int maxItems;
int *nItems;
void **itemList;
int lastSelection;
} managedListData;
static void destroyCB(Widget w, XtPointer clientData, XtPointer callData);
static void deleteCB(Widget w, XtPointer clientData, XtPointer callData);
static void copyCB(Widget w, XtPointer clientData, XtPointer callData);
static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData);
static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData);
static int incorporateDialogData(managedListData *ml,
int listPos,
int explicit);
static void updateDialogFromList(managedListData *ml,
int selection);
static void updateListWidgetItem(managedListData *ml,
int listPos);
static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData);
static int selectedListPosition(managedListData *ml);
static void selectItem(Widget listW,
int itemIndex,
int updateDialog);
static Widget shellOfWidget(Widget w);
Widget CreateManagedList(Widget parent,
char *name, Arg *args,
int argC,
void **itemList,
int *nItems,
int maxItems,
int nColumns,
void *(*getDialogDataCB)(
void *,
int,
int *,
void *),
void *getDialogDataArg,
void (*setDialogDataCB)(
void *,
void *),
void *setDialogDataArg,
void (*freeItemCB)(
void *))
{
int ac;
Arg al[
20];
XmString s1;
Widget form, rowCol, listW;
Widget deleteBtn, copyBtn, moveUpBtn, moveDownBtn;
XmString *placeholderTable;
char *placeholderStr;
form = XmCreateForm(parent, name, args, argC);
XtManageChild(form);
rowCol = XtVaCreateManagedWidget(
"mlRowCol", xmRowColumnWidgetClass, form,
XmNpacking, XmPACK_COLUMN,
XmNleftAttachment, XmATTACH_FORM,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
NULL);
deleteBtn = XtVaCreateManagedWidget(
"delete", xmPushButtonWidgetClass,
rowCol, XmNlabelString, s1=XmStringCreateSimple(
"Delete"),
NULL);
XmStringFree(s1);
copyBtn = XtVaCreateManagedWidget(
"copy", xmPushButtonWidgetClass, rowCol,
XmNlabelString, s1=XmStringCreateSimple(
"Copy"),
NULL);
XmStringFree(s1);
moveUpBtn = XtVaCreateManagedWidget(
"moveUp", xmPushButtonWidgetClass,
rowCol, XmNlabelString, s1=XmStringCreateSimple(
"Move ^"),
NULL);
XmStringFree(s1);
moveDownBtn = XtVaCreateManagedWidget(
"moveDown", xmPushButtonWidgetClass,
rowCol, XmNlabelString, s1=XmStringCreateSimple(
"Move v"),
NULL);
XmStringFree(s1);
placeholderStr = (
char*)NEditMalloc(nColumns+
1);
memset(placeholderStr,
'm', nColumns);
placeholderStr[nColumns] =
'\0';
placeholderTable = StringTable(
1, placeholderStr);
NEditFree(placeholderStr);
ac =
0;
XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmAS_NEEDED); ac++;
XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++;
XtSetArg(al[ac], XmNitems, placeholderTable); ac++;
XtSetArg(al[ac], XmNitemCount,
1); ac++;
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
XtSetArg(al[ac], XmNleftWidget, rowCol); ac++;
XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
listW = XmCreateScrolledList(form,
"list", al, ac);
AddMouseWheelSupport(listW);
XtManageChild(listW);
FreeStringTable(placeholderTable);
return ManageListAndButtons(listW, deleteBtn, copyBtn, moveUpBtn,
moveDownBtn, itemList, nItems, maxItems, getDialogDataCB,
getDialogDataArg, setDialogDataCB, setDialogDataArg, freeItemCB);
}
Widget ManageListAndButtons(Widget listW, Widget deleteBtn, Widget copyBtn,
Widget moveUpBtn, Widget moveDownBtn,
void **itemList,
int *nItems,
int maxItems,
void *(*getDialogDataCB)(
void *,
int,
int *,
void *),
void *getDialogDataArg,
void (*setDialogDataCB)(
void *,
void *),
void *setDialogDataArg,
void (*freeItemCB)(
void *))
{
managedListData *ml;
ml = (managedListData *)NEditMalloc(
sizeof(managedListData));
ml->listW = listW;
ml->deleteBtn = deleteBtn;
ml->copyBtn = copyBtn;
ml->moveUpBtn = moveUpBtn;
ml->moveDownBtn = moveDownBtn;
ml->getDialogDataCB =
NULL;
ml->getDialogDataArg = getDialogDataArg;
ml->setDialogDataCB =
NULL;
ml->setDialogDataArg = setDialogDataArg;
ml->freeItemCB = freeItemCB;
ml->deleteConfirmCB =
NULL;
ml->deleteConfirmArg =
NULL;
ml->nItems = nItems;
ml->maxItems = maxItems;
ml->itemList = itemList;
ml->lastSelection =
1;
XtVaSetValues(ml->listW, XmNuserData, ml,
NULL);
XtAddCallback(ml->listW, XmNdestroyCallback, destroyCB, ml);
XtAddCallback(ml->deleteBtn, XmNactivateCallback, deleteCB, ml);
XtAddCallback(ml->copyBtn, XmNactivateCallback, copyCB, ml);
XtAddCallback(ml->moveUpBtn, XmNactivateCallback, moveUpCB, ml);
XtAddCallback(ml->moveDownBtn, XmNactivateCallback, moveDownCB, ml);
XtAddCallback(ml->listW, XmNbrowseSelectionCallback, listSelectionCB, ml);
updateDialogFromList(ml, -
1);
ml->getDialogDataCB = getDialogDataCB;
ml->setDialogDataCB = setDialogDataCB;
return ml->listW;
}
int UpdateManagedList(Widget listW,
int explicitRequest)
{
managedListData *ml;
XtVaGetValues(listW, XmNuserData, &ml,
NULL);
return incorporateDialogData(ml, selectedListPosition(ml), explicitRequest);
}
void ChangeManagedListData(Widget listW)
{
managedListData *ml;
XtVaGetValues(listW, XmNuserData, &ml,
NULL);
updateDialogFromList(ml, -
1);
}
void SelectManagedListItem(Widget listW,
int itemIndex)
{
selectItem(listW, itemIndex, True);
}
int ManagedListSelectedIndex(Widget listW)
{
managedListData *ml;
XtVaGetValues(listW, XmNuserData, &ml,
NULL);
return selectedListPosition(ml)-
2;
}
void AddDeleteConfirmCB(Widget listW,
int (*deleteConfirmCB)(
int,
void *),
void *deleteConfirmArg)
{
managedListData *ml;
XtVaGetValues(listW, XmNuserData, &ml,
NULL);
ml->deleteConfirmCB = deleteConfirmCB;
ml->deleteConfirmArg = deleteConfirmArg;
}
static void destroyCB(Widget w, XtPointer clientData, XtPointer callData)
{
NEditFree(clientData);
}
static void deleteCB(Widget w, XtPointer clientData, XtPointer callData)
{
managedListData *ml = (managedListData *)clientData;
int i, ind, listPos;
listPos = selectedListPosition(ml);
ind = listPos-
2;
if (ml->deleteConfirmCB !=
NULL)
if (!(*ml->deleteConfirmCB)(ind, ml->deleteConfirmArg))
return;
(*ml->freeItemCB)(ml->itemList[ind]);
for (i=ind; i<*ml->nItems-
1; i++)
ml->itemList[i] = ml->itemList[i+
1];
(*ml->nItems)--;
updateDialogFromList(ml, ind-
1);
}
static void copyCB(Widget w, XtPointer clientData, XtPointer callData)
{
managedListData *ml = (managedListData *)clientData;
int i, listPos, abort = False;
void *item;
listPos = selectedListPosition(ml);
if (listPos ==
1)
return;
if ((*ml->nItems) == ml->maxItems) {
DialogF(
DF_ERR, shellOfWidget(ml->listW),
1,
"Limits exceeded",
"Cannot copy item.\nToo many items in list.",
"OK");
return;
}
item = (*ml->getDialogDataCB)(ml->itemList[listPos-
2], False, &abort,
ml->getDialogDataArg);
if (abort)
return;
if (item !=
NULL) {
(*ml->freeItemCB)(ml->itemList[listPos-
2]);
ml->itemList[listPos-
2] = item;
}
updateDialogFromList(ml, listPos-
2);
item = (*ml->getDialogDataCB)(ml->itemList[listPos-
2], True, &abort,
ml->getDialogDataArg);
if (abort)
return;
for (i= *ml->nItems; i>=listPos; i--)
ml->itemList[i] = ml->itemList[i-
1];
ml->itemList[listPos-
1] = item;
(*ml->nItems)++;
updateDialogFromList(ml, listPos-
1);
}
static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData)
{
managedListData *ml = (managedListData *)clientData;
int ind, listPos;
void *temp;
listPos = selectedListPosition(ml);
ind = listPos-
2;
if (!incorporateDialogData(ml, ml->lastSelection, False))
return;
temp = ml->itemList[ind];
ml->itemList[ind] = ml->itemList[ind-
1];
ml->itemList[ind-
1] = temp;
updateDialogFromList(ml, ind-
1);
}
static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData)
{
managedListData *ml = (managedListData *)clientData;
int ind, listPos;
void *temp;
listPos = selectedListPosition(ml);
ind = listPos-
2;
if (!incorporateDialogData(ml, ml->lastSelection, False))
return;
temp = ml->itemList[ind];
ml->itemList[ind] = ml->itemList[ind+
1];
ml->itemList[ind+
1] = temp;
updateDialogFromList(ml, ind+
1);
}
static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData)
{
managedListData *ml = (managedListData *)clientData;
int ind, listPos = ((XmListCallbackStruct *)callData)->item_position;
if (ml->getDialogDataCB !=
NULL && ml->lastSelection !=
0) {
if (!incorporateDialogData(ml, ml->lastSelection, False)) {
XmListDeselectAllItems(ml->listW);
XmListSelectPos(ml->listW, ml->lastSelection, False);
return;
}
selectItem(ml->listW, listPos-
2, False);
}
ml->lastSelection = listPos;
if (listPos ==
1) {
XtSetSensitive(ml->copyBtn, False);
XtSetSensitive(ml->deleteBtn, False);
XtSetSensitive(ml->moveUpBtn, False);
XtSetSensitive(ml->moveDownBtn, False);
}
else {
XtSetSensitive(ml->copyBtn, True);
XtSetSensitive(ml->deleteBtn, True);
XtSetSensitive(ml->moveUpBtn, listPos !=
2);
XtSetSensitive(ml->moveDownBtn, listPos != *ml->nItems+
1);
}
ind = listPos -
2;
if (ml->setDialogDataCB !=
NULL)
(*ml->setDialogDataCB)(listPos==
1 ?
NULL : ml->itemList[ind],
ml->setDialogDataArg);
}
static int incorporateDialogData(managedListData *ml,
int listPos,
int explicit)
{
int abort = False;
void *item;
item = (*ml->getDialogDataCB)(listPos ==
1 ?
NULL : ml->itemList[
listPos-
2], explicit, &abort, ml->getDialogDataArg);
if (abort)
return False;
if (item ==
NULL)
return True;
if (listPos ==
1) {
if ((*ml->nItems) == ml->maxItems) {
DialogF(
DF_ERR, shellOfWidget(ml->listW),
1,
"Limits exceeded",
"Cannot add new item.\nToo many items in list.",
"OK");
return False;
}
ml->itemList[(*ml->nItems)++] = item;
updateDialogFromList(ml, *ml->nItems -
1);
}
else {
(*ml->freeItemCB)(ml->itemList[listPos-
2]);
ml->itemList[listPos-
2] = item;
updateListWidgetItem(ml, listPos);
}
return True;
}
static void updateDialogFromList(managedListData *ml,
int selection)
{
int i;
XmString *stringTable;
XmListDeselectAllItems(ml->listW);
stringTable = (XmString *)NEditMalloc(
sizeof(XmString) * (*ml->nItems+
1));
stringTable[
0] = XmStringCreateSimple(
"New");
for (i=
0; i < *ml->nItems; i++)
stringTable[i+
1] = XmStringCreateSimple(*(
char **)ml->itemList[i]);
XtVaSetValues(ml->listW, XmNitems, stringTable,
XmNitemCount, *ml->nItems+
1,
NULL);
for (i=
0; i < *ml->nItems+
1; i++)
XmStringFree(stringTable[i]);
NEditFree(stringTable);
ml->lastSelection =
0;
selectItem(ml->listW, selection, True);
}
static void updateListWidgetItem(managedListData *ml,
int listPos)
{
int savedPos;
XmString newString[
1];
savedPos = selectedListPosition(ml);
XmListDeselectAllItems(ml->listW);
newString[
0] = XmStringCreateSimple(*(
char **)ml->itemList[listPos-
2]);
XmListReplaceItemsPos(ml->listW, newString,
1, listPos);
XmStringFree(newString[
0]);
XmListSelectPos(ml->listW, savedPos, False);
}
static int selectedListPosition(managedListData *ml)
{
int listPos;
int *posList =
NULL, posCount =
0;
if (!XmListGetSelectedPos(ml->listW, &posList, &posCount)) {
fprintf(stderr,
"Internal error (nothing selected)");
return 1;
}
listPos = *posList;
NEditFree(posList);
if (listPos <
1 || listPos > *ml->nItems+
1) {
fprintf(stderr,
"Internal error (XmList bad value)");
return 1;
}
return listPos;
}
static void selectItem(Widget listW,
int itemIndex,
int updateDialog)
{
int topPos, nVisible, selection = itemIndex+
2;
XmListDeselectAllItems(listW);
XmListSelectPos(listW, selection, updateDialog);
XtVaGetValues(listW, XmNtopItemPosition, &topPos, XmNvisibleItemCount,
&nVisible,
NULL);
if (selection < topPos)
XmListSetPos(listW, selection);
else if (selection >= topPos + nVisible)
XmListSetPos(listW, selection - nVisible +
1);
}
static Widget shellOfWidget(Widget w)
{
while(
1) {
if (!w)
return 0;
if (XtIsSubclass(w, shellWidgetClass))
return w;
w = XtParent(w);
}
}