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, ®ColorOption},
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