1 
2 /*
3  * bltTreeViewColumn.c --
4  *
5  *	This module implements an hierarchy widget for the BLT toolkit.
6  *
7  * Copyright 1998-1999 Lucent Technologies, Inc.
8  *
9  * Permission to use, copy, modify, and distribute this software and
10  * its documentation for any purpose and without fee is hereby
11  * granted, provided that the above copyright notice appear in all
12  * copies and that both that the copyright notice and warranty
13  * disclaimer appear in supporting documentation, and that the names
14  * of Lucent Technologies or any of their entities not be used in
15  * advertising or publicity pertaining to distribution of the software
16  * without specific, written prior permission.
17  *
18  * Lucent Technologies disclaims all warranties with regard to this
19  * software, including all implied warranties of merchantability and
20  * fitness.  In no event shall Lucent Technologies be liable for any
21  * special, indirect or consequential damages or any damages
22  * whatsoever resulting from loss of use, data or profits, whether in
23  * an action of contract, negligence or other tortuous action, arising
24  * out of or in connection with the use or performance of this
25  * software.
26  *
27  *	The "treeview" widget was created by George A. Howlett.
28  *      Extensive cleanups and enhancements by Peter MacDonald.
29  */
30 
31 /*
32  * TODO:
33  *
34  * BUGS:
35  *   1.  "open" operation should change scroll offset so that as many
36  *	 new entries (up to half a screen) can be seen.
37  *   2.  "open" needs to adjust the scrolloffset so that the same entry
38  *	 is seen at the same place.
39  */
40 #include "bltInt.h"
41 
42 #ifndef NO_TREEVIEW
43 
44 #include "bltTreeView.h"
45 #include <X11/Xutil.h>
46 
47 #define RULE_AREA		(8)
48 
49 static Blt_OptionParseProc ObjToColumn;
50 static Blt_OptionPrintProc ColumnToObj;
51 static Blt_OptionParseProc ObjToData;
52 static Blt_OptionPrintProc DataToObj;
53 static Blt_OptionParseProc ObjToColorPat;
54 static Blt_OptionPrintProc ColorPatToObj;
55 
56 static char *sortTypeStrings[] = {
57     "dictionary", "ascii", "integer", "real", "command", "none", NULL
58 };
59 
60 enum SortTypeValues {
61     SORT_TYPE_DICTIONARY, SORT_TYPE_ASCII, SORT_TYPE_INTEGER,
62     SORT_TYPE_REAL, SORT_TYPE_COMMAND, SORT_TYPE_NONE
63 };
64 
65 #define DEF_SORT_COLUMN		(char *)NULL
66 #define DEF_SORT_COMMAND	(char *)NULL
67 #define DEF_SORT_DECREASING	"0"
68 #define DEF_SORT_SETFLAT	"0"
69 #define DEF_SORT_TYPE		"dictionary"
70 
71 #ifdef WIN32
72 #define DEF_COLUMN_ACTIVE_TITLE_BG	RGB_GREY85
73 #else
74 #define DEF_COLUMN_ACTIVE_TITLE_BG	RGB_GREY90
75 #endif
76 #define DEF_COLUMN_AUTOWIDTH			"0"
77 #define DEF_COLUMN_ACTIVE_TITLE_FG	STD_ACTIVE_FOREGROUND
78 #define DEF_COLUMN_BIND_TAGS		"all"
79 #define DEF_COLUMN_BORDERWIDTH		STD_BORDERWIDTH
80 #define DEF_COLUMN_COLOR		RGB_BLACK
81 #define DEF_COLUMN_EDIT			"no"
82 #define DEF_COLUMN_FONT			STD_FONT
83 #define DEF_COLUMN_HIDE			"no"
84 #define DEF_COLUMN_JUSTIFY		"left"
85 #define DEF_COLUMN_MAX			"0"
86 #define DEF_COLUMN_MIN			"0"
87 #define DEF_COLUMN_PAD			"2"
88 #define DEF_COLUMN_RELIEF		"flat"
89 #define DEF_COLUMN_STATE		"normal"
90 #define DEF_COLUMN_STYLE		"text"
91 #define DEF_COLUMN_TITLE_BACKGROUND	STD_NORMAL_BACKGROUND
92 #define DEF_COLUMN_TITLE_BORDERWIDTH	STD_BORDERWIDTH
93 #define DEF_COLUMN_TITLE_FOREGROUND	STD_NORMAL_FOREGROUND
94 #define DEF_COLUMN_TITLE_RELIEF		"raised"
95 #define DEF_COLUMN_UNDERLINE		"-1"
96 #define DEF_COLUMN_WEIGHT		"1.0"
97 #define DEF_COLUMN_WIDTH		"0"
98 #define DEF_COLUMN_RULE_DASHES		"dot"
99 #define DEF_COLUMN_SCROLL_TILE          "no"
100 #define DEF_COLUMN_TITLEJUSTIFY		"center"
101 
102 extern Blt_OptionParseProc Blt_ObjToEnum;
103 extern Blt_OptionPrintProc Blt_EnumToObj;
104 
105 static Blt_CustomOption patColorOption =
106 {
107     ObjToColorPat, ColorPatToObj, NULL, (ClientData)0
108 };
109 
110 static Blt_CustomOption regColorOption =
111 {
112     ObjToColorPat, ColorPatToObj, NULL, (ClientData)1
113 };
114 
115 static Blt_CustomOption typeOption =
116 {
117     Blt_ObjToEnum, Blt_EnumToObj, NULL, (ClientData)sortTypeStrings
118 };
119 
120 Blt_CustomOption bltTreeViewColumnOption =
121 {
122     ObjToColumn, ColumnToObj, NULL, (ClientData)0
123 };
124 
125 Blt_CustomOption bltTreeViewDataOption =
126 {
127     ObjToData, DataToObj, NULL, (ClientData)0,
128 };
129 
130 static Blt_OptionParseProc ObjToStyle;
131 static Blt_OptionPrintProc StyleToObj;
132 static Blt_OptionFreeProc FreeStyle;
133 Blt_CustomOption bltTreeViewStyleOption =
134 {
135     /* Contains a pointer to the widget that's currently being
136      * configured.  This is used in the custom configuration parse
137      * routine for icons.  */
138     ObjToStyle, StyleToObj, FreeStyle, NULL,
139 };
140 
141 static Blt_OptionParseProc ObjToStyles;
142 static Blt_OptionPrintProc StylesToObj;
143 static Blt_OptionFreeProc FreeStyles;
144 Blt_CustomOption bltTreeViewStylesOption =
145 {
146     /* Contains a pointer to the widget that's currently being
147     * configured.  This is used in the custom configuration parse
148     * routine for icons.  */
149     ObjToStyles, StylesToObj, FreeStyles, NULL,
150 };
151 
152 static Blt_TreeApplyProc SortApplyProc;
153 
154 static Blt_ConfigSpec columnSpecs[] =
155 {
156     {BLT_CONFIG_BORDER, "-activetitlebackground", "activeTitleBackground",
157 	"Background", DEF_COLUMN_ACTIVE_TITLE_BG,
158 	Blt_Offset(TreeViewColumn, activeTitleBorder), 0},
159     {BLT_CONFIG_COLOR, "-activetitleforeground", "activeTitleForeground",
160 	"Foreground", DEF_COLUMN_ACTIVE_TITLE_FG,
161 	Blt_Offset(TreeViewColumn, activeTitleFgColor), 0},
162     {BLT_CONFIG_DISTANCE, "-autowidth",(char *)NULL, (char *)NULL,
163 	DEF_COLUMN_AUTOWIDTH, Blt_Offset(TreeViewColumn, autoWidth),
164         0},
165     {BLT_CONFIG_BORDER, "-background", (char *)NULL, (char *)NULL,
166 	(char *)NULL, Blt_Offset(TreeViewColumn, border),
167         BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT},
168     {BLT_CONFIG_SYNONYM, "-bd", (char *)NULL, (char *)NULL, (char *)NULL,
169 	0, 0, (ClientData)"-borderwidth"},
170     {BLT_CONFIG_SYNONYM, "-bg", (char *)NULL, (char *)NULL, (char *)NULL,
171 	0, 0, (ClientData)"-background"},
172     {BLT_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
173 	DEF_COLUMN_BIND_TAGS, Blt_Offset(TreeViewColumn, tagsUid),
174 	BLT_CONFIG_NULL_OK, &bltTreeViewUidOption},
175     {BLT_CONFIG_DISTANCE, "-borderwidth", (char *)NULL, (char *)NULL,
176 	DEF_COLUMN_BORDERWIDTH, Blt_Offset(TreeViewColumn, borderWidth),
177 	0},
178     {BLT_CONFIG_CUSTOM, "-colorpattern", "colorPattern", "ColorPattern",
179 	NULL, Blt_Offset(TreeViewColumn, colorPats),
180         BLT_CONFIG_NULL_OK, &patColorOption},
181     {BLT_CONFIG_CUSTOM, "-colorregex", "colorRegex", "ColorRegex",
182 	NULL, Blt_Offset(TreeViewColumn, colorRegex),
183         BLT_CONFIG_NULL_OK, &regColorOption},
184     {BLT_CONFIG_STRING, "-command",  (char *)NULL, (char *)NULL,
185 	(char *)NULL, Blt_Offset(TreeViewColumn, titleCmd),
186 	BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK},
187     {BLT_CONFIG_ARROW, "-titlearrow", "titleArrow", "TitleArrow",
188 	"none", Blt_Offset(TreeViewColumn, drawArrow),
189         0},
190     {BLT_CONFIG_BOOLEAN, "-edit", "edit", "Edit",
191 	DEF_COLUMN_EDIT, Blt_Offset(TreeViewColumn, editable),
192         0},
193     {BLT_CONFIG_STRING, "-editopts", "editOpts", "EditOpts",
194 	(char *)NULL, Blt_Offset(TreeViewColumn, editOpts),
195 	BLT_CONFIG_NULL_OK},
196     {BLT_CONFIG_SYNONYM, "-fg", (char *)NULL, (char *)NULL, (char *)NULL, 0, 0,
197         (ClientData)"-foreground"},
198     {BLT_CONFIG_OBJCMD, "-fillcmd", "fillCmd", "FillCmd",
199 	(char *)NULL, Blt_Offset(TreeViewColumn, fillCmd),
200 	BLT_CONFIG_NULL_OK},
201     {BLT_CONFIG_FONT, "-font", (char *)NULL, (char *)NULL,
202 	(char *)NULL, Blt_Offset(TreeViewColumn, font),
203 	BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT},
204     {BLT_CONFIG_COLOR, "-foreground", (char *)NULL, (char *)NULL,
205 	(char *)NULL, Blt_Offset(TreeViewColumn, fgColor),
206         BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT},
207     {BLT_CONFIG_OBJCMD, "-formatcmd", "formatCmd", "FormatCmd",
208 	NULL, Blt_Offset(TreeViewColumn, formatCmd),
209         BLT_CONFIG_NULL_OK},
210     {BLT_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
211 	DEF_COLUMN_HIDE, Blt_Offset(TreeViewColumn, hidden),
212 	BLT_CONFIG_DONT_SET_DEFAULT},
213     {BLT_CONFIG_CUSTOM, "-icon", "icon", "icon",
214 	(char *)NULL, Blt_Offset(TreeViewColumn, titleIcon),
215          BLT_CONFIG_DONT_SET_DEFAULT|BLT_CONFIG_NULL_OK,
216          &bltTreeViewIconOption},
217     {BLT_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
218 	DEF_COLUMN_JUSTIFY, Blt_Offset(TreeViewColumn, justify),
219         0},
220     {BLT_CONFIG_DISTANCE, "-max", "max", "Max",
221 	DEF_COLUMN_MAX, Blt_Offset(TreeViewColumn, reqMax),
222 	0},
223     {BLT_CONFIG_DISTANCE, "-min", "min", "Min",
224 	DEF_COLUMN_MIN, Blt_Offset(TreeViewColumn, reqMin),
225 	0},
226     {BLT_CONFIG_PAD, "-pad", "pad", "Pad",
227 	DEF_COLUMN_PAD, Blt_Offset(TreeViewColumn, pad),
228 	0},
229     {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief",
230 	DEF_COLUMN_RELIEF, Blt_Offset(TreeViewColumn, relief),
231         0},
232     {BLT_CONFIG_DASHES, "-ruledashes", "ruleDashes", "RuleDashes",
233 	DEF_COLUMN_RULE_DASHES, Blt_Offset(TreeViewColumn, ruleDashes),
234 	BLT_CONFIG_NULL_OK},
235     {BLT_CONFIG_BOOLEAN, "-scrolltile", "scrollTile", "ScrollTile",
236 	DEF_COLUMN_SCROLL_TILE, Tk_Offset(TreeViewColumn, scrollTile),
237 	0},
238     {BLT_CONFIG_STRING, "-sortcommand", "sortCommand", "SortCommand",
239 	DEF_SORT_COMMAND, Blt_Offset(TreeViewColumn, sortCmd),
240 	BLT_CONFIG_NULL_OK},
241     {BLT_CONFIG_LISTOBJ, "-sortaltcolumns", "sortAltColumns", "SortAltColumns",
242 	DEF_SORT_COMMAND, Blt_Offset(TreeViewColumn, sortAltColumns),
243 	BLT_CONFIG_NULL_OK},
244     {BLT_CONFIG_CUSTOM, "-sortmode", "sortMode", "SortMode",
245 	DEF_SORT_TYPE, Blt_Offset(TreeViewColumn, sortType), 0, &typeOption},
246     {BLT_CONFIG_STATE, "-state", "state", "State",
247 	DEF_COLUMN_STATE, Blt_Offset(TreeViewColumn, state),
248 	BLT_CONFIG_DONT_SET_DEFAULT},
249     {BLT_CONFIG_CUSTOM, "-style", "style", "Style",
250 	DEF_COLUMN_STYLE, Blt_Offset(TreeViewColumn, stylePtr),
251         0, &bltTreeViewStyleOption},
252     {BLT_CONFIG_TILE, "-tile", "columnTile", "ColumnTile",
253 	(char *)NULL, Tk_Offset(TreeViewColumn, tile), BLT_CONFIG_NULL_OK, },
254     {BLT_CONFIG_STRING, "-title", "title", "Title",
255 	(char *)NULL, Blt_Offset(TreeViewColumn, title), 0},
256     {BLT_CONFIG_BORDER, "-titlebackground", "titleBackground",
257 	"TitleBackground", DEF_COLUMN_TITLE_BACKGROUND,
258 	Blt_Offset(TreeViewColumn, titleBorder),0},
259     {BLT_CONFIG_DISTANCE, "-titleborderwidth", "BorderWidth",
260 	"TitleBorderWidth", DEF_COLUMN_TITLE_BORDERWIDTH,
261 	Blt_Offset(TreeViewColumn, titleBorderWidth),
262 	0},
263     {BLT_CONFIG_FONT, "-titlefont", (char *)NULL, (char *)NULL,
264 	(char *)NULL, Blt_Offset(TreeViewColumn, titleFont),
265 	BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT},
266     {BLT_CONFIG_COLOR, "-titleforeground", "titleForeground", "TitleForeground",
267 	DEF_COLUMN_TITLE_FOREGROUND,
268 	Blt_Offset(TreeViewColumn, titleFgColor), 0},
269     {BLT_CONFIG_JUSTIFY, "-titlejustify", "titleJustify", "TitleJustify",
270 	DEF_COLUMN_TITLEJUSTIFY, Blt_Offset(TreeViewColumn, titleJustify),
271         0},
272     {BLT_CONFIG_RELIEF, "-titlerelief", "titleRelief", "TitleRelief",
273 	DEF_COLUMN_TITLE_RELIEF, Blt_Offset(TreeViewColumn, titleRelief),
274         0},
275     {BLT_CONFIG_SHADOW, "-titleshadow", "titleShadow", "TitleShadow",
276 	(char *)NULL, Blt_Offset(TreeViewColumn, titleShadow), 0},
277     {BLT_CONFIG_CUSTOM, "-titlestyle", "titleStyle", "TitleStyle",
278 	DEF_COLUMN_STYLE, Blt_Offset(TreeViewColumn, titleStylePtr),
279         0, &bltTreeViewStyleOption},
280     {BLT_CONFIG_STRING, "-validatecmd", (char *)NULL, (char *)NULL,
281         (char *)NULL, Blt_Offset(TreeViewColumn, validCmd),
282 	BLT_CONFIG_NULL_OK, 0},
283     {BLT_CONFIG_INT, "-underline", (char *)NULL, (char *)NULL,
284 	DEF_COLUMN_UNDERLINE, Blt_Offset(TreeViewColumn, underline),
285 	0},
286     {BLT_CONFIG_DOUBLE, "-weight", (char *)NULL, (char *)NULL,
287 	DEF_COLUMN_WEIGHT, Blt_Offset(TreeViewColumn, weight),
288 	0},
289     {BLT_CONFIG_DISTANCE, "-width",(char *)NULL, (char *)NULL,
290 	DEF_COLUMN_WIDTH, Blt_Offset(TreeViewColumn, reqWidth),
291         0},
292     {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
293 	(char *)NULL, 0, 0}
294 };
295 
296 static Blt_ConfigSpec sortSpecs[] =
297 {
298     {BLT_CONFIG_STRING, "-command", "command", "Command",
299 	DEF_SORT_COMMAND, Blt_Offset(TreeView, sortCmd),
300 	BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK},
301     {BLT_CONFIG_CUSTOM, "-column", "column", "Column",
302 	DEF_SORT_COLUMN, Blt_Offset(TreeView, sortColumnPtr),
303 	BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewColumnOption},
304     {BLT_CONFIG_BOOLEAN, "-decreasing", "decreasing", "Decreasing",
305 	DEF_SORT_DECREASING, Blt_Offset(TreeView, sortDecreasing),
306         BLT_CONFIG_DONT_SET_DEFAULT},
307     {BLT_CONFIG_BOOLEAN, "-setflat", "setFlat", "SetFlat",
308 	DEF_SORT_SETFLAT, Blt_Offset(TreeView, setFlatView),
309 	BLT_CONFIG_DONT_SET_DEFAULT},
310     {BLT_CONFIG_CUSTOM, "-mode", "mode", "Mode",
311 	DEF_SORT_TYPE, Blt_Offset(TreeView, sortType), 0, &typeOption},
312     {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
313 	(char *)NULL, 0, 0}
314 };
315 
316 static Blt_TreeCompareNodesProc CompareNodes;
317 static Blt_TreeApplyProc SortApplyProc;
318 
319 /*
320  *----------------------------------------------------------------------
321  *
322  * ObjToColumn --
323  *
324  *	Convert the string reprsenting a scroll mode, to its numeric
325  *	form.
326  *
327  * Results:
328  *	If the string is successfully converted, TCL_OK is returned.
329  *	Otherwise, TCL_ERROR is returned and an error message is left
330  *	in interpreter's result field.
331  *
332  *----------------------------------------------------------------------
333  */
334 /*ARGSUSED*/
335 static int
ObjToColumn(clientData,interp,tkwin,objPtr,widgRec,offset)336 ObjToColumn(clientData, interp, tkwin, objPtr, widgRec, offset)
337     ClientData clientData;	/* Not used. */
338     Tcl_Interp *interp;		/* Interpreter to send results back to */
339     Tk_Window tkwin;		/* Not used. */
340     Tcl_Obj *objPtr;		/* New legend position string */
341     char *widgRec;
342     int offset;
343 {
344     TreeViewColumn **columnPtrPtr = (TreeViewColumn **)(widgRec + offset);
345     char *string;
346 
347     string = Tcl_GetString(objPtr);
348     if (*string == '\0') {
349 	*columnPtrPtr = NULL;
350     } else {
351 	TreeView *tvPtr = (TreeView *)widgRec;
352 
353 	if (Blt_TreeViewGetColumn(interp, tvPtr, objPtr, columnPtrPtr)
354 	    != TCL_OK) {
355 	    return TCL_ERROR;
356 	}
357     }
358     return TCL_OK;
359 }
360 
361 /*
362  *----------------------------------------------------------------------
363  *
364  * ColumnToString --
365  *
366  * Results:
367  *	The string representation of the button boolean is returned.
368  *
369  *----------------------------------------------------------------------
370  */
371 /*ARGSUSED*/
372 static Tcl_Obj *
ColumnToObj(clientData,interp,tkwin,widgRec,offset)373 ColumnToObj(clientData, interp, tkwin, widgRec, offset)
374     ClientData clientData;	/* Not used. */
375     Tcl_Interp *interp;
376     Tk_Window tkwin;		/* Not used. */
377     char *widgRec;
378     int offset;
379 {
380     TreeViewColumn *columnPtr = *(TreeViewColumn **)(widgRec + offset);
381 
382     return Tcl_NewStringObj(columnPtr?columnPtr->key:"", -1);
383 }
384 
385 /*
386  *----------------------------------------------------------------------
387  *
388  * ObjToData --
389  *
390  *	Convert the string reprsenting a data, to its tree
391  *	form.
392  *
393  * Results:
394  *	If the string is successfully converted, TCL_OK is returned.
395  *	Otherwise, TCL_ERROR is returned and an error message is left
396  *	in interpreter's result field.
397  *
398  *----------------------------------------------------------------------
399  */
400 /*ARGSUSED*/
401 static int
ObjToData(clientData,interp,tkwin,objPtr,widgRec,offset)402 ObjToData(clientData, interp, tkwin, objPtr, widgRec, offset)
403     ClientData clientData;	/* Unused. */
404     Tcl_Interp *interp;		/* Interpreter to send results back to */
405     Tk_Window tkwin;		/* Not used. */
406     Tcl_Obj *objPtr;		/* Tcl_Obj representing new data. */
407     char *widgRec;
408     int offset;
409 {
410     Tcl_Obj **objv;
411     TreeViewColumn *columnPtr;
412     TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec;
413     char *string;
414     int objc;
415     register int i;
416     Blt_TreeNode node;
417     TreeView *tvPtr;
418 
419     string = Tcl_GetString(objPtr);
420     if (*string == '\0') {
421 	return TCL_OK;
422     }
423     if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
424 	return TCL_ERROR;
425     }
426     if (objc == 0) {
427 	return TCL_OK;
428     }
429     if (objc & 0x1) {
430 	Tcl_AppendResult(interp, "data \"", string,
431 		 "\" must be in even name-value pairs", (char *)NULL);
432 	return TCL_ERROR;
433     }
434     node = entryPtr->node;
435     tvPtr = entryPtr->tvPtr;
436     for (i = 0; i < objc; i += 2) {
437         int result;
438 
439 	if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
440 	    != TCL_OK) {
441 	    return TCL_ERROR;
442 	}
443         result = Blt_TreeSetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node,
444              columnPtr->key, objv[i + 1]);
445         if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
446             return TCL_ERROR;
447         }
448 	if (result != TCL_OK) {
449 	    return TCL_ERROR;
450 	}
451 	Blt_TreeViewAddValue(entryPtr, columnPtr);
452     }
453     return TCL_OK;
454 }
455 
456 static int
ObjToColorPat(clientData,interp,tkwin,objPtr,widgRec,offset)457 ObjToColorPat(clientData, interp, tkwin, objPtr, widgRec, offset)
458     ClientData clientData;	/* Unused. */
459     Tcl_Interp *interp;		/* Interpreter to send results back to */
460     Tk_Window tkwin;		/* Not used. */
461     Tcl_Obj *objPtr;		/* Tcl_Obj representing new data. */
462     char *widgRec;
463     int offset;
464 {
465     Tcl_Obj **objv;
466     Tcl_Obj **objPtrPtr = (Tcl_Obj **)(widgRec + offset);
467     int objc, i;
468     XColor *color = NULL;
469 
470     if (objPtr != NULL && strlen(Tcl_GetString(objPtr))) {
471 
472         if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
473             return TCL_ERROR;
474         }
475         if (objc%2) {
476             Tcl_AppendResult(interp, "odd length: ", Tcl_GetString(objPtr),0);
477             return TCL_ERROR;
478         }
479         for (i = 0; i < objc; i += 2) {
480             if (clientData != 0 &&
481                 Tcl_RegExpMatchObj(interp, objv[i], objv[i]) < 0) {
482                 return TCL_ERROR;
483             }
484             color = Tk_AllocColorFromObj(interp, tkwin, objv[i+1]);
485             if (color == NULL) {
486                 Tcl_AppendResult(interp, "bad color: ", Tcl_GetString(objv[i+1]),0);
487                 return TCL_ERROR;
488             }
489         }
490     }
491     if (*objPtrPtr != NULL) {
492         Tcl_DecrRefCount(*objPtrPtr);
493     }
494     Tcl_IncrRefCount(objPtr);
495     *objPtrPtr = objPtr;
496     return TCL_OK;
497 }
498 
499 static Tcl_Obj *
ColorPatToObj(clientData,interp,tkwin,widgRec,offset)500 ColorPatToObj(clientData, interp, tkwin, widgRec, offset)
501     ClientData clientData;	/* Not used. */
502     Tcl_Interp *interp;
503     Tk_Window tkwin;		/* Not used. */
504     char *widgRec;
505     int offset;
506 {
507     TreeViewColumn *columnPtr = (TreeViewColumn *)widgRec;
508     Tcl_Obj *objPtr;
509     if (clientData == 0) {
510         objPtr = columnPtr->colorPats;
511     } else {
512         objPtr = columnPtr->colorRegex;
513     }
514     if (objPtr == NULL) {
515         objPtr = Tcl_NewStringObj("", -1);
516     }
517     Tcl_IncrRefCount(objPtr);
518     return objPtr;
519 }
520 
521 /*
522  *----------------------------------------------------------------------
523  *
524  * DataToObj --
525  *
526  * Results:
527  *	The string representation of the data is returned.
528  *
529  *----------------------------------------------------------------------
530  */
531 /*ARGSUSED*/
532 static Tcl_Obj *
DataToObj(clientData,interp,tkwin,widgRec,offset)533 DataToObj(clientData, interp, tkwin, widgRec, offset)
534     ClientData clientData;	/* Not used. */
535     Tcl_Interp *interp;
536     Tk_Window tkwin;		/* Not used. */
537     char *widgRec;
538     int offset;
539 {
540     Tcl_Obj *listObjPtr, *objPtr;
541     TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec;
542     TreeViewValue *valuePtr;
543 
544     /* Add the key-value pairs to a new Tcl_Obj */
545     listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
546     for (valuePtr = entryPtr->values; valuePtr != NULL;
547 	valuePtr = valuePtr->nextPtr) {
548 	objPtr = Tcl_NewStringObj(valuePtr->columnPtr->key, -1);
549 	Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
550 	if (Blt_TreeViewGetData(entryPtr, valuePtr->columnPtr->key, &objPtr)
551 	    != TCL_OK) {
552 	        objPtr = Tcl_NewStringObj("", -1);
553 	}
554 	Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
555     }
556     return listObjPtr;
557 }
558 
559 int
Blt_TreeViewGetColumn(interp,tvPtr,objPtr,columnPtrPtr)560 Blt_TreeViewGetColumn(interp, tvPtr, objPtr, columnPtrPtr)
561     Tcl_Interp *interp;
562     TreeView *tvPtr;
563     Tcl_Obj *objPtr;
564     TreeViewColumn **columnPtrPtr;
565 {
566     char *string;
567     Blt_TreeKey key;
568 
569     string = Tcl_GetString(objPtr);
570     if (strcmp(string, "BLT TreeView") == 0) {
571         *columnPtrPtr = &tvPtr->treeColumn;
572     } else {
573         int cNum, n = 0;
574         Blt_HashEntry *hPtr;
575 
576         key = Blt_TreeKeyGet(interp, tvPtr->tree?tvPtr->tree->treeObject:NULL, string);
577         hPtr = Blt_FindHashEntry(&tvPtr->columnTable, key);
578         if (hPtr == NULL) {
579             if (Tcl_GetIntFromObj(NULL, objPtr, &cNum) == TCL_OK &&
580             cNum >= 0) {
581                 Blt_ChainLink *linkPtr;
582                 TreeViewColumn *columnPtr;
583 
584                 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
585                 linkPtr = Blt_ChainNextLink(linkPtr)) {
586                     columnPtr = Blt_ChainGetValue(linkPtr);
587                     if (cNum == n) {
588                         *columnPtrPtr = columnPtr;
589                         return TCL_OK;
590                     }
591                     n++;
592                 }
593             }
594             if (interp != NULL) {
595                 Tcl_AppendResult(interp, "can't find column \"", string,
596                     "\" in \"", Tk_PathName(tvPtr->tkwin), "\"",
597                     (char *)NULL);
598             }
599             return TCL_ERROR;
600         }
601         *columnPtrPtr = Blt_GetHashValue(hPtr);
602     }
603     return TCL_OK;
604 }
605 
606 static int
ParseParentheses(Tcl_Interp * interp,CONST char * string,char ** leftPtr,char ** rightPtr)607 ParseParentheses(
608     Tcl_Interp *interp,
609     CONST char *string,
610     char **leftPtr,
611     char **rightPtr)
612 {
613     register char *p;
614     char *left, *right;
615 
616     left = right = NULL;
617     for (p = (char *)string; *p != '\0'; p++) {
618 	if (*p == '(') {
619 	    left = p;
620 	} else if (*p == ')') {
621 	    right = p;
622 	}
623     }
624     if (left != right) {
625 	if (((left != NULL) && (right == NULL)) ||
626 	    ((left == NULL) && (right != NULL)) ||
627 	    (left > right) || (right != (p - 1))) {
628 	    if (interp != NULL) {
629 		Tcl_AppendResult(interp, "bad array specification \"", string,
630 			     "\"", (char *)NULL);
631 	    }
632 	    return TCL_ERROR;
633 	}
634     }
635     *leftPtr = left;
636     *rightPtr = right;
637     return TCL_OK;
638 }
639 
640 
641 
642 int
Blt_TreeViewGetColumnKey(interp,tvPtr,objPtr,columnPtrPtr,keyPtrPtr)643 Blt_TreeViewGetColumnKey(interp, tvPtr, objPtr, columnPtrPtr, keyPtrPtr)
644     Tcl_Interp *interp;
645     TreeView *tvPtr;
646     Tcl_Obj *objPtr;
647     TreeViewColumn **columnPtrPtr;
648     char **keyPtrPtr;
649 {
650     char *right = NULL;
651     char *string;
652     int cNum, n = 0;
653     Blt_HashEntry *hPtr;
654     Blt_TreeKey key;
655     Blt_TreeObject tree;
656 
657     string = Tcl_GetString(objPtr);
658 
659     if (strcmp(string, "BLT TreeView") == 0) {
660         *columnPtrPtr = &tvPtr->treeColumn;
661         return TCL_OK;
662     }
663 
664     if (ParseParentheses(interp, string, keyPtrPtr, &right) != TCL_OK) {
665         return TCL_ERROR;
666     }
667 
668     tree = tvPtr->tree?tvPtr->tree->treeObject:NULL;
669     if (right == NULL) {
670         key = Blt_TreeKeyGet(interp, tree, string);
671     } else {
672         Tcl_DString dStr;
673         Tcl_DStringInit(&dStr);
674         Tcl_DStringAppend(&dStr, string, (*keyPtrPtr)-string);
675         key = Blt_TreeKeyGet(interp, tree,  Tcl_DStringValue(&dStr) );
676         Tcl_DStringFree(&dStr);
677     }
678     hPtr = Blt_FindHashEntry(&tvPtr->columnTable, key);
679     if (hPtr == NULL) {
680         if (Tcl_GetIntFromObj(NULL, objPtr, &cNum) == TCL_OK &&
681         cNum >= 0) {
682             Blt_ChainLink *linkPtr;
683             TreeViewColumn *columnPtr;
684 
685             for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
686             linkPtr = Blt_ChainNextLink(linkPtr)) {
687                 columnPtr = Blt_ChainGetValue(linkPtr);
688                 if (cNum == n) {
689                     *columnPtrPtr = columnPtr;
690                     return TCL_OK;
691                 }
692                 n++;
693             }
694         }
695         if (interp != NULL) {
696             Tcl_AppendResult(interp, "can't find column \"", string,
697                 "\" in \"", Tk_PathName(tvPtr->tkwin), "\"",
698                 (char *)NULL);
699         }
700         return TCL_ERROR;
701     }
702     *columnPtrPtr = Blt_GetHashValue(hPtr);
703     return TCL_OK;
704 }
705 
706 int
Blt_TreeViewNumColumns(tvPtr)707 Blt_TreeViewNumColumns(tvPtr)
708 TreeView *tvPtr;
709 {
710     int n = 0;
711     Blt_ChainLink *linkPtr;
712     TreeViewColumn *columnPtr;
713 
714     for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
715     linkPtr = Blt_ChainNextLink(linkPtr)) {
716         columnPtr = Blt_ChainGetValue(linkPtr);
717         n++;
718     }
719     return n;
720 }
721 
722 /*
723 * Refresh the tree-local definition for column keys.
724 */
725 void
Blt_TreeViewColumnRekey(tvPtr)726 Blt_TreeViewColumnRekey(tvPtr)
727 TreeView *tvPtr;
728 {
729     Blt_ChainLink *linkPtr;
730     TreeViewColumn *columnPtr;
731 
732     for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
733     linkPtr = Blt_ChainNextLink(linkPtr)) {
734         columnPtr = Blt_ChainGetValue(linkPtr);
735         columnPtr->key = Blt_TreeKeyGet(tvPtr->interp, tvPtr->tree?tvPtr->tree->treeObject:NULL, columnPtr->name);
736     }
737 }
738 
739 int
Blt_TreeViewColumnNum(tvPtr,string)740 Blt_TreeViewColumnNum(tvPtr, string)
741 TreeView *tvPtr;
742 char *string;
743 {
744     int n = 0, m = -1, isTree;
745     Blt_ChainLink *linkPtr;
746     TreeViewColumn *columnPtr;
747 
748 
749     isTree = (!strcmp(string, "BLT TreeView"));
750     for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
751         linkPtr = Blt_ChainNextLink(linkPtr)) {
752         columnPtr = Blt_ChainGetValue(linkPtr);
753         if (!strcmp(string, columnPtr->key)) {
754             return n;
755         } else if (isTree && columnPtr == &tvPtr->treeColumn) {
756             m = n;
757         }
758         n++;
759     }
760     return m;
761 }
762 
763 int
Blt_TreeViewColumnInd(tvPtr,columnPtr)764 Blt_TreeViewColumnInd(tvPtr, columnPtr)
765     TreeView *tvPtr;
766     TreeViewColumn *columnPtr;
767 {
768     int n = 0;
769     Blt_ChainLink *linkPtr;
770     TreeViewColumn *curPtr;
771 
772     for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
773         linkPtr = Blt_ChainNextLink(linkPtr)) {
774         curPtr = Blt_ChainGetValue(linkPtr);
775         if (curPtr == columnPtr) {
776             return n;
777         }
778         n++;
779     }
780     return -1;
781 }
782 
783 
784 /*
785  *----------------------------------------------------------------------
786  *
787  * ObjToStyle --
788  *
789  *	Convert the name of an icon into a treeview style.
790  *
791  * Results:
792  *	If the string is successfully converted, TCL_OK is returned.
793  *	Otherwise, TCL_ERROR is returned and an error message is left in
794  *	interpreter's result field.
795  *
796  *----------------------------------------------------------------------
797  */
798 /*ARGSUSED*/
799 static int
ObjToStyle(clientData,interp,tkwin,objPtr,widgRec,offset)800 ObjToStyle(clientData, interp, tkwin, objPtr, widgRec, offset)
801     ClientData clientData;	/* Not used. */
802     Tcl_Interp *interp;		/* Interpreter to send results back to */
803     Tk_Window tkwin;		/* Not used. */
804     Tcl_Obj *objPtr;		/* Tcl_Obj representing the new value. */
805     char *widgRec;
806     int offset;
807 {
808     TreeView *tvPtr = clientData;
809     TreeViewStyle **stylePtrPtr = (TreeViewStyle **)(widgRec + offset);
810     TreeViewStyle *stylePtr;
811 
812     if (Blt_TreeViewGetStyleMake(interp, tvPtr, Tcl_GetString(objPtr),
813 	     &stylePtr, NULL, NULL, NULL) != TCL_OK) {
814         *stylePtrPtr = tvPtr->stylePtr;
815 	return TCL_ERROR;
816     }
817     stylePtr->flags |= STYLE_DIRTY;
818     tvPtr->flags |= (TV_LAYOUT | TV_DIRTY);
819     *stylePtrPtr = stylePtr;
820     return TCL_OK;
821 }
822 
823 /*
824  *----------------------------------------------------------------------
825  *
826  * IconToObj --
827  *
828  *	Converts the icon into its string representation (its name).
829  *
830  * Results:
831  *	The name of the icon is returned.
832  *
833  *----------------------------------------------------------------------
834  */
835 /*ARGSUSED*/
836 static Tcl_Obj *
StyleToObj(clientData,interp,tkwin,widgRec,offset)837 StyleToObj(clientData, interp, tkwin, widgRec, offset)
838     ClientData clientData;	/* Not used. */
839     Tcl_Interp *interp;
840     Tk_Window tkwin;		/* Not used. */
841     char *widgRec;
842     int offset;
843 {
844     TreeViewStyle *stylePtr = *(TreeViewStyle **)(widgRec + offset);
845 
846     return Tcl_NewStringObj(stylePtr?stylePtr->name:"", -1);
847 }
848 
849 /*ARGSUSED*/
850 static int
FreeStyle(clientData,display,widgRec,offset,oldPtr)851 FreeStyle(clientData, display, widgRec, offset, oldPtr)
852     ClientData clientData;
853     Display *display;		/* Not used. */
854     char *widgRec;
855     int offset;
856     char *oldPtr;
857 {
858     TreeView *tvPtr = clientData;
859     TreeViewStyle *stylePtr = (TreeViewStyle *)(oldPtr);
860 
861     Blt_TreeViewFreeStyle(tvPtr, stylePtr);
862     return TCL_OK;
863 }
864 
865 static int
ObjToStyles(clientData,interp,tkwin,objPtr,widgRec,offset)866 ObjToStyles(clientData, interp, tkwin, objPtr, widgRec, offset)
867     ClientData clientData;	/* Not used. */
868     Tcl_Interp *interp;		/* Interpreter to send results back to */
869     Tk_Window tkwin;		/* Not used. */
870     Tcl_Obj *objPtr;		/* Tcl_Obj representing the new value. */
871     char *widgRec;
872     int offset;
873 {
874     TreeView *tvPtr = clientData;
875     TreeViewStyle ***stylesPtrPtr = (TreeViewStyle ***)(widgRec + offset);
876     TreeViewStyle **sPtr = NULL;
877     Tcl_Obj **objv;
878     int objc, i;
879 
880     if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
881         return TCL_ERROR;
882     }
883     if (objc != 0) {
884         sPtr = Blt_Calloc(objc+1, sizeof(*sPtr));
885         for (i=0; i<objc; i++) {
886             if (Blt_TreeViewGetStyleMake(interp, tvPtr, Tcl_GetString(objv[i]),
887                 &sPtr[i], NULL, NULL, NULL) != TCL_OK) {
888                     Blt_Free(sPtr);
889                     return TCL_ERROR;
890             }
891             sPtr[i]->flags |= STYLE_DIRTY;
892         }
893     }
894     tvPtr->flags |= (TV_LAYOUT | TV_DIRTY);
895     *stylesPtrPtr = sPtr;
896     return TCL_OK;
897 }
898 
899 /*ARGSUSED*/
900 static Tcl_Obj *
StylesToObj(clientData,interp,tkwin,widgRec,offset)901 StylesToObj(clientData, interp, tkwin, widgRec, offset)
902     ClientData clientData;	/* Not used. */
903     Tcl_Interp *interp;
904     Tk_Window tkwin;		/* Not used. */
905     char *widgRec;
906     int offset;
907 {
908     TreeViewStyle **sPtr = *(TreeViewStyle ***)(widgRec + offset);
909     Tcl_Obj *obj;
910     int i;
911 
912     if (sPtr == NULL) {
913         return Tcl_NewStringObj("", -1);
914     }
915     obj = Tcl_NewListObj(0,0);
916     i = 0;
917     while (sPtr[i]) {
918         Tcl_ListObjAppendElement(interp, obj, Tcl_NewStringObj(sPtr[i]->name, -1));
919         i++;
920     }
921     return obj;
922 }
923 
924 /*ARGSUSED*/
925 static int
FreeStyles(clientData,display,widgRec,offset,oldPtr)926 FreeStyles(clientData, display, widgRec, offset, oldPtr)
927     ClientData clientData;
928     Display *display;		/* Not used. */
929     char *widgRec;
930     int offset;
931     char *oldPtr;
932 {
933     TreeView *tvPtr = clientData;
934     TreeViewStyle **sPtr = (TreeViewStyle **)(oldPtr);
935     int i;
936 
937     if (sPtr == NULL) { return TCL_OK; }
938     i = 0;
939     while (sPtr[i] != NULL) {
940         Blt_TreeViewFreeStyle(tvPtr, sPtr[i]);
941         i++;
942     }
943     Blt_Free(sPtr);
944     return TCL_OK;
945 }
946 
947 void
Blt_TreeViewUpdateColumnGCs(tvPtr,columnPtr)948 Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr)
949     TreeView *tvPtr;
950     TreeViewColumn *columnPtr;
951 {
952     Drawable drawable;
953     GC newGC;
954     Tk_3DBorder border;
955     XGCValues gcValues;
956     int ruleDrawn;
957     unsigned long gcMask;
958     int iconWidth, iconHeight;
959     int textWidth, textHeight;
960     gcMask = GCForeground | GCFont;
961 
962     gcValues.font = Tk_FontId((columnPtr->font?columnPtr->font: tvPtr->font));
963 
964     /* Normal text */
965     gcValues.foreground = CHOOSE(tvPtr->fgColor,columnPtr->fgColor)->pixel;
966     newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
967     if (columnPtr->textGC != NULL) {
968         Tk_FreeGC(tvPtr->display, columnPtr->textGC);
969     }
970     columnPtr->textGC = newGC;
971 
972     gcValues.font = Tk_FontId((columnPtr->titleFont?columnPtr->titleFont:
973         tvPtr->titleFont));
974 
975     /* Normal title text */
976     gcValues.foreground = columnPtr->titleFgColor->pixel;
977     newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
978     if (columnPtr->titleGC != NULL) {
979 	Tk_FreeGC(tvPtr->display, columnPtr->titleGC);
980     }
981     columnPtr->titleGC = newGC;
982 
983     /* Active title text */
984     gcValues.foreground = columnPtr->activeTitleFgColor->pixel;
985     newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
986     if (columnPtr->activeTitleGC != NULL) {
987 	Tk_FreeGC(tvPtr->display, columnPtr->activeTitleGC);
988     }
989     columnPtr->activeTitleGC = newGC;
990 
991     columnPtr->titleWidth = 0;
992     iconWidth = iconHeight = 0;
993     if (columnPtr->titleIcon != NULL) {
994 	iconWidth = TreeViewIconWidth(columnPtr->titleIcon);
995 	iconHeight = TreeViewIconHeight(columnPtr->titleIcon);
996 	columnPtr->titleWidth += iconWidth;
997     }
998     if (columnPtr->titleTextPtr != NULL) {
999 	Blt_Free(columnPtr->titleTextPtr);
1000 	columnPtr->titleTextPtr = NULL;
1001     }
1002     textWidth = textHeight = 0;
1003     if (columnPtr->title != NULL) {
1004 	TextStyle ts;
1005 
1006         memset(&ts, 0, sizeof(TextStyle));
1007 	ts.font = (columnPtr->titleFont?columnPtr->titleFont:tvPtr->titleFont);
1008 	ts.justify = TK_JUSTIFY_LEFT;
1009 	ts.underline = columnPtr->underline;
1010 	ts.shadow.offset = columnPtr->titleShadow.offset;
1011 	columnPtr->titleTextPtr = Blt_GetTextLayout(columnPtr->title, &ts);
1012 	textHeight = columnPtr->titleTextPtr->height + tvPtr->titlePad*2;
1013         if (columnPtr->underline>=0) {
1014             textHeight += 2;
1015         }
1016 	textWidth = columnPtr->titleTextPtr->width;
1017 	columnPtr->titleWidth += textWidth;
1018     }
1019     if ((iconWidth > 0) && (textWidth > 0)) {
1020 	columnPtr->titleWidth += 8;
1021     }
1022     columnPtr->titleWidth += STD_ARROW_HEIGHT;
1023     columnPtr->titleHeight = MAX(iconHeight, textHeight);
1024 
1025     gcMask = (GCFunction | GCLineWidth | GCLineStyle | GCForeground);
1026 
1027     /*
1028      * If the rule is active, turn it off (i.e. draw again to erase
1029      * it) before changing the GC.  If the color changes, we won't be
1030      * able to erase the old line, since it will no longer be
1031      * correctly XOR-ed with the background.
1032      */
1033     drawable = Tk_WindowId(tvPtr->tkwin);
1034     ruleDrawn = ((tvPtr->flags & TV_RULE_ACTIVE) &&
1035 		 (tvPtr->activeTitleColumnPtr == columnPtr) &&
1036 		 (drawable != None));
1037     if (ruleDrawn) {
1038 	Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
1039     }
1040     /* XOR-ed rule column divider */
1041     gcValues.line_width = LineWidth(columnPtr->ruleLineWidth);
1042     gcValues.foreground =
1043 	Blt_TreeViewGetStyleFg(tvPtr, columnPtr, columnPtr->stylePtr)->pixel;
1044     if (LineIsDashed(columnPtr->ruleDashes)) {
1045 	gcValues.line_style = LineOnOffDash;
1046     } else {
1047 	gcValues.line_style = LineSolid;
1048     }
1049     gcValues.function = GXxor;
1050 
1051     border = CHOOSE(tvPtr->border, columnPtr->border);
1052     gcValues.foreground ^= Tk_3DBorderColor(border)->pixel;
1053     newGC = Blt_GetPrivateGC(tvPtr->tkwin, gcMask, &gcValues);
1054     if (columnPtr->ruleGC != NULL) {
1055 	Blt_FreePrivateGC(tvPtr->display, columnPtr->ruleGC);
1056     }
1057     if (LineIsDashed(columnPtr->ruleDashes)) {
1058 	Blt_SetDashes(tvPtr->display, newGC, &columnPtr->ruleDashes);
1059     }
1060     columnPtr->ruleGC = newGC;
1061     if (ruleDrawn) {
1062 	Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
1063     }
1064     columnPtr->flags |= COLUMN_DIRTY;
1065     tvPtr->flags |= TV_UPDATE;
1066 }
1067 
1068 static void
DestroyColumnNow(DestroyData data)1069 DestroyColumnNow(DestroyData data)
1070 {
1071     TreeViewColumn *columnPtr = (TreeViewColumn *)data;
1072     TreeView *tvPtr;
1073 
1074     tvPtr = columnPtr->tvPtr;
1075     if (columnPtr->title != NULL) {
1076         Blt_Free(columnPtr->title);
1077         columnPtr->title = NULL;
1078     }
1079     if (columnPtr->titleTextPtr != NULL) {
1080         Blt_Free(columnPtr->titleTextPtr);
1081         columnPtr->titleTextPtr = NULL;
1082     }
1083     if (columnPtr->stylePtr != NULL) {
1084 	Blt_TreeViewFreeStyle(tvPtr, columnPtr->stylePtr);
1085 	columnPtr->stylePtr = NULL;
1086     }
1087     if (columnPtr->titleStylePtr != NULL) {
1088         Blt_TreeViewFreeStyle(tvPtr, columnPtr->titleStylePtr);
1089         columnPtr->titleStylePtr = NULL;
1090     }
1091     if (columnPtr->tile != NULL) {
1092         Blt_FreeTile(columnPtr->tile);
1093         columnPtr->tile = NULL;
1094     }
1095     if (columnPtr->defValue != NULL) {
1096         Blt_PoolFreeItem(tvPtr->valuePool, columnPtr->defValue);
1097         columnPtr->defValue = NULL;
1098     }
1099     if (columnPtr->trace != NULL) {
1100         Blt_TreeDeleteTrace(columnPtr->trace);
1101         columnPtr->trace = NULL;
1102     }
1103     Blt_Free(columnPtr->name);
1104     if (columnPtr != &tvPtr->treeColumn) {
1105         Blt_Free(columnPtr);
1106     }
1107 }
1108 
1109 static void
DestroyColumn(tvPtr,columnPtr)1110 DestroyColumn(tvPtr, columnPtr)
1111     TreeView *tvPtr;
1112     TreeViewColumn *columnPtr;
1113 {
1114     ClientData object;
1115     Blt_HashEntry *hPtr;
1116 
1117     columnPtr->flags |= COLUMN_DELETED;
1118 
1119     if (tvPtr->selAnchorCol == columnPtr) { tvPtr->selAnchorCol = NULL; }
1120     if (tvPtr->activeColumnPtr == columnPtr) { tvPtr->activeColumnPtr = NULL; }
1121     if (tvPtr->activeTitleColumnPtr == columnPtr) { tvPtr->activeTitleColumnPtr = NULL; }
1122     if (tvPtr->resizeColumnPtr == columnPtr) { tvPtr->resizeColumnPtr = NULL; }
1123     if (tvPtr->sortColumnPtr == columnPtr) { tvPtr->sortColumnPtr = NULL; }
1124     Blt_TreeViewWindowRelease(NULL, columnPtr);
1125     Blt_TreeViewOptsInit(tvPtr);
1126     object = Blt_TreeViewColumnTag(tvPtr, columnPtr->key);
1127     if (object) {
1128         Blt_DeleteBindings(tvPtr->bindTable, object);
1129     }
1130     Blt_DeleteBindings(tvPtr->bindTable, columnPtr);
1131     hPtr = Blt_FindHashEntry(&tvPtr->columnTagTable, columnPtr->key);
1132     if (hPtr != NULL) {
1133         Blt_DeleteHashEntry(&tvPtr->columnTagTable, hPtr);
1134     }
1135     Blt_FreeObjOptions(tvPtr->interp, columnSpecs, (char *)columnPtr, tvPtr->display, 0);
1136     if (columnPtr->titleGC != NULL) {
1137         Tk_FreeGC(tvPtr->display, columnPtr->titleGC);
1138         columnPtr->titleGC = NULL;
1139     }
1140     if (columnPtr->textGC != NULL) {
1141         Tk_FreeGC(tvPtr->display, columnPtr->textGC);
1142         columnPtr->textGC = NULL;
1143     }
1144     if (columnPtr->ruleGC != NULL) {
1145         Blt_FreePrivateGC(tvPtr->display, columnPtr->ruleGC);
1146         columnPtr->ruleGC = NULL;
1147     }
1148     if (columnPtr->activeTitleGC != NULL) {
1149         Tk_FreeGC(tvPtr->display, columnPtr->activeTitleGC);
1150         columnPtr->activeTitleGC = NULL;
1151     }
1152     hPtr = Blt_FindHashEntry(&tvPtr->columnTable, columnPtr->key);
1153     if (hPtr != NULL) {
1154         Blt_DeleteHashEntry(&tvPtr->columnTable, hPtr);
1155     }
1156     if (columnPtr->linkPtr != NULL) {
1157         Blt_ChainDeleteLink(tvPtr->colChainPtr, columnPtr->linkPtr);
1158         columnPtr->linkPtr = NULL;
1159     }
1160     Tcl_EventuallyFree(columnPtr, DestroyColumnNow);
1161 }
1162 
1163 void
Blt_TreeViewDestroyColumns(tvPtr)1164 Blt_TreeViewDestroyColumns(tvPtr)
1165     TreeView *tvPtr;
1166 {
1167     if (tvPtr->colChainPtr != NULL) {
1168 	Blt_ChainLink *linkPtr;
1169 	TreeViewColumn *columnPtr;
1170 
1171 	for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
1172 	     linkPtr = Blt_ChainNextLink(linkPtr)) {
1173 	    columnPtr = Blt_ChainGetValue(linkPtr);
1174 	    columnPtr->linkPtr = NULL;
1175 	    DestroyColumn(tvPtr, columnPtr);
1176 	}
1177 	Blt_ChainDestroy(tvPtr->colChainPtr);
1178 	tvPtr->colChainPtr = NULL;
1179     }
1180     Blt_DeleteHashTable(&tvPtr->columnTable);
1181 }
1182 
1183 void
Blt_TreeViewConfigureColumns(tvPtr)1184 Blt_TreeViewConfigureColumns(tvPtr)
1185 TreeView *tvPtr;
1186 {
1187     if (tvPtr->colChainPtr != NULL) {
1188         Blt_ChainLink *linkPtr;
1189         TreeViewColumn *columnPtr;
1190 
1191         for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
1192         linkPtr = Blt_ChainNextLink(linkPtr)) {
1193             columnPtr = Blt_ChainGetValue(linkPtr);
1194             Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr);
1195         }
1196     }
1197 }
1198 
1199 static void
ColumnConfigChanges(tvPtr,interp,columnPtr)1200 ColumnConfigChanges(tvPtr, interp, columnPtr)
1201     TreeView *tvPtr;
1202     Tcl_Interp *interp;
1203     TreeViewColumn *columnPtr;
1204 {
1205     if (Blt_ObjConfigModified(columnSpecs, interp, "-background", (char *)NULL)) {
1206         columnPtr->hasbg = 1;
1207     }
1208     if (Blt_ObjConfigModified(columnSpecs, tvPtr->interp, "-titlebackground", (char *)NULL)) {
1209         columnPtr->hasttlbg = 1;
1210     }
1211     if (columnPtr->tile != NULL) {
1212         Blt_SetTileChangedProc(columnPtr->tile, Blt_TreeViewTileChangedProc, tvPtr);
1213     }
1214     if (columnPtr->stylePtr == NULL) {
1215     }
1216     if (Blt_ObjConfigModified(columnSpecs, tvPtr->interp, "-justify", "-hide", "-weight", "-formatcmd", "-font", (char *)NULL)) {
1217         Blt_TreeViewMakeStyleDirty(tvPtr);
1218     }
1219 }
1220 
1221 int
Blt_TreeViewCreateColumn(tvPtr,columnPtr,name,defTitle)1222 Blt_TreeViewCreateColumn(tvPtr, columnPtr, name, defTitle)
1223     TreeView *tvPtr;
1224     TreeViewColumn *columnPtr;
1225     char *name, *defTitle;
1226 {
1227     Blt_HashEntry *hPtr;
1228     int isNew;
1229     Tcl_Interp *interp;
1230     Blt_TreeObject treeObj;
1231     char *left = NULL, *right = NULL;
1232 
1233     interp = tvPtr->interp;
1234     if (ParseParentheses(interp, name, &left, &right) != TCL_OK ||
1235         left != NULL || right != NULL) {
1236         Blt_Free(columnPtr);
1237         Tcl_AppendResult(interp, "column key may not use parens", 0);
1238         return TCL_ERROR;
1239     }
1240     treeObj = tvPtr->tree?tvPtr->tree->treeObject:NULL;
1241     columnPtr->tvPtr = tvPtr;
1242     columnPtr->name = Blt_Strdup(name);
1243     columnPtr->key = Blt_TreeKeyGet(interp, treeObj, name);
1244     columnPtr->title = Blt_Strdup(defTitle);
1245     columnPtr->justify = TK_JUSTIFY_CENTER;
1246     columnPtr->titleJustify = TK_JUSTIFY_CENTER;
1247     columnPtr->relief = TK_RELIEF_FLAT;
1248     columnPtr->borderWidth = 1;
1249     columnPtr->pad.side1 = columnPtr->pad.side2 = 2;
1250     columnPtr->state = STATE_NORMAL;
1251     columnPtr->weight = 1.0;
1252     columnPtr->editable = FALSE;
1253     columnPtr->ruleLineWidth = 1;
1254     columnPtr->titleBorderWidth = 2;
1255     columnPtr->titleRelief = TK_RELIEF_RAISED;
1256     columnPtr->titleIcon = NULL;
1257     columnPtr->tile = NULL;
1258     columnPtr->scrollTile = 0;
1259     columnPtr->hasbg = 0;
1260     columnPtr->hasttlbg = 0;
1261     columnPtr->defValue = Blt_TreeViewMakeValue(tvPtr, columnPtr, NULL);
1262     hPtr = Blt_CreateHashEntry(&tvPtr->columnTable, columnPtr->key, &isNew);
1263     Blt_SetHashValue(hPtr, columnPtr);
1264 
1265     Blt_TreeViewOptsInit(tvPtr);
1266     if (Blt_ConfigureComponentFromObj(tvPtr->interp, tvPtr->tkwin, name,
1267 	"Column", columnSpecs, 0, (Tcl_Obj **)NULL, (char *)columnPtr, 0)
1268 	!= TCL_OK) {
1269 	DestroyColumn(tvPtr, columnPtr);
1270 	return TCL_ERROR;
1271     }
1272     if (Blt_ObjConfigModified(columnSpecs, tvPtr->interp, "-background", (char *)NULL)) {
1273         columnPtr->hasbg = 1;
1274     }
1275     if (Blt_ObjConfigModified(columnSpecs, tvPtr->interp, "-titlebackground", (char *)NULL)) {
1276         columnPtr->hasttlbg = 1;
1277     }
1278     if (columnPtr->tile != NULL) {
1279         Blt_SetTileChangedProc(columnPtr->tile, Blt_TreeViewTileChangedProc, tvPtr);
1280     }
1281     if (Blt_ObjConfigModified(columnSpecs, tvPtr->interp, "-*font", "-foreground", "-titleborderwidth", "-titlerelief", "-titleshadow", (char *)NULL)) {
1282         Blt_TreeViewMakeStyleDirty(tvPtr);
1283     }
1284     ColumnConfigChanges(tvPtr, interp, columnPtr);
1285     Blt_ObjConfigModified(columnSpecs, tvPtr->interp, (char *)NULL);
1286     return TCL_OK;
1287 
1288 }
1289 
1290 static TreeViewColumn *
CreateColumn(tvPtr,nameObjPtr,objc,objv)1291 CreateColumn(tvPtr, nameObjPtr, objc, objv)
1292     TreeView *tvPtr;
1293     Tcl_Obj *nameObjPtr;
1294     int objc;
1295     Tcl_Obj *CONST *objv;
1296 {
1297     TreeViewColumn *columnPtr;
1298     Tcl_DString dString;
1299     char *string, *nStr;
1300     int colIdx, len;
1301 
1302     colIdx = 1;
1303     nStr = string = Tcl_GetStringFromObj(nameObjPtr, &len);
1304 
1305     columnPtr = Blt_Calloc(1, sizeof(TreeViewColumn));
1306     assert(columnPtr);
1307     Tcl_DStringInit(&dString);
1308     while (string[0] == 0 || (len>=5 && strncmp(string+len-5,"#auto", 5)==0)) {
1309         Tcl_DStringSetLength(&dString, 0);
1310         if (len <= 5) {
1311             Tcl_DStringAppend(&dString, "Col", -1);
1312         } else {
1313             Tcl_DStringAppend(&dString, string, len-5);
1314         }
1315         Tcl_DStringAppend(&dString, Blt_Itoa(colIdx), -1);
1316         colIdx++;
1317         nStr = Tcl_DStringValue(&dString);
1318         if (Blt_TreeViewColumnNum(tvPtr, nStr)<0) {
1319             break;
1320         }
1321     }
1322     if (Blt_TreeViewCreateColumn(tvPtr, columnPtr, nStr, nStr) != TCL_OK) {
1323         Tcl_DStringFree(&dString);
1324 	return NULL;
1325     }
1326     Tcl_DStringFree(&dString);
1327     Blt_TreeViewOptsInit(tvPtr);
1328     if (Blt_ConfigureComponentFromObj(tvPtr->interp, tvPtr->tkwin,
1329 	columnPtr->key, "Column", columnSpecs, objc, objv, (char *)columnPtr,
1330 	BLT_CONFIG_OBJV_ONLY) != TCL_OK) {
1331 	DestroyColumn(tvPtr, columnPtr);
1332 	return NULL;
1333     }
1334     if (Blt_ObjConfigModified(columnSpecs, tvPtr->interp, "-background", (char *)NULL)) {
1335         columnPtr->hasbg = 1;
1336     }
1337     if (columnPtr->tile != NULL) {
1338         Blt_SetTileChangedProc(columnPtr->tile, Blt_TreeViewTileChangedProc, tvPtr);
1339     }
1340     Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr);
1341     return columnPtr;
1342 }
1343 
1344 TreeViewColumn *
Blt_TreeViewNearestColumn(tvPtr,x,y,contextPtr)1345 Blt_TreeViewNearestColumn(tvPtr, x, y, contextPtr)
1346     TreeView *tvPtr;
1347     int x, y;
1348     ClientData *contextPtr;
1349 {
1350     if (tvPtr->nVisible > 0) {
1351 	Blt_ChainLink *linkPtr;
1352 	TreeViewColumn *columnPtr;
1353 	int right;
1354 
1355 	/*
1356 	 * Determine if the pointer is over the rightmost portion of the
1357 	 * column.  This activates the rule.
1358 	 */
1359 	x = WORLDX(tvPtr, x);
1360 	for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
1361 	    linkPtr = Blt_ChainNextLink(linkPtr)) {
1362 	    columnPtr = Blt_ChainGetValue(linkPtr);
1363 	    right = columnPtr->worldX + columnPtr->width;
1364 	    if ((x >= columnPtr->worldX) && (x <= right)) {
1365 		if (contextPtr != NULL) {
1366 		    *contextPtr = NULL;
1367 		    if ((tvPtr->flags & TV_SHOW_COLUMN_TITLES) &&
1368 			(y >= tvPtr->insetY) &&
1369 			(y < (tvPtr->titleHeight + tvPtr->insetY))) {
1370 			*contextPtr = (x >= (right - RULE_AREA))
1371 			    ? ITEM_COLUMN_RULE : ITEM_COLUMN_TITLE;
1372 		    }
1373 		}
1374 		return columnPtr;
1375 	    }
1376 	}
1377     }
1378     return NULL;
1379 }
1380 
1381 /*
1382  *----------------------------------------------------------------------
1383  *
1384  * ColumnActivateOp --
1385  *
1386  *	Selects the button to appear active.
1387  *
1388  *----------------------------------------------------------------------
1389  */
1390 /*ARGSUSED*/
1391 static int
ColumnActivateOp(tvPtr,interp,objc,objv)1392 ColumnActivateOp(tvPtr, interp, objc, objv)
1393     TreeView *tvPtr;
1394     Tcl_Interp *interp;
1395     int objc;			/* Not used. */
1396     Tcl_Obj *CONST *objv;
1397 {
1398     if (objc == 4) {
1399 	Drawable drawable;
1400 	TreeViewColumn *columnPtr;
1401 	char *string;
1402 
1403 	string = Tcl_GetString(objv[3]);
1404 	if (string[0] == '\0') {
1405 	    columnPtr = NULL;
1406 	} else {
1407 	    if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr)
1408 		!= TCL_OK) {
1409 		return TCL_ERROR;
1410 	    }
1411 	    if (((tvPtr->flags & TV_SHOW_COLUMN_TITLES) == 0) ||
1412 		(columnPtr->hidden) || (columnPtr->state == STATE_DISABLED)) {
1413 		columnPtr = NULL;
1414 	    }
1415 	}
1416 	tvPtr->activeTitleColumnPtr = tvPtr->activeColumnPtr = columnPtr;
1417 	drawable = Tk_WindowId(tvPtr->tkwin);
1418 	if (drawable != None) {
1419 	    Blt_TreeViewDrawHeadings(tvPtr, drawable);
1420 	    Blt_TreeViewDrawOuterBorders(tvPtr, drawable);
1421 	}
1422     }
1423     if (tvPtr->activeTitleColumnPtr != NULL) {
1424 	Tcl_SetResult(interp, tvPtr->activeTitleColumnPtr->key, TCL_VOLATILE);
1425     }
1426     return TCL_OK;
1427 }
1428 
1429 /*
1430  *----------------------------------------------------------------------
1431  *
1432  * ColumnBindOp --
1433  *
1434  *	  .t bind tag sequence command
1435  *
1436  *----------------------------------------------------------------------
1437  */
1438 /*ARGSUSED*/
1439 static int
ColumnBindOp(tvPtr,interp,objc,objv)1440 ColumnBindOp(tvPtr, interp, objc, objv)
1441     TreeView *tvPtr;
1442     Tcl_Interp *interp;
1443     int objc;			/* Not used. */
1444     Tcl_Obj *CONST *objv;
1445 {
1446     ClientData object;
1447     TreeViewColumn *columnPtr;
1448 
1449     if (Blt_TreeViewGetColumn(NULL, tvPtr, objv[3], &columnPtr) == TCL_OK) {
1450 	object = Blt_TreeViewColumnTag(tvPtr, columnPtr->key);
1451     } else {
1452 	object = Blt_TreeViewColumnTag(tvPtr, Tcl_GetString(objv[3]));
1453     }
1454     return Blt_ConfigureBindingsFromObj(interp, tvPtr->bindTable, object,
1455 	objc - 4, objv + 4);
1456 }
1457 
1458 
1459 /*
1460  *----------------------------------------------------------------------
1461  *
1462  * ColumnCgetOp --
1463  *
1464  *----------------------------------------------------------------------
1465  */
1466 /*ARGSUSED*/
1467 static int
ColumnCgetOp(tvPtr,interp,objc,objv)1468 ColumnCgetOp(tvPtr, interp, objc, objv)
1469     TreeView *tvPtr;
1470     Tcl_Interp *interp;
1471     int objc;			/* Not used. */
1472     Tcl_Obj *CONST *objv;
1473 {
1474     TreeViewColumn *columnPtr;
1475 
1476     if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) {
1477 	return TCL_ERROR;
1478     }
1479     Blt_TreeViewOptsInit(tvPtr);
1480     return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, columnSpecs,
1481 	(char *)columnPtr, objv[4], 0);
1482 }
1483 
1484 /*
1485  *----------------------------------------------------------------------
1486  *
1487  * ColumnConfigureOp --
1488  *
1489  * 	This procedure is called to process a list of configuration
1490  *	options database, in order to reconfigure the one of more
1491  *	entries in the widget.
1492  *
1493  *	  .h entryconfigure node node node node option value
1494  *
1495  * Results:
1496  *	A standard Tcl result.  If TCL_ERROR is returned, then
1497  *	interp->result contains an error message.
1498  *
1499  * Side effects:
1500  *	Configuration information, such as text string, colors, font,
1501  *	etc. get set for tvPtr; old resources get freed, if there
1502  *	were any.  The hypertext is redisplayed.
1503  *
1504  *----------------------------------------------------------------------
1505  */
1506 static int
ColumnConfigureOp(tvPtr,interp,objc,objv)1507 ColumnConfigureOp(tvPtr, interp, objc, objv)
1508     TreeView *tvPtr;
1509     Tcl_Interp *interp;
1510     int objc;
1511     Tcl_Obj *CONST *objv;
1512 {
1513     TreeViewColumn *columnPtr;
1514     int nOptions, start, result;
1515     register int i;
1516 
1517     /* Figure out where the option value pairs begin */
1518     for(i = 4; i < objc; i++) {
1519 	if (Blt_ObjIsOption(tvPtr->interp, columnSpecs, objv[i], 0)) {
1520 	    break;
1521 	}
1522 	if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
1523 	    != TCL_OK) {
1524 	    return TCL_ERROR;
1525 	}
1526     }
1527     if (i<=3) {
1528         Tcl_AppendResult(interp, "column name missing", 0);
1529         return TCL_ERROR;
1530     }
1531     start = i;
1532     nOptions = objc - start;
1533 
1534     Blt_TreeViewOptsInit(tvPtr);
1535     for (i = 3; i < start; i++) {
1536         char *oldStyle;
1537         int isdel;
1538 
1539 	if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
1540 	    != TCL_OK) {
1541 	    return TCL_ERROR;
1542 	}
1543 	if (nOptions == 0) {
1544 	    return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, columnSpecs,
1545 		(char *)columnPtr, (Tcl_Obj *)NULL, 0);
1546 	} else if (nOptions == 1) {
1547 	    return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, columnSpecs,
1548 		(char *)columnPtr, objv[start], 0);
1549 	}
1550         oldStyle = (columnPtr->stylePtr ? columnPtr->stylePtr->name : NULL);
1551         Tcl_Preserve(columnPtr);
1552         result = Blt_ConfigureWidgetFromObj(tvPtr->interp, tvPtr->tkwin,
1553              columnSpecs, nOptions, objv + start, (char *)columnPtr,
1554              BLT_CONFIG_OBJV_ONLY, NULL);
1555          isdel = (columnPtr->flags & ENTRY_DELETED);
1556          Tcl_Release(columnPtr);
1557          if (isdel) {
1558              return TCL_ERROR;
1559          }
1560          if (columnPtr->sortAltColumns != NULL) {
1561 
1562              Tcl_Obj **sobjv;
1563              int sobjc, n;
1564              TreeViewColumn *acPtr;
1565 
1566              if (Tcl_ListObjGetElements(interp, columnPtr->sortAltColumns,
1567                  &sobjc, &sobjv) != TCL_OK) {
1568                      Tcl_DecrRefCount(columnPtr->sortAltColumns);
1569                      columnPtr->sortAltColumns = NULL;
1570                      return TCL_ERROR;
1571              }
1572              for (n = 0; n < sobjc; n++) {
1573 
1574                  if (Blt_TreeViewGetColumn(interp, tvPtr, sobjv[n], &acPtr)
1575                      != TCL_OK || acPtr == columnPtr || acPtr == &tvPtr->treeColumn) {
1576                      if (acPtr == columnPtr) {
1577                          Tcl_AppendResult(interp, "self reference", 0);
1578                      }
1579                      if (acPtr == &tvPtr->treeColumn) {
1580                          Tcl_AppendResult(interp, "tree column not valid", 0);
1581                      }
1582                      Tcl_DecrRefCount(columnPtr->sortAltColumns);
1583                      columnPtr->sortAltColumns = NULL;
1584                      return TCL_ERROR;
1585                  }
1586              }
1587         }
1588          if (columnPtr->stylePtr == NULL && oldStyle) {
1589              TreeViewStyle *stylePtr = NULL;
1590 
1591              Blt_TreeViewGetStyleMake(interp, tvPtr, oldStyle, &stylePtr, columnPtr,
1592                 NULL, NULL);
1593              columnPtr->stylePtr = stylePtr;
1594          }
1595          if (result != TCL_OK) {
1596             return TCL_ERROR;
1597          }
1598          ColumnConfigChanges(tvPtr, interp, columnPtr);
1599          Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr);
1600     }
1601     /*FIXME: Makes every change redo everything. */
1602     tvPtr->flags |= (TV_LAYOUT | TV_DIRTY);
1603     Blt_TreeViewEventuallyRedraw(tvPtr);
1604     return TCL_OK;
1605 }
1606 
1607 /*
1608  *----------------------------------------------------------------------
1609  *
1610  * ColumnDeleteOp --
1611  *
1612  *----------------------------------------------------------------------
1613  */
1614 /*ARGSUSED*/
1615 static int
ColumnDeleteOp(tvPtr,interp,objc,objv)1616 ColumnDeleteOp(tvPtr, interp, objc, objv)
1617     TreeView *tvPtr;
1618     Tcl_Interp *interp;		/* Not used. */
1619     int objc;
1620     Tcl_Obj *CONST *objv;
1621 {
1622     TreeViewColumn *columnPtr;
1623     TreeViewEntry *entryPtr;
1624     register int i;
1625 
1626     for(i = 3; i < objc; i++) {
1627 	if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
1628 	    != TCL_OK) {
1629 	    return TCL_ERROR;
1630 	}
1631 	if (columnPtr == &tvPtr->treeColumn) {
1632 	    /* Quietly ignore requests to delete tree. */
1633 	    continue;
1634 	}
1635 	if (columnPtr == tvPtr->sortColumnPtr) {
1636 	    tvPtr->sortColumnPtr = NULL;
1637 	}
1638 	/* Traverse the tree deleting values associated with the column.  */
1639 	for(entryPtr = tvPtr->rootPtr; entryPtr != NULL;
1640 	    entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
1641 	    if (entryPtr != NULL) {
1642 		TreeViewValue *valuePtr, *lastPtr, *nextPtr;
1643 
1644 		lastPtr = NULL;
1645 		for (valuePtr = entryPtr->values; valuePtr != NULL;
1646 		     valuePtr = nextPtr) {
1647 		    nextPtr = valuePtr->nextPtr;
1648 		    if (valuePtr->columnPtr == columnPtr) {
1649 			Blt_TreeViewDestroyValue(tvPtr, entryPtr, valuePtr);
1650 			if (lastPtr == NULL) {
1651 			    entryPtr->values = nextPtr;
1652 			} else {
1653 			    lastPtr->nextPtr = nextPtr;
1654 			}
1655 			break;
1656 		    }
1657 		    lastPtr = valuePtr;
1658 		}
1659 	    }
1660 	}
1661 	DestroyColumn(tvPtr, columnPtr);
1662     }
1663     /* Deleting a column may affect the height of an entry. */
1664     tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
1665     Blt_TreeViewEventuallyRedraw(tvPtr);
1666     return TCL_OK;
1667 }
1668 
1669 /*
1670  *----------------------------------------------------------------------
1671  *
1672  * ColumnIssetOp --
1673  *
1674  *   Return columns that have data in the currently visible entries.
1675  *
1676  *----------------------------------------------------------------------
1677  */
1678 /*ARGSUSED*/
1679 static int
ColumnIssetOp(tvPtr,interp,objc,objv)1680 ColumnIssetOp(tvPtr, interp, objc, objv)
1681     TreeView *tvPtr;
1682     Tcl_Interp *interp;		/* Not used. */
1683     int objc;
1684     Tcl_Obj *CONST *objv;
1685 {
1686     TreeViewColumn *columnPtr;
1687     TreeViewEntry *entryPtr, **p;
1688     TreeViewValue *valuePtr;
1689     Blt_ChainLink *linkPtr;
1690     Tcl_Obj *listObjPtr, *objPtr;
1691 
1692     listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1693     if (objc == 3) {
1694         for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
1695             linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1696             columnPtr = Blt_ChainGetValue(linkPtr);
1697             if (columnPtr == &tvPtr->treeColumn) continue;
1698 
1699             for (p = tvPtr->visibleArr; *p != NULL; p++) {
1700                 entryPtr = *p;
1701                 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
1702                 if (valuePtr != NULL) {
1703                     objPtr = Tcl_NewStringObj(columnPtr->key, -1);
1704                     Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1705                     break;
1706                 }
1707             }
1708         }
1709     } else if (objc == 4) {
1710         TreeViewTagInfo info = {0};
1711 
1712         for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
1713             linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1714 
1715             columnPtr = Blt_ChainGetValue(linkPtr);
1716             if (columnPtr == &tvPtr->treeColumn) continue;
1717             if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[3], &info) != TCL_OK) {
1718                 return TCL_ERROR;
1719             }
1720             for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
1721                 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
1722 
1723                 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
1724                 if (valuePtr != NULL) {
1725                     objPtr = Tcl_NewStringObj(columnPtr->key, -1);
1726                     Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1727                     break;
1728                 }
1729             }
1730             Blt_TreeViewDoneTaggedEntries(&info);
1731         }
1732 
1733     } else if (objc == 5) {
1734         TreeViewEntry *ePtr, *entryPtr2;
1735         if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
1736             return TCL_ERROR;
1737         }
1738         if (Blt_TreeViewGetEntry(tvPtr, objv[4], &entryPtr2) != TCL_OK) {
1739             return TCL_ERROR;
1740         }
1741         for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
1742             linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1743             columnPtr = Blt_ChainGetValue(linkPtr);
1744             if (columnPtr == &tvPtr->treeColumn) continue;
1745             for (ePtr = entryPtr; ePtr;
1746                 ePtr = Blt_TreeViewNextEntry(ePtr, ENTRY_MASK)) {
1747                 valuePtr = Blt_TreeViewFindValue(ePtr, columnPtr);
1748                 if (valuePtr != NULL) {
1749                     objPtr = Tcl_NewStringObj(columnPtr->key, -1);
1750                     Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1751                     break;
1752                 }
1753                 if (ePtr == entryPtr2) break;
1754             }
1755 
1756         }
1757     }
1758     Tcl_SetObjResult(interp, listObjPtr);
1759 
1760     return TCL_OK;
1761 }
1762 
1763 /*
1764  *----------------------------------------------------------------------
1765  *
1766  * ColumnIndexOp --
1767  *
1768  *	Return column index.
1769  *
1770  *----------------------------------------------------------------------
1771  */
1772 /*ARGSUSED*/
1773 static int
ColumnIndexOp(tvPtr,interp,objc,objv)1774 ColumnIndexOp(tvPtr, interp, objc, objv)
1775     TreeView *tvPtr;
1776     Tcl_Interp *interp;
1777     int objc;
1778     Tcl_Obj *CONST *objv;
1779 {
1780     int n, cnt;
1781     char *string;
1782 
1783     string = Tcl_GetString(objv[3]);
1784 
1785     cnt = Blt_TreeViewNumColumns(tvPtr);
1786     if (strncmp("end", string, 3) == 0 &&
1787         Blt_GetPositionSize(interp, string, cnt, &n) == TCL_OK) {
1788             Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
1789             return TCL_OK;
1790     }
1791     n = Blt_TreeViewColumnNum(tvPtr, string);
1792     if (n<0) {
1793         if ((Tcl_GetInt(NULL, string, &n) != TCL_OK)) {
1794             goto err;
1795         }
1796         if (n>=cnt || n<0) {
1797             goto err;
1798         }
1799     }
1800     if (n<0) {
1801 err:
1802         Tcl_AppendResult(interp, "unknown column: ", string, 0);
1803         return TCL_ERROR;
1804     }
1805     Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
1806     return TCL_OK;
1807 }
1808 
1809 
1810 /*
1811  *----------------------------------------------------------------------
1812  *
1813  * ColumnIstreeOp --
1814  *
1815  *	Return 1 if is the tree column.
1816  *
1817  *----------------------------------------------------------------------
1818  */
1819 /*ARGSUSED*/
1820 static int
ColumnIstreeOp(tvPtr,interp,objc,objv)1821 ColumnIstreeOp(tvPtr, interp, objc, objv)
1822     TreeView *tvPtr;
1823     Tcl_Interp *interp;
1824     int objc;
1825     Tcl_Obj *CONST *objv;
1826 {
1827     TreeViewColumn *columnPtr;
1828     if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) {
1829         return TCL_ERROR;
1830     }
1831 
1832     Tcl_SetObjResult(interp, Tcl_NewIntObj(columnPtr==&tvPtr->treeColumn));
1833     return TCL_OK;
1834 }
1835 
1836 
1837 /*
1838  *----------------------------------------------------------------------
1839  *
1840  * ColumnInsertOp --
1841  *
1842  *	Add new columns to the tree.
1843  *      .t col insert POS NAME ...
1844  *
1845  *----------------------------------------------------------------------
1846  */
1847 /*ARGSUSED*/
1848 static int
ColumnInsertOp(tvPtr,interp,objc,objv)1849 ColumnInsertOp(tvPtr, interp, objc, objv)
1850     TreeView *tvPtr;
1851     Tcl_Interp *interp;
1852     int objc;
1853     Tcl_Obj *CONST *objv;
1854 {
1855     Blt_ChainLink *beforePtr;
1856     Tcl_Obj *CONST *options;
1857     TreeViewColumn *columnPtr;
1858     TreeViewEntry *entryPtr;
1859     int insertPos;
1860     int nOptions;
1861     int start;
1862     register int i;
1863     int maxCol = Blt_ChainGetLength(tvPtr->colChainPtr);
1864 
1865     if (Blt_GetPositionSizeFromObj(tvPtr->interp, objv[3], maxCol,
1866         &insertPos) != TCL_OK) {
1867         if ((insertPos = Blt_TreeViewColumnNum(tvPtr, Tcl_GetString(objv[3])))<0) {
1868             return TCL_ERROR;
1869         }
1870         Tcl_ResetResult(interp);
1871     }
1872     if ((insertPos == -1) ||
1873 	(insertPos >= maxCol)) {
1874 	beforePtr = NULL;
1875     } else {
1876 	beforePtr =  Blt_ChainGetNthLink(tvPtr->colChainPtr, insertPos);
1877     }
1878     /*
1879      * Count the column names that follow.  Count the arguments until we
1880      * spot one that looks like a configuration option (i.e. starts
1881      * with a minus ("-")).
1882      */
1883     for (i = 5; i < objc; i++) {
1884         char *cp = Tcl_GetString(objv[i]);
1885         if (cp[0] == '-') break;
1886     }
1887     start = i;
1888     nOptions = objc - i;
1889     options = objv + start;
1890 
1891     if ((objc-nOptions) < 5) {
1892         Tcl_AppendResult(interp, "column insert must have a name", 0);
1893         return TCL_ERROR;
1894     }
1895     if ((objc-start)%2) {
1896         Tcl_AppendResult(interp, "odd number of column options", 0);
1897         return TCL_ERROR;
1898     }
1899     for (i = start; i < objc; i+=2) {
1900         if (!Blt_ObjIsOption(tvPtr->interp, columnSpecs, objv[i], 0)) {
1901             Tcl_AppendResult(interp, "unknown option \"", Tcl_GetString(objv[i]), "\", should be one of one: ", 0);
1902             Blt_FormatSpecOptions(interp, columnSpecs);
1903             return TCL_ERROR;
1904         }
1905     }
1906 
1907     for (i = 4; i < start; i++) {
1908 	if (Blt_TreeViewGetColumn(NULL, tvPtr, objv[i], &columnPtr) == TCL_OK) {
1909 	    Tcl_AppendResult(interp, "column \"", Tcl_GetString(objv[i]),
1910 		"\" already exists", (char *)NULL);
1911 	    return TCL_ERROR;
1912 	}
1913 	columnPtr = CreateColumn(tvPtr, objv[i], nOptions, options);
1914 	if (columnPtr == NULL) {
1915 	    return TCL_ERROR;
1916 	}
1917 	if (beforePtr == NULL) {
1918 	    columnPtr->linkPtr = Blt_ChainAppend(tvPtr->colChainPtr, columnPtr);
1919 	} else {
1920 	    columnPtr->linkPtr = Blt_ChainNewLink();
1921 	    Blt_ChainSetValue(columnPtr->linkPtr, columnPtr);
1922 	    Blt_ChainLinkBefore(tvPtr->colChainPtr, columnPtr->linkPtr,
1923 		beforePtr);
1924 	}
1925 	Tcl_AppendResult(interp, i>4?" ":"", columnPtr->key, 0);
1926 	/*
1927 	 * Traverse the tree adding column entries where needed.
1928 	 */
1929 	for(entryPtr = tvPtr->rootPtr; entryPtr != NULL;
1930 	    entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
1931 	    Blt_TreeViewAddValue(entryPtr, columnPtr);
1932 	}
1933 	Blt_TreeViewTraceColumn(tvPtr, columnPtr);
1934     }
1935     Blt_TreeViewEventuallyRedraw(tvPtr);
1936     return TCL_OK;
1937 }
1938 
1939 
1940 
1941 /*
1942  *----------------------------------------------------------------------
1943  *
1944  * ColumnCurrentOp --
1945  *
1946  *	Make the rule to appear active.
1947  *
1948  *----------------------------------------------------------------------
1949  */
1950 /*ARGSUSED*/
1951 static int
ColumnCurrentOp(tvPtr,interp,objc,objv)1952 ColumnCurrentOp(tvPtr, interp, objc, objv)
1953     TreeView *tvPtr;
1954     Tcl_Interp *interp;
1955     int objc;			/* Not used. */
1956     Tcl_Obj *CONST *objv;	/* Not used. */
1957 {
1958     ClientData context;
1959     TreeViewColumn *columnPtr;
1960 
1961     columnPtr = NULL;
1962     context = Blt_GetCurrentContext(tvPtr->bindTable);
1963     if ((context == ITEM_COLUMN_TITLE) || (context == ITEM_COLUMN_RULE)) {
1964 	columnPtr = Blt_GetCurrentItem(tvPtr->bindTable);
1965     }
1966     if (context >= ITEM_STYLE) {
1967 	TreeViewValue *valuePtr = context;
1968 
1969 	columnPtr = valuePtr->columnPtr;
1970     }
1971     if (columnPtr != NULL) {
1972 	Tcl_SetResult(interp, columnPtr->key, TCL_VOLATILE);
1973     }
1974     return TCL_OK;
1975 }
1976 
1977 static void
ColumnPercentSubst(tvPtr,columnPtr,command,resultPtr)1978 ColumnPercentSubst(tvPtr, columnPtr, command, resultPtr)
1979     TreeView *tvPtr;
1980     TreeViewColumn *columnPtr;
1981     char *command;
1982     Tcl_DString *resultPtr;
1983 {
1984     register char *last, *p;
1985     int one = (command[0] == '%' && strlen(command)==2);
1986 
1987     /*
1988      * Get the full path name of the node, in case we need to
1989      * substitute for it.
1990      */
1991     Tcl_DStringInit(resultPtr);
1992     /* Append the widget name and the node .t 0 */
1993     for (last = p = command; *p != '\0'; p++) {
1994 	if (*p == '%') {
1995 	    char *string;
1996 	    char buf[3];
1997 
1998 	    if (p > last) {
1999 		*p = '\0';
2000 		Tcl_DStringAppend(resultPtr, last, -1);
2001 		*p = '%';
2002 	    }
2003 	    switch (*(p + 1)) {
2004 	    case '%':		/* Percent sign */
2005 		string = "%";
2006 		break;
2007 	    case 'W':		/* Widget name */
2008 		string = Tk_PathName(tvPtr->tkwin);
2009 		break;
2010 	    case 'C':		/* Node identifier */
2011 		string = columnPtr->key;
2012                 if (one) {
2013                     Tcl_DStringAppend(resultPtr, string, -1);
2014                 } else {
2015                     Tcl_DStringAppendElement(resultPtr, string);
2016                 }
2017                 p++;
2018                 last = p + 1;
2019                 continue;
2020                 break;
2021 	    default:
2022 		if (*(p + 1) == '\0') {
2023 		    p--;
2024 		}
2025 		buf[0] = *p, buf[1] = *(p + 1), buf[2] = '\0';
2026 		string = buf;
2027 		break;
2028 	    }
2029 	    Tcl_DStringAppend(resultPtr, string, -1);
2030 	    p++;
2031 	    last = p + 1;
2032 	}
2033     }
2034     if (p > last) {
2035 	*p = '\0';
2036 	Tcl_DStringAppend(resultPtr, last, -1);
2037     }
2038 }
2039 
2040 
2041 /*
2042  *----------------------------------------------------------------------
2043  *
2044  * ColumnInvokeOp --
2045  *
2046  * 	This procedure is called to invoke a column command.
2047  *
2048  *	  .h column invoke columnName
2049  *
2050  * Results:
2051  *	A standard Tcl result.  If TCL_ERROR is returned, then
2052  *	interp->result contains an error message.
2053  *
2054  *----------------------------------------------------------------------
2055  */
2056 /*ARGSUSED*/
2057 static int
ColumnInvokeOp(tvPtr,interp,objc,objv)2058 ColumnInvokeOp(tvPtr, interp, objc, objv)
2059     TreeView *tvPtr;
2060     Tcl_Interp *interp;		/* Not used. */
2061     int objc;
2062     Tcl_Obj *CONST *objv;
2063 {
2064     TreeViewColumn *columnPtr;
2065     char *string;
2066 
2067     string = Tcl_GetString(objv[3]);
2068     if (string[0] == '\0') {
2069 	return TCL_OK;
2070     }
2071     if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) {
2072 	return TCL_ERROR;
2073     }
2074     if ((columnPtr->state == STATE_NORMAL) && (columnPtr->titleCmd != NULL)) {
2075         Tcl_DString dString;
2076         int result;
2077 
2078         Tcl_DStringInit(&dString);
2079         ColumnPercentSubst(tvPtr, columnPtr, columnPtr->titleCmd, &dString);
2080         Tcl_Preserve(tvPtr);
2081 	Tcl_Preserve(columnPtr);
2082         result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString));
2083 	Tcl_Release(columnPtr);
2084 	Tcl_Release(tvPtr);
2085 	Tcl_DStringFree(&dString);
2086 	return result;
2087     }
2088     return TCL_OK;
2089 }
2090 
2091 /*
2092  *----------------------------------------------------------------------
2093  *
2094  * ColumnValuesOp --
2095  *
2096  * 	This procedure is called to get all column values.
2097  *
2098  *	  .h column values ?-visible? ?-default value? columnName ?start? ?end?
2099  *
2100  * Results:
2101  *	A standard Tcl result.  If TCL_ERROR is returned, then
2102  *	interp->result contains an error message.
2103  *
2104  *----------------------------------------------------------------------
2105  */
2106 /*ARGSUSED*/
2107 static int
ColumnValuesOp(tvPtr,interp,objc,objv)2108 ColumnValuesOp(tvPtr, interp, objc, objv)
2109     TreeView *tvPtr;
2110     Tcl_Interp *interp;		/* Not used. */
2111     int objc;
2112     Tcl_Obj *CONST *objv;
2113 {
2114     TreeViewColumn *columnPtr;
2115     TreeViewEntry *entryPtr, *lastPtr = NULL, *firstPtr = NULL;
2116     int isTree;
2117     int mask;
2118     Tcl_Obj *listObjPtr, *objPtr, *defObj;
2119     char *string;
2120 
2121     mask = 0;
2122     defObj = NULL;
2123     while (objc>4) {
2124         string = Tcl_GetString(objv[3]);
2125         if (string[0] == '-' && strcmp(string, "-visible") == 0) {
2126             mask = ENTRY_MASK;
2127             objv++;
2128             objc--;
2129         } else if (string[0] == '-' && strcmp(string, "-default") == 0) {
2130             defObj = objv[4];
2131             objv += 2;
2132             objc -= 2;
2133         } else {
2134             break;
2135         }
2136     }
2137     if (objc>6) {
2138         Tcl_AppendResult(interp, "too many args", 0);
2139         return TCL_ERROR;
2140     }
2141     if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) {
2142 	return TCL_ERROR;
2143     }
2144     isTree = (columnPtr == &tvPtr->treeColumn);
2145 
2146     if (objc > 4 && Blt_TreeViewGetEntry(tvPtr, objv[4], &firstPtr) != TCL_OK) {
2147         return TCL_ERROR;
2148     }
2149     if (objc > 5 && Blt_TreeViewGetEntry(tvPtr, objv[5], &lastPtr) != TCL_OK) {
2150         return TCL_ERROR;
2151     }
2152     if (firstPtr == NULL) {
2153         firstPtr = tvPtr->rootPtr;
2154     }
2155     if (mask && firstPtr == tvPtr->rootPtr) {
2156         if ((tvPtr->flags & TV_HIDE_ROOT)) {
2157             firstPtr = Blt_TreeViewNextEntry(firstPtr, mask);
2158         }
2159     } else if (mask  && (firstPtr->flags & mask)) {
2160         firstPtr = Blt_TreeViewNextEntry(firstPtr, mask);
2161     }
2162     listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
2163 
2164     for (entryPtr = firstPtr; entryPtr != NULL; ) {
2165         if (!isTree) {
2166             if (Blt_TreeGetValueByKey(NULL, tvPtr->tree, entryPtr->node,
2167                 columnPtr->key, &objPtr) != TCL_OK) {
2168                 if (defObj == NULL) {
2169                     objPtr = Tcl_NewStringObj("",0);
2170                 } else {
2171                     objPtr = defObj;
2172                 }
2173                 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
2174             } else {
2175                 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
2176             }
2177         } else {
2178             objPtr = Tcl_NewStringObj(Blt_TreeNodeLabel(entryPtr->node),-1);
2179             Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
2180         }
2181         if (lastPtr && entryPtr == lastPtr) break;
2182         entryPtr = Blt_TreeViewNextEntry(entryPtr, mask);
2183     }
2184     Tcl_SetObjResult(interp, listObjPtr);
2185 
2186     return TCL_OK;
2187 }
2188 
2189 /*
2190  *----------------------------------------------------------------------
2191  *
2192  * ColumnMoveOp --
2193  *
2194  *	Move a column.
2195  *
2196  * .h column move field1 position
2197  * NOT IMPLEMENTED;
2198  *----------------------------------------------------------------------
2199  */
2200 static int
ColumnMoveOp(tvPtr,interp,objc,objv)2201 ColumnMoveOp(tvPtr, interp, objc, objv)
2202     TreeView *tvPtr;
2203     Tcl_Interp *interp;
2204     int objc;			/* Not used. */
2205     Tcl_Obj *CONST *objv;
2206 {
2207     TreeViewColumn *columnPtr, *beforeColumn;
2208     Blt_ChainLink *beforePtr;
2209     char *string;
2210 
2211     if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) {
2212 	return TCL_ERROR;
2213     }
2214     if (columnPtr->linkPtr == NULL) {
2215         return TCL_OK;
2216     }
2217     string = Tcl_GetString(objv[4]);
2218     if (!strcmp(string, "end")) {
2219         beforePtr = NULL;
2220     } else if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &beforeColumn) != TCL_OK) {
2221         return TCL_ERROR;
2222 
2223     } else {
2224         beforePtr = beforeColumn->linkPtr;
2225     }
2226     if (beforePtr == columnPtr->linkPtr) {
2227         return TCL_OK;
2228     }
2229     Blt_ChainUnlinkLink(tvPtr->colChainPtr, columnPtr->linkPtr);
2230     Blt_ChainLinkBefore(tvPtr->colChainPtr, columnPtr->linkPtr, beforePtr);
2231     tvPtr->flags |= (TV_DIRTY | TV_LAYOUT);
2232     Blt_TreeViewEventuallyRedraw(tvPtr);
2233     return TCL_OK;
2234 }
2235 
2236 /*
2237  *----------------------------------------------------------------------
2238  *
2239  * ColumnNamesOp --
2240  *
2241  *----------------------------------------------------------------------
2242  */
2243 /*ARGSUSED*/
2244 static int
ColumnNamesOp(tvPtr,interp,objc,objv)2245 ColumnNamesOp(tvPtr, interp, objc, objv)
2246     TreeView *tvPtr;
2247     Tcl_Interp *interp;
2248     int objc;			/* Not used. */
2249     Tcl_Obj *CONST *objv;		/* Not used. */
2250 {
2251     Blt_ChainLink *linkPtr;
2252     Tcl_Obj *listObjPtr, *objPtr;
2253     TreeViewColumn *columnPtr;
2254     int vis;
2255     char *pattern = NULL;
2256 
2257     vis = 0;
2258     if (objc > 3) {
2259         if (strcmp("-visible", Tcl_GetString(objv[3]))) {
2260             if (objc>4) {
2261                 Tcl_AppendResult( interp, "expected -visible", (char*)NULL);
2262                 return TCL_ERROR;
2263             } else {
2264                 pattern = Tcl_GetString(objv[3]);
2265             }
2266         } else {
2267             vis =  1;
2268             if (objc>4) {
2269                 pattern = Tcl_GetString(objv[4]);
2270             }
2271         }
2272     }
2273     listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
2274     for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
2275 	linkPtr = Blt_ChainNextLink(linkPtr)) {
2276 	columnPtr = Blt_ChainGetValue(linkPtr);
2277 	if (vis && columnPtr->hidden) {
2278 	    continue;
2279 	}
2280 	if (pattern != NULL && !Tcl_StringMatch(columnPtr->key, pattern)) {
2281 	    continue;
2282 	}
2283 	objPtr = Tcl_NewStringObj(columnPtr->key, -1);
2284 	Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
2285     }
2286     Tcl_SetObjResult(interp, listObjPtr);
2287     return TCL_OK;
2288 }
2289 
2290 /*ARGSUSED*/
2291 static int
ColumnNearestOp(tvPtr,interp,objc,objv)2292 ColumnNearestOp(tvPtr, interp, objc, objv)
2293     TreeView *tvPtr;
2294     Tcl_Interp *interp;
2295     int objc;			/* Not used. */
2296     Tcl_Obj *CONST *objv;
2297 {
2298     int x, y;			/* Screen coordinates of the test point. */
2299     TreeViewColumn *columnPtr;
2300     ClientData context;
2301     int checkTitle;
2302 #ifdef notdef
2303     int isRoot;
2304 
2305     isRoot = FALSE;
2306     string = Tcl_GetString(objv[3]);
2307 
2308     if (strcmp("-root", string) == 0) {
2309 	isRoot = TRUE;
2310 	objv++, objc--;
2311     }
2312     if (objc != 5) {
2313 	Tcl_AppendResult(interp, "wrong # args: should be \"",
2314 		Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]),
2315 		Tcl_GetString(objv[2]), " ?-root? x y\"", (char *)NULL);
2316 	return TCL_ERROR;
2317 
2318     }
2319 #endif
2320     if (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[3], &x) != TCL_OK) {
2321 	return TCL_ERROR;
2322     }
2323     y = 0;
2324     checkTitle = FALSE;
2325     if (objc == 5) {
2326 	if (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[4], &y) != TCL_OK) {
2327 	    return TCL_ERROR;
2328 	}
2329 	checkTitle = TRUE;
2330     }
2331     columnPtr = Blt_TreeViewNearestColumn(tvPtr, x, y, &context);
2332     if ((checkTitle) && (context == NULL)) {
2333 	columnPtr = NULL;
2334     }
2335     if (columnPtr != NULL) {
2336 	Tcl_SetObjResult(interp, Tcl_NewStringObj(columnPtr->key,-1));
2337     }
2338     return TCL_OK;
2339 }
2340 
2341 /*ARGSUSED*/
2342 static int
ColumnOffsetsOp(tvPtr,interp,objc,objv)2343 ColumnOffsetsOp(tvPtr, interp, objc, objv)
2344     TreeView *tvPtr;
2345     Tcl_Interp *interp;
2346     int objc;			/* Not used. */
2347     Tcl_Obj *CONST *objv;
2348 {
2349     Tcl_Obj *listPtr;
2350     Blt_ChainLink *linkPtr;
2351     TreeViewColumn *columnPtr;
2352     int x;
2353     int vis;
2354 
2355     vis = 0;
2356     if (objc > 3) {
2357         if (strcmp("-visible", Tcl_GetString(objv[3]))) {
2358             Tcl_AppendResult( interp, "expected -visible", (char*)NULL);
2359             return TCL_ERROR;
2360         }
2361         vis =  1;
2362     }
2363 
2364     listPtr = Tcl_NewListObj(0,0);
2365     for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
2366         linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2367         columnPtr = Blt_ChainGetValue(linkPtr);
2368         if (vis && columnPtr->hidden) {
2369             continue;
2370         }
2371         x = SCREENX(tvPtr, columnPtr->worldX);
2372         Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(x));
2373     }
2374     Tcl_SetObjResult(interp, listPtr);
2375     return TCL_OK;
2376 
2377 }
2378 
2379 /* .t column bbox field entry */
2380 /*ARGSUSED*/
2381 static int
ColumnBboxOp(tvPtr,interp,objc,objv)2382 ColumnBboxOp(tvPtr, interp, objc, objv)
2383     TreeView *tvPtr;
2384     Tcl_Interp *interp;
2385     int objc;			/* Not used. */
2386     Tcl_Obj *CONST *objv;
2387 {
2388     Tcl_Obj *listPtr;
2389     TreeViewColumn *colPtr;
2390     TreeViewEntry *entryPtr = NULL;
2391     int x, y, w, h, visible = 0;
2392     const char *string;
2393     int mw, mh;
2394     mw = Tk_Width(tvPtr->tkwin) - tvPtr->padX;
2395     mh = Tk_Height(tvPtr->tkwin) - tvPtr->padY;
2396 
2397     if (objc == 6) {
2398         string = Tcl_GetString(objv[3]);
2399         if (strcmp("-visible", string)) {
2400             Tcl_AppendResult(interp, "expected -visible", 0);
2401             return TCL_ERROR;
2402         }
2403         visible = 1;
2404         objc--;
2405         objv++;
2406     }
2407     if (objc != 5) {
2408         Tcl_AppendResult(interp, "missing args", 0);
2409         return TCL_ERROR;
2410     }
2411     if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &colPtr) != TCL_OK ||
2412         colPtr == NULL) {
2413         return TCL_ERROR;
2414     }
2415     string = Tcl_GetString(objv[4]);
2416     if (!strcmp(string, "-1")) {
2417     } else if (Blt_TreeViewGetEntry(tvPtr, objv[4], &entryPtr) != TCL_OK ||
2418         entryPtr == NULL) {
2419         return TCL_ERROR;
2420     }
2421     if (tvPtr->flags & TV_LAYOUT) {
2422         Blt_TreeViewComputeLayout(tvPtr);
2423     }
2424     if (entryPtr == NULL) {
2425         if (!(tvPtr->flags & TV_SHOW_COLUMN_TITLES)) return TCL_OK;
2426         listPtr = Tcl_NewListObj(0,0);
2427         x = SCREENX(tvPtr, colPtr->worldX);
2428         y = (tvPtr->yOffset + tvPtr->insetY);
2429         w = colPtr->width;
2430         h = tvPtr->titleHeight;
2431         if (visible) {
2432             if ((x+w) > mw) {
2433                 w = (mw-x-2);
2434             }
2435             if ((y+h) > mh) {
2436                 w = (mh-y-2);
2437             }
2438         }
2439         Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(x));
2440         Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(y));
2441         Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(w));
2442         Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(h));
2443         Tcl_SetObjResult(interp, listPtr);
2444         return TCL_OK;
2445     }
2446     if (Blt_TreeViewEntryIsHidden(entryPtr)) {
2447         return TCL_OK;
2448     }
2449     listPtr = Tcl_NewListObj(0,0);
2450     x = SCREENX(tvPtr, colPtr->worldX);
2451     y = SCREENY(tvPtr, entryPtr->worldY);
2452     w = colPtr->width;
2453     h = entryPtr->height;
2454     if (visible) {
2455         if ((x+w) > mw) {
2456             w = (mw-x-2);
2457         }
2458         if ((y+h) > mh) {
2459             w = (mh-y-2);
2460         }
2461     }
2462     Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(x));
2463     Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(y));
2464     Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(w));
2465     Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(h));
2466     Tcl_SetObjResult(interp, listPtr);
2467     return TCL_OK;
2468 
2469 }
2470 
2471 /*ARGSUSED*/
2472 static int
ColumnSeeOp(tvPtr,interp,objc,objv)2473 ColumnSeeOp(tvPtr, interp, objc, objv)
2474     TreeView *tvPtr;
2475     Tcl_Interp *interp;		/* Not used. */
2476     int objc;
2477     Tcl_Obj *CONST *objv;
2478 {
2479     TreeViewColumn *colPtr;
2480     int width, height;
2481     Tk_Anchor anchor;
2482     int left, right;
2483     char *string;
2484 
2485     string = Tcl_GetString(objv[3]);
2486     anchor = TK_ANCHOR_W;	/* Default anchor is West */
2487     if ((string[0] == '-') && (strcmp(string, "-anchor") == 0)) {
2488 	if (objc == 4) {
2489 	    Tcl_AppendResult(interp, "missing \"-anchor\" argument",
2490 		(char *)NULL);
2491 	    return TCL_ERROR;
2492 	}
2493 	if (Tk_GetAnchorFromObj(interp, objv[4], &anchor) != TCL_OK) {
2494 	    return TCL_ERROR;
2495 	}
2496 	objc -= 2, objv += 2;
2497     }
2498     if (objc != 4) {
2499         Tcl_AppendResult(interp, "wrong # args: should be \"",
2500             "see ?-anchor anchor? tagOrId\"", (char *)NULL);
2501             return TCL_ERROR;
2502     }
2503     if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &colPtr) != TCL_OK ||
2504         colPtr == NULL) {
2505         return TCL_ERROR;
2506     }
2507     if (colPtr->hidden) {
2508         return TCL_OK;
2509     }
2510     width = VPORTWIDTH(tvPtr);
2511     height = VPORTHEIGHT(tvPtr);
2512 
2513     left = tvPtr->xOffset;
2514     right = tvPtr->xOffset + width;
2515 
2516     if (colPtr->worldX >= left && (colPtr->worldX + colPtr->width) <= right) {
2517         return TCL_OK;
2518     }
2519     if (colPtr->worldX < left) {
2520         tvPtr->xOffset = colPtr->worldX;
2521     } else {
2522         tvPtr->xOffset = colPtr->worldX;
2523     }
2524     tvPtr->flags |= TV_XSCROLL;
2525 
2526 #if 0
2527     switch (anchor) {
2528     case TK_ANCHOR_W:
2529     case TK_ANCHOR_NW:
2530     case TK_ANCHOR_SW:
2531 	x = 0;
2532 	break;
2533     case TK_ANCHOR_E:
2534     case TK_ANCHOR_NE:
2535     case TK_ANCHOR_SE:
2536 	x = entryPtr->worldX + entryPtr->width +
2537 	    ICONWIDTH(DEPTH(tvPtr, entryPtr->node)) - width;
2538 	break;
2539     default:
2540 	if (entryPtr->worldX < left) {
2541 	    x = entryPtr->worldX;
2542 	} else if ((entryPtr->worldX + entryPtr->width) > right) {
2543 	    x = entryPtr->worldX + entryPtr->width - width;
2544 	} else {
2545 	    x = tvPtr->xOffset;
2546 	}
2547 	break;
2548     }
2549     if (x != tvPtr->xOffset) {
2550 	tvPtr->xOffset = x;
2551 	tvPtr->flags |= TV_XSCROLL;
2552     }
2553 #endif
2554     Blt_TreeViewEventuallyRedraw(tvPtr);
2555     return TCL_OK;
2556 }
2557 
2558 static void
UpdateMark(tvPtr,newMark)2559 UpdateMark(tvPtr, newMark)
2560     TreeView *tvPtr;
2561     int newMark;
2562 {
2563     Drawable drawable;
2564     TreeViewColumn *columnPtr;
2565     int dx;
2566     int width;
2567 
2568     columnPtr = tvPtr->resizeColumnPtr;
2569     if (columnPtr == NULL) {
2570 	return;
2571     }
2572     drawable = Tk_WindowId(tvPtr->tkwin);
2573     if (drawable == None) {
2574 	return;
2575     }
2576 
2577     /* Erase any existing rule. */
2578     if (tvPtr->flags & TV_RULE_ACTIVE) {
2579 	Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
2580     }
2581 
2582     dx = newMark - tvPtr->ruleAnchor;
2583     width = columnPtr->width -
2584 	(PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth);
2585     if ((columnPtr->reqMin > 0) && ((width + dx) < columnPtr->reqMin)) {
2586 	dx = columnPtr->reqMin - width;
2587     }
2588     if ((columnPtr->reqMax > 0) && ((width + dx) > columnPtr->reqMax)) {
2589 	dx = columnPtr->reqMax - width;
2590     }
2591     if ((width + dx) < 4) {
2592 	dx = 4 - width;
2593     }
2594     tvPtr->ruleMark = tvPtr->ruleAnchor + dx;
2595 
2596     /* Redraw the rule if required. */
2597     if (tvPtr->flags & TV_RULE_NEEDED) {
2598 	Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
2599     }
2600 }
2601 
2602 /*
2603  *----------------------------------------------------------------------
2604  *
2605  * ResizeActivateOp --
2606  *
2607  *	Turns on/off the resize cursor.
2608  *
2609  *----------------------------------------------------------------------
2610  */
2611 /*ARGSUSED*/
2612 static int
ResizeActivateOp(tvPtr,interp,objc,objv)2613 ResizeActivateOp(tvPtr, interp, objc, objv)
2614     TreeView *tvPtr;
2615     Tcl_Interp *interp;
2616     int objc;			/* Not used. */
2617     Tcl_Obj *CONST *objv;
2618 {
2619     TreeViewColumn *columnPtr;
2620     char *string;
2621 
2622     string = Tcl_GetString(objv[4]);
2623     if (string[0] == '\0') {
2624 	if (tvPtr->cursor != None) {
2625 	    Tk_DefineCursor(tvPtr->tkwin, tvPtr->cursor);
2626 	} else {
2627 	    Tk_UndefineCursor(tvPtr->tkwin);
2628 	}
2629 	tvPtr->resizeColumnPtr = NULL;
2630     } else if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr)
2631 	       == TCL_OK) {
2632 	if (tvPtr->resizeCursor != None) {
2633 	    Tk_DefineCursor(tvPtr->tkwin, tvPtr->resizeCursor);
2634 	}
2635 	tvPtr->resizeColumnPtr = columnPtr;
2636     } else {
2637 	return TCL_ERROR;
2638     }
2639     return TCL_OK;
2640 }
2641 
2642 /*
2643  *----------------------------------------------------------------------
2644  *
2645  * ResizeAnchorOp --
2646  *
2647  *	Set the anchor for the resize.
2648  *
2649  *----------------------------------------------------------------------
2650  */
2651 /*ARGSUSED*/
2652 static int
ResizeAnchorOp(tvPtr,interp,objc,objv)2653 ResizeAnchorOp(tvPtr, interp, objc, objv)
2654     TreeView *tvPtr;
2655     Tcl_Interp *interp;
2656     int objc;			/* Not used. */
2657     Tcl_Obj *CONST *objv;
2658 {
2659     int x;
2660 
2661     if (Tcl_GetIntFromObj(NULL, objv[4], &x) != TCL_OK) {
2662 	return TCL_ERROR;
2663     }
2664     tvPtr->ruleAnchor = x;
2665     tvPtr->flags |= TV_RULE_NEEDED;
2666     UpdateMark(tvPtr, x);
2667     return TCL_OK;
2668 }
2669 
2670 /*
2671  *----------------------------------------------------------------------
2672  *
2673  * ResizeMarkOp --
2674  *
2675  *	Sets the resize mark.  The distance between the mark and the anchor
2676  *	is the delta to change the width of the active column.
2677  *
2678  *----------------------------------------------------------------------
2679  */
2680 /*ARGSUSED*/
2681 static int
ResizeMarkOp(tvPtr,interp,objc,objv)2682 ResizeMarkOp(tvPtr, interp, objc, objv)
2683     TreeView *tvPtr;
2684     Tcl_Interp *interp;
2685     int objc;			/* Not used. */
2686     Tcl_Obj *CONST *objv;
2687 {
2688     int x;
2689 
2690     if (Tcl_GetIntFromObj(NULL, objv[4], &x) != TCL_OK) {
2691 	return TCL_ERROR;
2692     }
2693     tvPtr->flags |= TV_RULE_NEEDED;
2694     UpdateMark(tvPtr, x);
2695     return TCL_OK;
2696 }
2697 
2698 /*
2699  *----------------------------------------------------------------------
2700  *
2701  * ResizeSetOp --
2702  *
2703  *	Returns the new width of the column including the resize delta.
2704  *
2705  *----------------------------------------------------------------------
2706  */
2707 /*ARGSUSED*/
2708 static int
ResizeSetOp(tvPtr,interp,objc,objv)2709 ResizeSetOp(tvPtr, interp, objc, objv)
2710     TreeView *tvPtr;
2711     Tcl_Interp *interp;
2712     int objc;			/* Not used. */
2713     Tcl_Obj *CONST *objv;	/* Not used. */
2714 {
2715     tvPtr->flags &= ~TV_RULE_NEEDED;
2716     UpdateMark(tvPtr, tvPtr->ruleMark);
2717     if (tvPtr->resizeColumnPtr != NULL) {
2718 	int width, delta;
2719 	TreeViewColumn *columnPtr;
2720 
2721 	columnPtr = tvPtr->resizeColumnPtr;
2722 	delta = (tvPtr->ruleMark - tvPtr->ruleAnchor);
2723 	width = tvPtr->resizeColumnPtr->width + delta -
2724 	    (PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth) - 1;
2725 	Tcl_SetObjResult(interp, Tcl_NewIntObj(width));
2726     }
2727     return TCL_OK;
2728 }
2729 
2730 static Blt_OpSpec resizeOps[] =
2731 {
2732     {"activate", 2, (Blt_Op)ResizeActivateOp, 5, 5, "column"},
2733     {"anchor", 2, (Blt_Op)ResizeAnchorOp, 5, 5, "x"},
2734     {"mark", 1, (Blt_Op)ResizeMarkOp, 5, 5, "x"},
2735     {"set", 1, (Blt_Op)ResizeSetOp, 4, 4, "",},
2736 };
2737 
2738 static int nResizeOps = sizeof(resizeOps) / sizeof(Blt_OpSpec);
2739 
2740 /*
2741  *----------------------------------------------------------------------
2742  *
2743  * ColumnResizeOp --
2744  *
2745  *----------------------------------------------------------------------
2746  */
2747 static int
ColumnResizeOp(tvPtr,interp,objc,objv)2748 ColumnResizeOp(tvPtr, interp, objc, objv)
2749     TreeView *tvPtr;
2750     Tcl_Interp *interp;
2751     int objc;
2752     Tcl_Obj *CONST *objv;
2753 {
2754     Blt_Op proc;
2755     int result;
2756 
2757     proc = Blt_GetOpFromObj(interp, nResizeOps, resizeOps, BLT_OP_ARG3,
2758 	objc, objv,0);
2759     if (proc == NULL) {
2760 	return TCL_ERROR;
2761     }
2762     result = (*proc) (tvPtr, interp, objc, objv);
2763     return result;
2764 }
2765 
2766 
2767 static Blt_OpSpec columnOps[] =
2768 {
2769     {"activate", 1, (Blt_Op)ColumnActivateOp, 3, 4, "?field?",},
2770     {"bbox", 2, (Blt_Op)ColumnBboxOp, 5, 6, "?-visible? field entry",},
2771     {"bind", 2, (Blt_Op)ColumnBindOp, 4, 6, "tagName ?sequence command?",},
2772     {"cget", 2, (Blt_Op)ColumnCgetOp, 5, 5, "field option",},
2773     {"configure", 2, (Blt_Op)ColumnConfigureOp, 4, 0,
2774 	"field ?option value?...",},
2775     {"current", 2, (Blt_Op)ColumnCurrentOp, 3, 3, "",},
2776     {"delete", 1, (Blt_Op)ColumnDeleteOp, 3, 0, "?field...?",},
2777     {"index", 3, (Blt_Op)ColumnIndexOp, 4, 4, "field", },
2778     {"insert", 3, (Blt_Op)ColumnInsertOp, 5, 0,
2779 	"position field ?field...? ?option value?...",},
2780     {"invoke", 3, (Blt_Op)ColumnInvokeOp, 4, 4, "field",},
2781     {"isset", 3, (Blt_Op)ColumnIssetOp, 3, 5, "?startOrTag? ?end?", },
2782     {"istree", 3, (Blt_Op)ColumnIstreeOp, 4, 4, "field", },
2783     {"move", 1, (Blt_Op)ColumnMoveOp, 5, 5, "src dest",},
2784     {"names", 2, (Blt_Op)ColumnNamesOp, 3, 5, "?-visible? ?PATTERN?",},
2785     {"nearest", 2, (Blt_Op)ColumnNearestOp, 4, 5, "x ?y?",},
2786     {"offsets", 2, (Blt_Op)ColumnOffsetsOp, 3, 4, "?-visible?",},
2787     {"resize", 1, (Blt_Op)ColumnResizeOp, 3, 0, "arg ...",},
2788     {"see", 1, (Blt_Op)ColumnSeeOp, 4, 6, "field ?-anchor pos?",},
2789     {"values", 1, (Blt_Op)ColumnValuesOp, 4, 9, "?-visible? ?-default value? field ?startOrTag? ?end?",},
2790     };
2791 static int nColumnOps = sizeof(columnOps) / sizeof(Blt_OpSpec);
2792 
2793 /*
2794  *----------------------------------------------------------------------
2795  *
2796  * Blt_TreeViewColumnOp --
2797  *
2798  *----------------------------------------------------------------------
2799  */
2800 int
Blt_TreeViewColumnOp(tvPtr,interp,objc,objv)2801 Blt_TreeViewColumnOp(tvPtr, interp, objc, objv)
2802     TreeView *tvPtr;
2803     Tcl_Interp *interp;
2804     int objc;
2805     Tcl_Obj *CONST *objv;
2806 {
2807     Blt_Op proc;
2808     int result;
2809 
2810     proc = Blt_GetOpFromObj(interp, nColumnOps, columnOps, BLT_OP_ARG2,
2811 	objc, objv,0);
2812     if (proc == NULL) {
2813 	return TCL_ERROR;
2814     }
2815     result = (*proc) (tvPtr, interp, objc, objv);
2816     return result;
2817 }
2818 
2819 
2820 static int
InvokeCompare(tvPtr,e1Ptr,e2Ptr,command)2821 InvokeCompare(tvPtr, e1Ptr, e2Ptr, command)
2822     TreeView *tvPtr;
2823     TreeViewEntry *e1Ptr, *e2Ptr;
2824     char *command;
2825 {
2826     int result;
2827     Tcl_Obj *objv[8];
2828     int i;
2829 
2830     objv[0] = Tcl_NewStringObj(command, -1);
2831     objv[1] = Tcl_NewStringObj(Tk_PathName(tvPtr->tkwin), -1);
2832     objv[2] = Tcl_NewIntObj(Blt_TreeNodeId(e1Ptr->node));
2833     objv[3] = Tcl_NewIntObj(Blt_TreeNodeId(e2Ptr->node));
2834     objv[4] = Tcl_NewStringObj(tvPtr->sortColumnPtr->key, -1);
2835 
2836     if (tvPtr->flatView) {
2837 	objv[5] = Tcl_NewStringObj(e1Ptr->fullName, -1);
2838 	objv[6] = Tcl_NewStringObj(e2Ptr->fullName, -1);
2839     } else {
2840 	objv[5] = Tcl_NewStringObj(GETLABEL(e1Ptr), -1);
2841 	objv[6] = Tcl_NewStringObj(GETLABEL(e2Ptr), -1);
2842     }
2843     for(i = 0; i < 7; i++) {
2844 	Tcl_IncrRefCount(objv[i]);
2845     }
2846     objv[7] = NULL;
2847     result = Tcl_EvalObjv(tvPtr->interp, 7, objv, TCL_EVAL_GLOBAL);
2848     if ((result != TCL_OK) ||
2849 	(Tcl_GetIntFromObj(tvPtr->interp, Tcl_GetObjResult(tvPtr->interp),
2850 			   &result) != TCL_OK)) {
2851 	Tcl_BackgroundError(tvPtr->interp);
2852     }
2853     for(i = 0; i < 7; i++) {
2854 	Tcl_DecrRefCount(objv[i]);
2855     }
2856     Tcl_ResetResult(tvPtr->interp);
2857     return result;
2858 }
2859 
2860 static TreeView *treeViewInstance;
2861 
2862 static int
CompareEntry(CONST void * a,CONST void * b,Tcl_Obj * colName)2863 CompareEntry( CONST void *a, CONST void *b, Tcl_Obj *colName)
2864 {
2865     TreeView *tvPtr;
2866     TreeViewColumn *columnPtr;
2867     TreeViewEntry *e1Ptr, **e1PtrPtr = (TreeViewEntry **)a;
2868     TreeViewEntry *e2Ptr, **e2PtrPtr = (TreeViewEntry **)b;
2869     Tcl_Obj *obj1, *obj2;
2870     char *s1, *s2;
2871     int result, sType;
2872 
2873     tvPtr = (*e1PtrPtr)->tvPtr;
2874     columnPtr = tvPtr->sortColumnPtr;
2875     sType = tvPtr->sortType;
2876 
2877     obj1 = (*e1PtrPtr)->dataObjPtr;
2878     obj2 = (*e2PtrPtr)->dataObjPtr;
2879     if (colName != NULL) {
2880         if (Blt_TreeViewGetColumn(NULL, tvPtr, colName, &columnPtr)
2881             != TCL_OK) {
2882             return 1;
2883         }
2884         e1Ptr = *e1PtrPtr;
2885         e2Ptr = *e2PtrPtr;
2886         if (Blt_TreeGetValueByKey(tvPtr->interp, tvPtr->tree,
2887             e1Ptr->node, columnPtr->key, &obj1) != TCL_OK) {
2888             return 1;
2889         }
2890         if (Blt_TreeGetValueByKey(tvPtr->interp, tvPtr->tree,
2891             e2Ptr->node, columnPtr->key, &obj2) != TCL_OK) {
2892                 return 1;
2893         }
2894         sType = columnPtr->sortType;
2895     }
2896     s1 = Tcl_GetString(obj1);
2897     s2 = Tcl_GetString(obj2);
2898     result = 0;
2899     switch (sType) {
2900     case SORT_TYPE_ASCII:
2901 	result = strcmp(s1, s2);
2902 	break;
2903 
2904     case SORT_TYPE_COMMAND:
2905 	{
2906 	    char *cmd;
2907 
2908 	    cmd = columnPtr->sortCmd;
2909 	    if (cmd == NULL) {
2910 		cmd = tvPtr->sortCmd;
2911 	    }
2912 	    if (cmd == NULL) {
2913 		result = Blt_DictionaryCompare(s1, s2);
2914 	    } else {
2915 		result = InvokeCompare(tvPtr, *e1PtrPtr, *e2PtrPtr, cmd);
2916 	    }
2917 	}
2918 	break;
2919 
2920     case SORT_TYPE_DICTIONARY:
2921 	result = Blt_DictionaryCompare(s1, s2);
2922 	break;
2923 
2924     case SORT_TYPE_INTEGER:
2925 	{
2926 	    int i1, i2;
2927 
2928 	    if (Tcl_GetIntFromObj(NULL, obj1, &i1)==TCL_OK) {
2929 		if (Tcl_GetIntFromObj(NULL, obj2, &i2) == TCL_OK) {
2930 		    result = i1 - i2;
2931 		} else {
2932 		    result = -1;
2933 		}
2934 	    } else if (Tcl_GetIntFromObj(NULL, obj2, &i2) == TCL_OK) {
2935 		result = 1;
2936 	    } else {
2937 		result = Blt_DictionaryCompare(s1, s2);
2938 	    }
2939 	}
2940 	break;
2941 
2942     case SORT_TYPE_REAL:
2943 	{
2944 	    double r1, r2;
2945 
2946 	    if (Tcl_GetDoubleFromObj(NULL, obj1, &r1) == TCL_OK) {
2947 		if (Tcl_GetDoubleFromObj(NULL, obj2, &r2) == TCL_OK) {
2948 		    result = (r1 < r2) ? -1 : (r1 > r2) ? 1 : 0;
2949 		} else {
2950 		    result = -1;
2951 		}
2952 	    } else if (Tcl_GetDoubleFromObj(NULL, obj2, &r2) == TCL_OK) {
2953 		result = 1;
2954 	    } else {
2955 		result = Blt_DictionaryCompare(s1, s2);
2956 	    }
2957 	}
2958 	break;
2959     }
2960     if (tvPtr->sortDecreasing) {
2961 	return -result;
2962     }
2963     return result;
2964 }
2965 
2966 static int
CompareEntries(a,b)2967 CompareEntries(a, b)
2968     CONST void *a, *b;
2969 {
2970     TreeView *tvPtr;
2971     int result, i;
2972     TreeViewEntry **e1PtrPtr = (TreeViewEntry **)a;
2973     int objc;
2974     Tcl_Obj **objv;
2975 
2976     result = CompareEntry(a, b, NULL);
2977 
2978     tvPtr = (*e1PtrPtr)->tvPtr;
2979     if (result != 0) { return result; }
2980     if (result != 0 || tvPtr->sortColumnPtr == NULL) return result;
2981     if (tvPtr->sortColumnPtr->sortAltColumns == NULL) return result;
2982 
2983     if (Tcl_ListObjGetElements(NULL, tvPtr->sortColumnPtr->sortAltColumns,
2984         &objc, &objv) != TCL_OK) {
2985             return result;
2986     }
2987     for (i = 0; i < objc && result == 0; i++) {
2988         result = CompareEntry(a, b, objv[i]);
2989     }
2990 
2991     return result;
2992 }
2993 
2994 /*
2995  *----------------------------------------------------------------------
2996  *
2997  * CompareNodes --
2998  *
2999  *	Comparison routine (used by qsort) to sort a chain of subnodes.
3000  *
3001  * Results:
3002  *	1 is the first is greater, -1 is the second is greater, 0
3003  *	if equal.
3004  *
3005  *----------------------------------------------------------------------
3006  */
3007 static int
CompareNodes(Blt_TreeNode * n1Ptr,Blt_TreeNode * n2Ptr)3008 CompareNodes( Blt_TreeNode *n1Ptr, Blt_TreeNode *n2Ptr )
3009 {
3010     TreeView *tvPtr = treeViewInstance;
3011     TreeViewEntry *e1Ptr, *e2Ptr;
3012 
3013     e1Ptr = Blt_NodeToEntry(tvPtr, *n1Ptr);
3014     e2Ptr = Blt_NodeToEntry(tvPtr, *n2Ptr);
3015 
3016     TreeViewColumn *columnPtr = tvPtr->sortColumnPtr;
3017 
3018     /* Fetch the data for sorting. */
3019     if (tvPtr->sortType == SORT_TYPE_COMMAND) {
3020 	e1Ptr->dataObjPtr = Tcl_NewIntObj(Blt_TreeNodeId(*n1Ptr));
3021 	e2Ptr->dataObjPtr = Tcl_NewIntObj(Blt_TreeNodeId(*n2Ptr));
3022     } else if (columnPtr == &tvPtr->treeColumn) {
3023 	Tcl_DString dString;
3024 
3025 	Tcl_DStringInit(&dString);
3026 	if (e1Ptr->fullName == NULL) {
3027 	    Blt_TreeViewGetFullName(tvPtr, e1Ptr, TRUE, &dString);
3028 	    e1Ptr->fullName = Blt_Strdup(Tcl_DStringValue(&dString));
3029 	}
3030 	e1Ptr->dataObjPtr = Tcl_NewStringObj(e1Ptr->fullName, -1);
3031 	if (e2Ptr->fullName == NULL) {
3032 	    Blt_TreeViewGetFullName(tvPtr, e2Ptr, TRUE, &dString);
3033 	    e2Ptr->fullName = Blt_Strdup(Tcl_DStringValue(&dString));
3034 	}
3035 	e2Ptr->dataObjPtr = Tcl_NewStringObj(e2Ptr->fullName, -1);
3036 	Tcl_DStringFree(&dString);
3037     } else {
3038 	Blt_TreeKey key;
3039 	Tcl_Obj *objPtr;
3040 
3041 	key = columnPtr->key;
3042 	if (Blt_TreeViewGetData(e1Ptr, key, &objPtr) != TCL_OK) {
3043 	    e1Ptr->dataObjPtr = Tcl_NewStringObj("",-1);
3044 	} else {
3045 	    e1Ptr->dataObjPtr = objPtr;
3046 	}
3047 	if (Blt_TreeViewGetData(e2Ptr, key, &objPtr) != TCL_OK) {
3048             e2Ptr->dataObjPtr = Tcl_NewStringObj("",-1);
3049 	} else {
3050 	    e2Ptr->dataObjPtr = objPtr;
3051 	}
3052     }
3053     return CompareEntries(&e1Ptr, &e2Ptr);
3054 }
3055 
3056 static int
SortAutoOp(tvPtr,interp,objc,objv)3057 SortAutoOp(tvPtr, interp, objc, objv)
3058     TreeView *tvPtr;
3059     Tcl_Interp *interp;		/* Not used. */
3060     int objc;
3061     Tcl_Obj *CONST *objv;
3062 {
3063 
3064     if (objc == 4) {
3065 	int bool;
3066 	int isAuto;
3067 
3068 	isAuto = ((tvPtr->flags & TV_SORT_AUTO) != 0);
3069 	if (Tcl_GetBooleanFromObj(interp, objv[3], &bool) != TCL_OK) {
3070 	    return TCL_ERROR;
3071 	}
3072 	if (isAuto != bool) {
3073 	    tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
3074 	    Blt_TreeViewEventuallyRedraw(tvPtr);
3075 	}
3076 	if (bool) {
3077 	    tvPtr->flags |= TV_SORT_AUTO;
3078 	} else {
3079 	    tvPtr->flags &= ~TV_SORT_AUTO;
3080 	}
3081     }
3082     Tcl_SetObjResult(interp, Tcl_NewBooleanObj(tvPtr->flags & TV_SORT_AUTO));
3083     return TCL_OK;
3084 }
3085 
3086 /*
3087  *----------------------------------------------------------------------
3088  *
3089  * SortCgetOp --
3090  *
3091  *----------------------------------------------------------------------
3092  */
3093 /*ARGSUSED*/
3094 static int
SortCgetOp(tvPtr,interp,objc,objv)3095 SortCgetOp(tvPtr, interp, objc, objv)
3096     TreeView *tvPtr;
3097     Tcl_Interp *interp;
3098     int objc;			/* Not used. */
3099     Tcl_Obj *CONST *objv;
3100 {
3101     Blt_TreeViewOptsInit(tvPtr);
3102     return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, sortSpecs,
3103 	(char *)tvPtr, objv[3], 0);
3104 }
3105 
3106 /*
3107  *----------------------------------------------------------------------
3108  *
3109  * SortConfigureOp --
3110  *
3111  * 	This procedure is called to process a list of configuration
3112  *	options database, in order to reconfigure the one of more
3113  *	entries in the widget.
3114  *
3115  *	  .h sort configure option value
3116  *
3117  * Results:
3118  *	A standard Tcl result.  If TCL_ERROR is returned, then
3119  *	interp->result contains an error message.
3120  *
3121  * Side effects:
3122  *	Configuration information, such as text string, colors, font,
3123  *	etc. get set for tvPtr; old resources get freed, if there
3124  *	were any.  The hypertext is redisplayed.
3125  *
3126  *----------------------------------------------------------------------
3127  */
3128 static int
SortConfigureOp(tvPtr,interp,objc,objv)3129 SortConfigureOp(tvPtr, interp, objc, objv)
3130     TreeView *tvPtr;
3131     Tcl_Interp *interp;
3132     int objc;
3133     Tcl_Obj *CONST *objv;
3134 {
3135     int oldType;
3136     char *oldCommand;
3137     TreeViewColumn *oldColumn;
3138 
3139     Blt_TreeViewOptsInit(tvPtr);
3140     if (objc == 3) {
3141 	return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, sortSpecs,
3142 		(char *)tvPtr, (Tcl_Obj *)NULL, 0);
3143     } else if (objc == 4) {
3144 	return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, sortSpecs,
3145 		(char *)tvPtr, objv[3], 0);
3146     }
3147     oldColumn = tvPtr->sortColumnPtr;
3148     oldType = tvPtr->sortType;
3149     oldCommand = tvPtr->sortCmd;
3150     if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, sortSpecs,
3151 	objc - 3, objv + 3, (char *)tvPtr, BLT_CONFIG_OBJV_ONLY, NULL) != TCL_OK) {
3152 	return TCL_ERROR;
3153     }
3154     if ((oldColumn != tvPtr->sortColumnPtr) ||
3155 	(oldType != tvPtr->sortType) ||
3156 	(oldCommand != tvPtr->sortCmd)) {
3157 	tvPtr->flags &= ~TV_SORTED;
3158 	tvPtr->flags |= (TV_DIRTY | TV_RESORT);
3159     }
3160     if (tvPtr->flags & TV_SORT_AUTO) {
3161 	tvPtr->flags |= TV_SORT_PENDING;
3162     }
3163     Blt_TreeViewEventuallyRedraw(tvPtr);
3164     return TCL_OK;
3165 }
3166 
3167 /*ARGSUSED*/
3168 static int
SortOnceOp(tvPtr,interp,objc,objv)3169 SortOnceOp(tvPtr, interp, objc, objv)
3170     TreeView *tvPtr;
3171     Tcl_Interp *interp;		/* Not used. */
3172     int objc;
3173     Tcl_Obj *CONST *objv;
3174 {
3175     TreeViewEntry *entryPtr;
3176     int recurse, result;
3177     register int i;
3178 
3179     recurse = FALSE;
3180     if (objc > 3) {
3181 	char *string;
3182 	int length;
3183 
3184 	string = Tcl_GetStringFromObj(objv[3], &length);
3185 	if ((string[0] == '-') && (length > 1) &&
3186 	    (strncmp(string, "-recurse", length) == 0)) {
3187 	    objv++, objc--;
3188 	    recurse = TRUE;
3189 	}
3190     }
3191     if (tvPtr->sortColumnPtr == NULL) {
3192         Tcl_AppendResult(interp, "must select column to sort by", 0);
3193         return TCL_ERROR;
3194     }
3195     for (i = 3; i < objc; i++) {
3196 	if (Blt_TreeViewGetEntry(tvPtr, objv[i], &entryPtr) != TCL_OK) {
3197 	    return TCL_ERROR;
3198 	}
3199 	if (recurse) {
3200 	    result = Blt_TreeApply(entryPtr->node, SortApplyProc, tvPtr);
3201 	} else {
3202 	    result = SortApplyProc(entryPtr->node, tvPtr, TREE_PREORDER);
3203 	}
3204 	if (result != TCL_OK) {
3205 	    return TCL_ERROR;
3206 	}
3207     }
3208     tvPtr->flags |= TV_LAYOUT;
3209     Blt_TreeViewEventuallyRedraw(tvPtr);
3210     return TCL_OK;
3211 }
3212 
3213 /*
3214  *----------------------------------------------------------------------
3215  *
3216  * Blt_TreeViewSortOp --
3217  *
3218  *	Comparison routine (used by qsort) to sort a chain of subnodes.
3219  *	A simple string comparison is performed on each node name.
3220  *
3221  *	.h sort auto
3222  *	.h sort once -recurse root
3223  *
3224  * Results:
3225  *	1 is the first is greater, -1 is the second is greater, 0
3226  *	if equal.
3227  *
3228  *----------------------------------------------------------------------
3229  */
3230 static Blt_OpSpec sortOps[] =
3231 {
3232     {"auto", 1, (Blt_Op)SortAutoOp, 3, 4, "?boolean?",},
3233     {"cget", 2, (Blt_Op)SortCgetOp, 4, 4, "option",},
3234     {"configure", 2, (Blt_Op)SortConfigureOp, 3, 0, "?option value?...",},
3235     {"once", 1, (Blt_Op)SortOnceOp, 3, 0, "?-recurse? node...",},
3236 };
3237 static int nSortOps = sizeof(sortOps) / sizeof(Blt_OpSpec);
3238 
3239 /*ARGSUSED*/
3240 int
Blt_TreeViewSortOp(tvPtr,interp,objc,objv)3241 Blt_TreeViewSortOp(tvPtr, interp, objc, objv)
3242     TreeView *tvPtr;
3243     Tcl_Interp *interp;		/* Not used. */
3244     int objc;
3245     Tcl_Obj *CONST *objv;
3246 {
3247     Blt_Op proc;
3248     int result;
3249 
3250     proc = Blt_GetOpFromObj(interp, nSortOps, sortOps, BLT_OP_ARG2, objc,
3251 	    objv, 0);
3252     if (proc == NULL) {
3253 	return TCL_ERROR;
3254     }
3255     result = (*proc) (tvPtr, interp, objc, objv);
3256     return result;
3257 }
3258 
3259 /*
3260  *----------------------------------------------------------------------
3261  *
3262  * SortApplyProc --
3263  *
3264  *	Sorts the subnodes at a given node.
3265  *
3266  * Results:
3267  *	Always returns TCL_OK.
3268  *
3269  *----------------------------------------------------------------------
3270  */
3271 /*ARGSUSED*/
3272 static int
SortApplyProc(node,clientData,order)3273 SortApplyProc(node, clientData, order)
3274     Blt_TreeNode node;
3275     ClientData clientData;
3276     int order;			/* Not used. */
3277 {
3278     TreeView *tvPtr = clientData;
3279 
3280     if (!Blt_TreeIsLeaf(node)) {
3281         treeViewInstance = tvPtr;
3282         Blt_TreeSortNode(tvPtr->tree, node, CompareNodes);
3283     }
3284     return TCL_OK;
3285 }
3286 
3287 /*
3288  *----------------------------------------------------------------------
3289  *
3290  * Blt_TreeViewSortFlatView --
3291  *
3292  *	Sorts the flatten array of entries.
3293  *
3294  *----------------------------------------------------------------------
3295  */
3296 void
Blt_TreeViewSortFlatView(tvPtr)3297 Blt_TreeViewSortFlatView(tvPtr)
3298     TreeView *tvPtr;
3299 {
3300     TreeViewEntry *entryPtr, **p;
3301 
3302     tvPtr->flags &= ~TV_SORT_PENDING;
3303     if ((tvPtr->sortType == SORT_TYPE_NONE) || (tvPtr->sortColumnPtr == NULL) ||
3304 	(tvPtr->nEntries == 1)) {
3305 	return;
3306     }
3307     if (tvPtr->flags & TV_SORTED) {
3308 	int first, last;
3309 	TreeViewEntry *hold;
3310 
3311 	if (tvPtr->sortDecreasing == tvPtr->viewIsDecreasing) {
3312 	    return;
3313 	}
3314 
3315 	/*
3316 	 * The view is already sorted but in the wrong direction.
3317 	 * Reverse the entries in the array.
3318 	 */
3319  	for (first = 0, last = tvPtr->nEntries - 1; last > first;
3320 	     first++, last--) {
3321 	    hold = tvPtr->flatArr[first];
3322 	    tvPtr->flatArr[first] = tvPtr->flatArr[last];
3323 	    tvPtr->flatArr[last] = hold;
3324 	}
3325 	tvPtr->viewIsDecreasing = tvPtr->sortDecreasing;
3326 	tvPtr->flags |= TV_SORTED | TV_LAYOUT;
3327 	return;
3328     }
3329     /* Fetch each entry's data as Tcl_Objs for sorting. */
3330     if (tvPtr->sortColumnPtr == &tvPtr->treeColumn) {
3331 	for(p = tvPtr->flatArr; *p != NULL; p++) {
3332 	    entryPtr = *p;
3333 	    if (entryPtr->fullName == NULL) {
3334 		Tcl_DString dString;
3335 
3336 		Tcl_DStringInit(&dString);
3337 		Blt_TreeViewGetFullName(tvPtr, entryPtr, TRUE, &dString);
3338 		entryPtr->fullName = Blt_Strdup(Tcl_DStringValue(&dString));
3339 		Tcl_DStringFree(&dString);
3340 	    }
3341 	    entryPtr->dataObjPtr = Tcl_NewStringObj(entryPtr->fullName, -1);
3342 	    Tcl_IncrRefCount(entryPtr->dataObjPtr);
3343 	}
3344     } else {
3345 	Blt_TreeKey key;
3346 	Tcl_Obj *objPtr;
3347 	int isFmt;
3348 
3349 	key = tvPtr->sortColumnPtr->key;
3350 	isFmt = Blt_TreeViewStyleIsFmt(tvPtr, tvPtr->sortColumnPtr->stylePtr);
3351         for(p = tvPtr->flatArr; *p != NULL; p++) {
3352             TreeViewValue *valuePtr;
3353             TreeViewColumn *columnPtr = tvPtr->sortColumnPtr;
3354 
3355 	    entryPtr = *p;
3356 	   /* if (Blt_TreeViewGetData(entryPtr, key, &objPtr) != TCL_OK) {
3357                 objPtr =  Tcl_NewStringObj("",-1);
3358 	    }*/
3359              if (isFmt &&
3360                 ((valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr))) &&
3361                 valuePtr->textPtr) {
3362                  Tcl_DString dStr;
3363                  Tcl_DStringInit(&dStr);
3364                  Blt_TextLayoutValue( valuePtr->textPtr, &dStr);
3365                  objPtr = Tcl_NewStringObj( Tcl_DStringValue(&dStr), -1);
3366                  Tcl_DStringFree(&dStr);
3367              } else if (Blt_TreeGetValueByKey(tvPtr->interp, tvPtr->tree,
3368                 entryPtr->node, columnPtr->key, &objPtr) != TCL_OK) {
3369                      objPtr = Tcl_NewStringObj("",0);
3370              }
3371 
3372 	    entryPtr->dataObjPtr = objPtr;
3373 	    Tcl_IncrRefCount(entryPtr->dataObjPtr);
3374 	}
3375     }
3376     qsort((char *)tvPtr->flatArr, tvPtr->nEntries, sizeof(TreeViewEntry *),
3377 	  (QSortCompareProc *)CompareEntries);
3378 
3379     /* Free all the Tcl_Objs used for comparison data. */
3380     for(p = tvPtr->flatArr; *p != NULL; p++) {
3381 	Tcl_DecrRefCount((*p)->dataObjPtr);
3382          (*p)->dataObjPtr = NULL;
3383     }
3384     tvPtr->viewIsDecreasing = tvPtr->sortDecreasing;
3385     tvPtr->flags |= TV_SORTED;
3386 }
3387 
3388 /*
3389  *----------------------------------------------------------------------
3390  *
3391  * Blt_TreeViewSortTreeView --
3392  *
3393  *	Sorts the tree array of entries.
3394  *
3395  *----------------------------------------------------------------------
3396  */
3397 void
Blt_TreeViewSortTreeView(tvPtr)3398 Blt_TreeViewSortTreeView(tvPtr)
3399     TreeView *tvPtr;
3400 {
3401     tvPtr->flags &= ~TV_SORT_PENDING;
3402     if ((tvPtr->sortType != SORT_TYPE_NONE) && (tvPtr->sortColumnPtr != NULL)) {
3403 	treeViewInstance = tvPtr;
3404 	Blt_TreeApply(tvPtr->rootPtr->node, SortApplyProc, tvPtr);
3405     }
3406     tvPtr->viewIsDecreasing = tvPtr->sortDecreasing;
3407 }
3408 
3409 
3410 #endif /* NO_TREEVIEW */
3411