source: trunk/kitgen/8.x/blt/generic/bltTreeViewColumn.c@ 201

Last change on this file since 201 was 175, checked in by demin, 12 years ago

initial commit

File size: 56.0 KB
Line 
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 */
29
30/*
31 * TODO:
32 *
33 * BUGS:
34 * 1. "open" operation should change scroll offset so that as many
35 * new entries (up to half a screen) can be seen.
36 * 2. "open" needs to adjust the scrolloffset so that the same entry
37 * is seen at the same place.
38 */
39#include "bltInt.h"
40
41#ifndef NO_TREEVIEW
42
43#include "bltTreeView.h"
44#include <X11/Xutil.h>
45
46#define RULE_AREA (8)
47
48static Blt_OptionParseProc ObjToColumn;
49static Blt_OptionPrintProc ColumnToObj;
50static Blt_OptionParseProc ObjToData;
51static Blt_OptionPrintProc DataToObj;
52
53static char *sortTypeStrings[] = {
54 "dictionary", "ascii", "integer", "real", "command", "none", NULL
55};
56
57enum SortTypeValues {
58 SORT_TYPE_DICTIONARY, SORT_TYPE_ASCII, SORT_TYPE_INTEGER,
59 SORT_TYPE_REAL, SORT_TYPE_COMMAND, SORT_TYPE_NONE
60};
61
62#define DEF_SORT_COLUMN (char *)NULL
63#define DEF_SORT_COMMAND (char *)NULL
64#define DEF_SORT_DECREASING "no"
65#define DEF_SORT_TYPE "dictionary"
66
67#ifdef WIN32
68#define DEF_COLUMN_ACTIVE_TITLE_BG RGB_GREY85
69#else
70#define DEF_COLUMN_ACTIVE_TITLE_BG RGB_GREY90
71#endif
72#define DEF_COLUMN_ACTIVE_TITLE_FG STD_ACTIVE_FOREGROUND
73#define DEF_COLUMN_BACKGROUND (char *)NULL
74#define DEF_COLUMN_BIND_TAGS "all"
75#define DEF_COLUMN_BORDERWIDTH STD_BORDERWIDTH
76#define DEF_COLUMN_COLOR RGB_BLACK
77#define DEF_COLUMN_EDIT "yes"
78#define DEF_COLUMN_FONT STD_FONT
79#define DEF_COLUMN_COMMAND (char *)NULL
80#define DEF_COLUMN_FORMAT_COMMAND (char *)NULL
81#define DEF_COLUMN_HIDE "no"
82#define DEF_COLUMN_JUSTIFY "center"
83#define DEF_COLUMN_MAX "0"
84#define DEF_COLUMN_MIN "0"
85#define DEF_COLUMN_PAD "2"
86#define DEF_COLUMN_RELIEF "flat"
87#define DEF_COLUMN_STATE "normal"
88#define DEF_COLUMN_STYLE "text"
89#define DEF_COLUMN_TITLE_BACKGROUND STD_NORMAL_BACKGROUND
90#define DEF_COLUMN_TITLE_BORDERWIDTH STD_BORDERWIDTH
91#define DEF_COLUMN_TITLE_FONT STD_FONT
92#define DEF_COLUMN_TITLE_FOREGROUND STD_NORMAL_FOREGROUND
93#define DEF_COLUMN_TITLE_RELIEF "raised"
94#define DEF_COLUMN_WEIGHT "1.0"
95#define DEF_COLUMN_WIDTH "0"
96#define DEF_COLUMN_RULE_DASHES "dot"
97
98extern Blt_OptionParseProc Blt_ObjToEnum;
99extern Blt_OptionPrintProc Blt_EnumToObj;
100
101static Blt_CustomOption typeOption =
102{
103 Blt_ObjToEnum, Blt_EnumToObj, NULL, (ClientData)sortTypeStrings
104};
105
106static Blt_CustomOption columnOption =
107{
108 ObjToColumn, ColumnToObj, NULL, (ClientData)0
109};
110
111Blt_CustomOption bltTreeViewDataOption =
112{
113 ObjToData, DataToObj, NULL, (ClientData)0,
114};
115
116static Blt_OptionParseProc ObjToStyle;
117static Blt_OptionPrintProc StyleToObj;
118static Blt_OptionFreeProc FreeStyle;
119static Blt_CustomOption styleOption =
120{
121 /* Contains a pointer to the widget that's currently being
122 * configured. This is used in the custom configuration parse
123 * routine for icons. */
124 ObjToStyle, StyleToObj, FreeStyle, NULL,
125};
126
127extern Blt_CustomOption bltTreeViewUidOption;
128extern Blt_CustomOption bltTreeViewIconOption;
129static Blt_TreeApplyProc SortApplyProc;
130
131static Blt_ConfigSpec columnSpecs[] =
132{
133 {BLT_CONFIG_BORDER, "-activetitlebackground", "activeTitleBackground",
134 "Background", DEF_COLUMN_ACTIVE_TITLE_BG,
135 Blt_Offset(TreeViewColumn, activeTitleBorder), 0},
136 {BLT_CONFIG_COLOR, "-activetitleforeground", "activeTitleForeground",
137 "Foreground", DEF_COLUMN_ACTIVE_TITLE_FG,
138 Blt_Offset(TreeViewColumn, activeTitleFgColor), 0},
139 {BLT_CONFIG_BORDER, "-background", "background", "Background",
140 DEF_COLUMN_BACKGROUND, Blt_Offset(TreeViewColumn, border),
141 BLT_CONFIG_NULL_OK},
142 {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL,
143 0, 0},
144 {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL,
145 0, 0},
146 {BLT_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
147 DEF_COLUMN_BIND_TAGS, Blt_Offset(TreeViewColumn, tagsUid),
148 BLT_CONFIG_NULL_OK, &bltTreeViewUidOption},
149 {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth",
150 DEF_COLUMN_BORDERWIDTH, Blt_Offset(TreeViewColumn, borderWidth),
151 BLT_CONFIG_DONT_SET_DEFAULT},
152 {BLT_CONFIG_STRING, "-command", "command", "Command",
153 DEF_COLUMN_COMMAND, Blt_Offset(TreeViewColumn, titleCmd),
154 BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK},
155 {BLT_CONFIG_BOOLEAN, "-edit", "edit", "Edit",
156 DEF_COLUMN_STATE, Blt_Offset(TreeViewColumn, editable),
157 BLT_CONFIG_DONT_SET_DEFAULT},
158 {BLT_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
159 DEF_COLUMN_HIDE, Blt_Offset(TreeViewColumn, hidden),
160 BLT_CONFIG_DONT_SET_DEFAULT},
161 {BLT_CONFIG_CUSTOM, "-icon", "icon", "icon",
162 (char *)NULL, Blt_Offset(TreeViewColumn, titleIcon),
163 BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewIconOption},
164 {BLT_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
165 DEF_COLUMN_JUSTIFY, Blt_Offset(TreeViewColumn, justify),
166 BLT_CONFIG_DONT_SET_DEFAULT},
167 {BLT_CONFIG_DISTANCE, "-max", "max", "Max",
168 DEF_COLUMN_MAX, Blt_Offset(TreeViewColumn, reqMax),
169 BLT_CONFIG_DONT_SET_DEFAULT},
170 {BLT_CONFIG_DISTANCE, "-min", "min", "Min",
171 DEF_COLUMN_MIN, Blt_Offset(TreeViewColumn, reqMin),
172 BLT_CONFIG_DONT_SET_DEFAULT},
173 {BLT_CONFIG_PAD, "-pad", "pad", "Pad",
174 DEF_COLUMN_PAD, Blt_Offset(TreeViewColumn, pad),
175 BLT_CONFIG_DONT_SET_DEFAULT},
176 {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief",
177 DEF_COLUMN_RELIEF, Blt_Offset(TreeViewColumn, relief),
178 BLT_CONFIG_DONT_SET_DEFAULT},
179 {BLT_CONFIG_DASHES, "-ruledashes", "ruleDashes", "RuleDashes",
180 DEF_COLUMN_RULE_DASHES, Blt_Offset(TreeViewColumn, ruleDashes),
181 BLT_CONFIG_NULL_OK},
182 {BLT_CONFIG_STRING, "-sortcommand", "sortCommand", "SortCommand",
183 DEF_SORT_COMMAND, Blt_Offset(TreeViewColumn, sortCmd),
184 BLT_CONFIG_NULL_OK},
185 {BLT_CONFIG_STATE, "-state", "state", "State",
186 DEF_COLUMN_STATE, Blt_Offset(TreeViewColumn, state),
187 BLT_CONFIG_DONT_SET_DEFAULT},
188 {BLT_CONFIG_CUSTOM, "-style", "style", "Style",
189 DEF_COLUMN_STYLE, Blt_Offset(TreeViewColumn, stylePtr),
190 0, &styleOption},
191 {BLT_CONFIG_STRING, "-text", "text", "Text",
192 (char *)NULL, Blt_Offset(TreeViewColumn, title), 0},
193 {BLT_CONFIG_STRING, "-title", "title", "Title",
194 (char *)NULL, Blt_Offset(TreeViewColumn, title), 0},
195 {BLT_CONFIG_BORDER, "-titlebackground", "titleBackground",
196 "TitleBackground", DEF_COLUMN_TITLE_BACKGROUND,
197 Blt_Offset(TreeViewColumn, titleBorder),0},
198 {BLT_CONFIG_DISTANCE, "-titleborderwidth", "BorderWidth",
199 "TitleBorderWidth", DEF_COLUMN_TITLE_BORDERWIDTH,
200 Blt_Offset(TreeViewColumn, titleBorderWidth),
201 BLT_CONFIG_DONT_SET_DEFAULT},
202 {BLT_CONFIG_FONT, "-titlefont", "titleFont", "Font",
203 DEF_COLUMN_TITLE_FONT, Blt_Offset(TreeViewColumn, titleFont), 0},
204 {BLT_CONFIG_COLOR, "-titleforeground", "titleForeground", "TitleForeground",
205 DEF_COLUMN_TITLE_FOREGROUND,
206 Blt_Offset(TreeViewColumn, titleFgColor), 0},
207 {BLT_CONFIG_RELIEF, "-titlerelief", "titleRelief", "TitleRelief",
208 DEF_COLUMN_TITLE_RELIEF, Blt_Offset(TreeViewColumn, titleRelief),
209 BLT_CONFIG_DONT_SET_DEFAULT},
210 {BLT_CONFIG_SHADOW, "-titleshadow", "titleShadow", "TitleShadow",
211 (char *)NULL, Blt_Offset(TreeViewColumn, titleShadow), 0},
212 {BLT_CONFIG_DOUBLE, "-weight", (char *)NULL, (char *)NULL,
213 DEF_COLUMN_WEIGHT, Blt_Offset(TreeViewColumn, weight),
214 BLT_CONFIG_DONT_SET_DEFAULT},
215 {BLT_CONFIG_DISTANCE, "-width", "width", "Width",
216 DEF_COLUMN_WIDTH, Blt_Offset(TreeViewColumn, reqWidth),
217 BLT_CONFIG_DONT_SET_DEFAULT},
218 {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
219 (char *)NULL, 0, 0}
220};
221
222static Blt_ConfigSpec sortSpecs[] =
223{
224 {BLT_CONFIG_STRING, "-command", "command", "Command",
225 DEF_SORT_COMMAND, Blt_Offset(TreeView, sortCmd),
226 BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK},
227 {BLT_CONFIG_CUSTOM, "-column", "column", "Column",
228 DEF_SORT_COLUMN, Blt_Offset(TreeView, sortColumnPtr),
229 BLT_CONFIG_DONT_SET_DEFAULT, &columnOption},
230 {BLT_CONFIG_BOOLEAN, "-decreasing", "decreasing", "Decreasing",
231 DEF_SORT_DECREASING, Blt_Offset(TreeView, sortDecreasing),
232 BLT_CONFIG_DONT_SET_DEFAULT},
233 {BLT_CONFIG_CUSTOM, "-mode", "mode", "Mode",
234 DEF_SORT_TYPE, Blt_Offset(TreeView, sortType), 0, &typeOption},
235 {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
236 (char *)NULL, 0, 0}
237};
238
239static Blt_TreeCompareNodesProc CompareNodes;
240static Blt_TreeApplyProc SortApplyProc;
241
242/*
243 *----------------------------------------------------------------------
244 *
245 * ObjToColumn --
246 *
247 * Convert the string reprsenting a scroll mode, to its numeric
248 * form.
249 *
250 * Results:
251 * If the string is successfully converted, TCL_OK is returned.
252 * Otherwise, TCL_ERROR is returned and an error message is left
253 * in interpreter's result field.
254 *
255 *----------------------------------------------------------------------
256 */
257/*ARGSUSED*/
258static int
259ObjToColumn(clientData, interp, tkwin, objPtr, widgRec, offset)
260 ClientData clientData; /* Not used. */
261 Tcl_Interp *interp; /* Interpreter to send results back to */
262 Tk_Window tkwin; /* Not used. */
263 Tcl_Obj *objPtr; /* New legend position string */
264 char *widgRec;
265 int offset;
266{
267 TreeViewColumn **columnPtrPtr = (TreeViewColumn **)(widgRec + offset);
268 char *string;
269
270 string = Tcl_GetString(objPtr);
271 if (*string == '\0') {
272 *columnPtrPtr = NULL;
273 } else {
274 TreeView *tvPtr = (TreeView *)widgRec;
275
276 if (Blt_TreeViewGetColumn(interp, tvPtr, objPtr, columnPtrPtr)
277 != TCL_OK) {
278 return TCL_ERROR;
279 }
280 }
281 return TCL_OK;
282}
283
284/*
285 *----------------------------------------------------------------------
286 *
287 * ColumnToString --
288 *
289 * Results:
290 * The string representation of the button boolean is returned.
291 *
292 *----------------------------------------------------------------------
293 */
294/*ARGSUSED*/
295static Tcl_Obj *
296ColumnToObj(clientData, interp, tkwin, widgRec, offset)
297 ClientData clientData; /* Not used. */
298 Tcl_Interp *interp;
299 Tk_Window tkwin; /* Not used. */
300 char *widgRec;
301 int offset;
302{
303 TreeViewColumn *columnPtr = *(TreeViewColumn **)(widgRec + offset);
304
305 if (columnPtr == NULL) {
306 return bltEmptyStringObjPtr;
307 }
308 return Tcl_NewStringObj(columnPtr->key, -1);
309}
310
311/*
312 *----------------------------------------------------------------------
313 *
314 * ObjToData --
315 *
316 * Convert the string reprsenting a scroll mode, to its numeric
317 * form.
318 *
319 * Results:
320 * If the string is successfully converted, TCL_OK is returned.
321 * Otherwise, TCL_ERROR is returned and an error message is left
322 * in interpreter's result field.
323 *
324 *----------------------------------------------------------------------
325 */
326/*ARGSUSED*/
327static int
328ObjToData(clientData, interp, tkwin, objPtr, widgRec, offset)
329 ClientData clientData; /* Node of entry. */
330 Tcl_Interp *interp; /* Interpreter to send results back to */
331 Tk_Window tkwin; /* Not used. */
332 Tcl_Obj *objPtr; /* Tcl_Obj representing new data. */
333 char *widgRec;
334 int offset;
335{
336 Tcl_Obj **objv;
337 TreeViewColumn *columnPtr;
338 TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec;
339 char *string;
340 int objc;
341 register int i;
342
343 string = Tcl_GetString(objPtr);
344 if (*string == '\0') {
345 return TCL_OK;
346 }
347 if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
348 return TCL_ERROR;
349 }
350 if (objc == 0) {
351 return TCL_OK;
352 }
353 if (objc & 0x1) {
354 Tcl_AppendResult(interp, "data \"", string,
355 "\" must be in even name-value pairs", (char *)NULL);
356 return TCL_ERROR;
357 }
358 for (i = 0; i < objc; i += 2) {
359 TreeView *tvPtr = entryPtr->tvPtr;
360
361 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
362 != TCL_OK) {
363 return TCL_ERROR;
364 }
365 if (Blt_TreeSetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node,
366 columnPtr->key, objv[i + 1]) != TCL_OK) {
367 return TCL_ERROR;
368 }
369 Blt_TreeViewAddValue(entryPtr, columnPtr);
370 }
371 return TCL_OK;
372}
373
374/*
375 *----------------------------------------------------------------------
376 *
377 * DataToObj --
378 *
379 * Results:
380 * The string representation of the data is returned.
381 *
382 *----------------------------------------------------------------------
383 */
384/*ARGSUSED*/
385static Tcl_Obj *
386DataToObj(clientData, interp, tkwin, widgRec, offset)
387 ClientData clientData; /* Not used. */
388 Tcl_Interp *interp;
389 Tk_Window tkwin; /* Not used. */
390 char *widgRec;
391 int offset;
392{
393 Tcl_Obj *listObjPtr, *objPtr;
394 TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec;
395 TreeViewValue *valuePtr;
396
397 /* Add the key-value pairs to a new Tcl_Obj */
398 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
399 for (valuePtr = entryPtr->values; valuePtr != NULL;
400 valuePtr = valuePtr->nextPtr) {
401 objPtr = Tcl_NewStringObj(valuePtr->columnPtr->key, -1);
402 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
403 if (Blt_TreeViewGetData(entryPtr, valuePtr->columnPtr->key, &objPtr)
404 != TCL_OK) {
405 objPtr = bltEmptyStringObjPtr;
406 }
407 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
408 }
409 return listObjPtr;
410}
411
412int
413Blt_TreeViewGetColumn(interp, tvPtr, objPtr, columnPtrPtr)
414 Tcl_Interp *interp;
415 TreeView *tvPtr;
416 Tcl_Obj *objPtr;
417 TreeViewColumn **columnPtrPtr;
418{
419 char *string;
420
421 string = Tcl_GetString(objPtr);
422 if (strcmp(string, "treeView") == 0) {
423 *columnPtrPtr = &tvPtr->treeColumn;
424 } else {
425 Blt_HashEntry *hPtr;
426
427 hPtr = Blt_FindHashEntry(&tvPtr->columnTable, Blt_TreeGetKey(string));
428 if (hPtr == NULL) {
429 if (interp != NULL) {
430 Tcl_AppendResult(interp, "can't find column \"", string,
431 "\" in \"", Tk_PathName(tvPtr->tkwin), "\"",
432 (char *)NULL);
433 }
434 return TCL_ERROR;
435 }
436 *columnPtrPtr = Blt_GetHashValue(hPtr);
437 }
438 return TCL_OK;
439}
440
441
442/*
443 *----------------------------------------------------------------------
444 *
445 * ObjToStyle --
446 *
447 * Convert the name of an icon into a treeview style.
448 *
449 * Results:
450 * If the string is successfully converted, TCL_OK is returned.
451 * Otherwise, TCL_ERROR is returned and an error message is left in
452 * interpreter's result field.
453 *
454 *----------------------------------------------------------------------
455 */
456/*ARGSUSED*/
457static int
458ObjToStyle(clientData, interp, tkwin, objPtr, widgRec, offset)
459 ClientData clientData; /* Not used. */
460 Tcl_Interp *interp; /* Interpreter to send results back to */
461 Tk_Window tkwin; /* Not used. */
462 Tcl_Obj *objPtr; /* Tcl_Obj representing the new value. */
463 char *widgRec;
464 int offset;
465{
466 TreeView *tvPtr = clientData;
467 TreeViewStyle **stylePtrPtr = (TreeViewStyle **)(widgRec + offset);
468 TreeViewStyle *stylePtr;
469
470 if (Blt_TreeViewGetStyle(interp, tvPtr, Tcl_GetString(objPtr),
471 &stylePtr) != TCL_OK) {
472 return TCL_ERROR;
473 }
474 stylePtr->flags |= STYLE_DIRTY;
475 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY);
476 *stylePtrPtr = stylePtr;
477 return TCL_OK;
478}
479
480/*
481 *----------------------------------------------------------------------
482 *
483 * IconToObj --
484 *
485 * Converts the icon into its string representation (its name).
486 *
487 * Results:
488 * The name of the icon is returned.
489 *
490 *----------------------------------------------------------------------
491 */
492/*ARGSUSED*/
493static Tcl_Obj *
494StyleToObj(clientData, interp, tkwin, widgRec, offset)
495 ClientData clientData; /* Not used. */
496 Tcl_Interp *interp;
497 Tk_Window tkwin; /* Not used. */
498 char *widgRec;
499 int offset;
500{
501 TreeViewStyle *stylePtr = *(TreeViewStyle **)(widgRec + offset);
502
503 if (stylePtr == NULL) {
504 return bltEmptyStringObjPtr;
505 }
506 return Tcl_NewStringObj(stylePtr->name, -1);
507}
508
509/*ARGSUSED*/
510static void
511FreeStyle(clientData, display, widgRec, offset)
512 ClientData clientData;
513 Display *display; /* Not used. */
514 char *widgRec;
515 int offset;
516{
517 TreeView *tvPtr = clientData;
518 TreeViewStyle *stylePtr = *(TreeViewStyle **)(widgRec + offset);
519
520 Blt_TreeViewFreeStyle(tvPtr, stylePtr);
521}
522
523void
524Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr)
525 TreeView *tvPtr;
526 TreeViewColumn *columnPtr;
527{
528 Drawable drawable;
529 GC newGC;
530 Tk_3DBorder border;
531 XGCValues gcValues;
532 int ruleDrawn;
533 unsigned long gcMask;
534 int iconWidth, iconHeight;
535 int textWidth, textHeight;
536
537 gcMask = GCForeground | GCFont;
538 gcValues.font = Tk_FontId(columnPtr->titleFont);
539
540 /* Normal title text */
541 gcValues.foreground = columnPtr->titleFgColor->pixel;
542 newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
543 if (columnPtr->titleGC != NULL) {
544 Tk_FreeGC(tvPtr->display, columnPtr->titleGC);
545 }
546 columnPtr->titleGC = newGC;
547
548 /* Active title text */
549 gcValues.foreground = columnPtr->activeTitleFgColor->pixel;
550 newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
551 if (columnPtr->activeTitleGC != NULL) {
552 Tk_FreeGC(tvPtr->display, columnPtr->activeTitleGC);
553 }
554 columnPtr->activeTitleGC = newGC;
555
556 columnPtr->titleWidth = 0;
557 iconWidth = iconHeight = 0;
558 if (columnPtr->titleIcon != NULL) {
559 iconWidth = TreeViewIconWidth(columnPtr->titleIcon);
560 iconHeight = TreeViewIconHeight(columnPtr->titleIcon);
561 columnPtr->titleWidth += iconWidth;
562 }
563 if (columnPtr->titleTextPtr != NULL) {
564 Blt_Free(columnPtr->titleTextPtr);
565 columnPtr->titleTextPtr = NULL;
566 }
567 textWidth = textHeight = 0;
568 if (columnPtr->title != NULL) {
569 TextStyle ts;
570
571 memset(&ts, 0, sizeof(TextStyle));
572 ts.font = columnPtr->titleFont;
573 ts.justify = TK_JUSTIFY_LEFT;
574 ts.shadow.offset = columnPtr->titleShadow.offset;
575 columnPtr->titleTextPtr = Blt_GetTextLayout(columnPtr->title, &ts);
576 textHeight = columnPtr->titleTextPtr->height;
577 textWidth = columnPtr->titleTextPtr->width;
578 columnPtr->titleWidth += textWidth;
579 }
580 if ((iconWidth > 0) && (textWidth > 0)) {
581 columnPtr->titleWidth += 8;
582 }
583 columnPtr->titleWidth += STD_ARROW_HEIGHT;
584 columnPtr->titleHeight = MAX(iconHeight, textHeight);
585
586 gcMask = (GCFunction | GCLineWidth | GCLineStyle | GCForeground);
587
588 /*
589 * If the rule is active, turn it off (i.e. draw again to erase
590 * it) before changing the GC. If the color changes, we won't be
591 * able to erase the old line, since it will no longer be
592 * correctly XOR-ed with the background.
593 */
594 drawable = Tk_WindowId(tvPtr->tkwin);
595 ruleDrawn = ((tvPtr->flags & TV_RULE_ACTIVE) &&
596 (tvPtr->activeTitleColumnPtr == columnPtr) &&
597 (drawable != None));
598 if (ruleDrawn) {
599 Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
600 }
601 /* XOR-ed rule column divider */
602 gcValues.line_width = LineWidth(columnPtr->ruleLineWidth);
603 gcValues.foreground =
604 Blt_TreeViewGetStyleFg(tvPtr, columnPtr->stylePtr)->pixel;
605 if (LineIsDashed(columnPtr->ruleDashes)) {
606 gcValues.line_style = LineOnOffDash;
607 } else {
608 gcValues.line_style = LineSolid;
609 }
610 gcValues.function = GXxor;
611
612 border = CHOOSE(tvPtr->border, columnPtr->border);
613 gcValues.foreground ^= Tk_3DBorderColor(border)->pixel;
614 newGC = Blt_GetPrivateGC(tvPtr->tkwin, gcMask, &gcValues);
615 if (columnPtr->ruleGC != NULL) {
616 Blt_FreePrivateGC(tvPtr->display, columnPtr->ruleGC);
617 }
618 if (LineIsDashed(columnPtr->ruleDashes)) {
619 Blt_SetDashes(tvPtr->display, newGC, &columnPtr->ruleDashes);
620 }
621 columnPtr->ruleGC = newGC;
622 if (ruleDrawn) {
623 Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
624 }
625 columnPtr->flags |= COLUMN_DIRTY;
626 tvPtr->flags |= TV_UPDATE;
627}
628
629static void
630DestroyColumn(tvPtr, columnPtr)
631 TreeView *tvPtr;
632 TreeViewColumn *columnPtr;
633{
634 Blt_HashEntry *hPtr;
635
636 bltTreeViewUidOption.clientData = tvPtr;
637 bltTreeViewIconOption.clientData = tvPtr;
638 styleOption.clientData = tvPtr;
639 Blt_FreeObjOptions(columnSpecs, (char *)columnPtr, tvPtr->display, 0);
640
641 if (columnPtr->titleGC != NULL) {
642 Tk_FreeGC(tvPtr->display, columnPtr->titleGC);
643 }
644 if (columnPtr->ruleGC != NULL) {
645 Blt_FreePrivateGC(tvPtr->display, columnPtr->ruleGC);
646 }
647 hPtr = Blt_FindHashEntry(&tvPtr->columnTable, columnPtr->key);
648 if (hPtr != NULL) {
649 Blt_DeleteHashEntry(&tvPtr->columnTable, hPtr);
650 }
651 if (columnPtr->linkPtr != NULL) {
652 Blt_ChainDeleteLink(tvPtr->colChainPtr, columnPtr->linkPtr);
653 }
654 if (columnPtr->title != NULL) {
655 Blt_Free(columnPtr->title);
656 }
657 if (columnPtr->titleTextPtr != NULL) {
658 Blt_Free(columnPtr->titleTextPtr);
659 }
660 if (columnPtr->stylePtr != NULL) {
661 Blt_TreeViewFreeStyle(tvPtr, columnPtr->stylePtr);
662 }
663 if (columnPtr != &tvPtr->treeColumn) {
664 Blt_Free(columnPtr);
665 }
666}
667
668void
669Blt_TreeViewDestroyColumns(tvPtr)
670 TreeView *tvPtr;
671{
672 if (tvPtr->colChainPtr != NULL) {
673 Blt_ChainLink *linkPtr;
674 TreeViewColumn *columnPtr;
675
676 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
677 linkPtr = Blt_ChainNextLink(linkPtr)) {
678 columnPtr = Blt_ChainGetValue(linkPtr);
679 columnPtr->linkPtr = NULL;
680 DestroyColumn(tvPtr, columnPtr);
681 }
682 Blt_ChainDestroy(tvPtr->colChainPtr);
683 tvPtr->colChainPtr = NULL;
684 }
685 Blt_DeleteHashTable(&tvPtr->columnTable);
686}
687
688int
689Blt_TreeViewCreateColumn(tvPtr, columnPtr, name, defTitle)
690 TreeView *tvPtr;
691 TreeViewColumn *columnPtr;
692 char *name, *defTitle;
693{
694 Blt_HashEntry *hPtr;
695 int isNew;
696
697 columnPtr->key = Blt_TreeGetKey(name);
698 columnPtr->title = Blt_Strdup(defTitle);
699 columnPtr->justify = TK_JUSTIFY_CENTER;
700 columnPtr->relief = TK_RELIEF_FLAT;
701 columnPtr->borderWidth = 1;
702 columnPtr->pad.side1 = columnPtr->pad.side2 = 2;
703 columnPtr->state = STATE_NORMAL;
704 columnPtr->weight = 1.0;
705 columnPtr->editable = FALSE;
706 columnPtr->ruleLineWidth = 1;
707 columnPtr->titleBorderWidth = 2;
708 columnPtr->titleRelief = TK_RELIEF_RAISED;
709 columnPtr->titleIcon = NULL;
710 hPtr = Blt_CreateHashEntry(&tvPtr->columnTable, columnPtr->key, &isNew);
711 Blt_SetHashValue(hPtr, columnPtr);
712
713 bltTreeViewUidOption.clientData = tvPtr;
714 bltTreeViewIconOption.clientData = tvPtr;
715 styleOption.clientData = tvPtr;
716 if (Blt_ConfigureComponentFromObj(tvPtr->interp, tvPtr->tkwin, name,
717 "Column", columnSpecs, 0, (Tcl_Obj **)NULL, (char *)columnPtr, 0)
718 != TCL_OK) {
719 DestroyColumn(tvPtr, columnPtr);
720 return TCL_ERROR;
721 }
722 return TCL_OK;
723}
724
725static TreeViewColumn *
726CreateColumn(tvPtr, nameObjPtr, objc, objv)
727 TreeView *tvPtr;
728 Tcl_Obj *nameObjPtr;
729 int objc;
730 Tcl_Obj *CONST *objv;
731{
732 TreeViewColumn *columnPtr;
733
734 columnPtr = Blt_Calloc(1, sizeof(TreeViewColumn));
735 assert(columnPtr);
736 if (Blt_TreeViewCreateColumn(tvPtr, columnPtr, Tcl_GetString(nameObjPtr),
737 Tcl_GetString(nameObjPtr)) != TCL_OK) {
738 return NULL;
739 }
740 bltTreeViewUidOption.clientData = tvPtr;
741 bltTreeViewIconOption.clientData = tvPtr;
742 styleOption.clientData = tvPtr;
743 if (Blt_ConfigureComponentFromObj(tvPtr->interp, tvPtr->tkwin,
744 columnPtr->key, "Column", columnSpecs, objc, objv, (char *)columnPtr,
745 BLT_CONFIG_OBJV_ONLY) != TCL_OK) {
746 DestroyColumn(tvPtr, columnPtr);
747 return NULL;
748 }
749 Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr);
750 return columnPtr;
751}
752
753TreeViewColumn *
754Blt_TreeViewNearestColumn(tvPtr, x, y, contextPtr)
755 TreeView *tvPtr;
756 int x, y;
757 ClientData *contextPtr;
758{
759 if (tvPtr->nVisible > 0) {
760 Blt_ChainLink *linkPtr;
761 TreeViewColumn *columnPtr;
762 int right;
763
764 /*
765 * Determine if the pointer is over the rightmost portion of the
766 * column. This activates the rule.
767 */
768 x = WORLDX(tvPtr, x);
769 for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
770 linkPtr = Blt_ChainNextLink(linkPtr)) {
771 columnPtr = Blt_ChainGetValue(linkPtr);
772 right = columnPtr->worldX + columnPtr->width;
773 if ((x >= columnPtr->worldX) && (x <= right)) {
774 if (contextPtr != NULL) {
775 *contextPtr = NULL;
776 if ((tvPtr->flags & TV_SHOW_COLUMN_TITLES) &&
777 (y >= tvPtr->inset) &&
778 (y < (tvPtr->titleHeight + tvPtr->inset))) {
779 *contextPtr = (x >= (right - RULE_AREA))
780 ? ITEM_COLUMN_RULE : ITEM_COLUMN_TITLE;
781 }
782 }
783 return columnPtr;
784 }
785 }
786 }
787 return NULL;
788}
789
790/*
791 *----------------------------------------------------------------------
792 *
793 * ColumnActivateOp --
794 *
795 * Selects the button to appear active.
796 *
797 *----------------------------------------------------------------------
798 */
799/*ARGSUSED*/
800static int
801ColumnActivateOp(tvPtr, interp, objc, objv)
802 TreeView *tvPtr;
803 Tcl_Interp *interp;
804 int objc; /* Not used. */
805 Tcl_Obj *CONST *objv;
806{
807 if (objc == 4) {
808 Drawable drawable;
809 TreeViewColumn *columnPtr;
810 char *string;
811
812 string = Tcl_GetString(objv[3]);
813 if (string[0] == '\0') {
814 columnPtr = NULL;
815 } else {
816 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr)
817 != TCL_OK) {
818 return TCL_ERROR;
819 }
820 if (((tvPtr->flags & TV_SHOW_COLUMN_TITLES) == 0) ||
821 (columnPtr->hidden) || (columnPtr->state == STATE_DISABLED)) {
822 columnPtr = NULL;
823 }
824 }
825 tvPtr->activeTitleColumnPtr = tvPtr->activeColumnPtr = columnPtr;
826 drawable = Tk_WindowId(tvPtr->tkwin);
827 if (drawable != None) {
828 Blt_TreeViewDrawHeadings(tvPtr, drawable);
829 Blt_TreeViewDrawOuterBorders(tvPtr, drawable);
830 }
831 }
832 if (tvPtr->activeTitleColumnPtr != NULL) {
833 Tcl_SetResult(interp, tvPtr->activeTitleColumnPtr->key, TCL_VOLATILE);
834 }
835 return TCL_OK;
836}
837
838/*
839 *----------------------------------------------------------------------
840 *
841 * ColumnBindOp --
842 *
843 * .t bind tag sequence command
844 *
845 *----------------------------------------------------------------------
846 */
847/*ARGSUSED*/
848static int
849ColumnBindOp(tvPtr, interp, objc, objv)
850 TreeView *tvPtr;
851 Tcl_Interp *interp;
852 int objc; /* Not used. */
853 Tcl_Obj *CONST *objv;
854{
855 ClientData object;
856 TreeViewColumn *columnPtr;
857
858 if (Blt_TreeViewGetColumn(NULL, tvPtr, objv[3], &columnPtr) == TCL_OK) {
859 object = Blt_TreeViewColumnTag(tvPtr, columnPtr->key);
860 } else {
861 object = Blt_TreeViewColumnTag(tvPtr, Tcl_GetString(objv[3]));
862 }
863 return Blt_ConfigureBindingsFromObj(interp, tvPtr->bindTable, object,
864 objc - 4, objv + 4);
865}
866
867
868/*
869 *----------------------------------------------------------------------
870 *
871 * ColumnCgetOp --
872 *
873 *----------------------------------------------------------------------
874 */
875/*ARGSUSED*/
876static int
877ColumnCgetOp(tvPtr, interp, objc, objv)
878 TreeView *tvPtr;
879 Tcl_Interp *interp;
880 int objc; /* Not used. */
881 Tcl_Obj *CONST *objv;
882{
883 TreeViewColumn *columnPtr;
884
885 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) {
886 return TCL_ERROR;
887 }
888 return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, columnSpecs,
889 (char *)columnPtr, objv[4], 0);
890}
891
892/*
893 *----------------------------------------------------------------------
894 *
895 * ColumnConfigureOp --
896 *
897 * This procedure is called to process a list of configuration
898 * options database, in order to reconfigure the one of more
899 * entries in the widget.
900 *
901 * .h entryconfigure node node node node option value
902 *
903 * Results:
904 * A standard Tcl result. If TCL_ERROR is returned, then
905 * interp->result contains an error message.
906 *
907 * Side effects:
908 * Configuration information, such as text string, colors, font,
909 * etc. get set for tvPtr; old resources get freed, if there
910 * were any. The hypertext is redisplayed.
911 *
912 *----------------------------------------------------------------------
913 */
914static int
915ColumnConfigureOp(tvPtr, interp, objc, objv)
916 TreeView *tvPtr;
917 Tcl_Interp *interp;
918 int objc;
919 Tcl_Obj *CONST *objv;
920{
921 TreeViewColumn *columnPtr;
922 int nOptions, start;
923 register int i;
924
925 /* Figure out where the option value pairs begin */
926 for(i = 3; i < objc; i++) {
927 if (Blt_ObjIsOption(columnSpecs, objv[i], 0)) {
928 break;
929 }
930 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
931 != TCL_OK) {
932 return TCL_ERROR;
933 }
934 }
935 start = i;
936 nOptions = objc - start;
937
938 bltTreeViewUidOption.clientData = tvPtr;
939 bltTreeViewIconOption.clientData = tvPtr;
940 styleOption.clientData = tvPtr;
941 for (i = 3; i < start; i++) {
942 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
943 != TCL_OK) {
944 return TCL_ERROR;
945 }
946 if (nOptions == 0) {
947 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, columnSpecs,
948 (char *)columnPtr, (Tcl_Obj *)NULL, 0);
949 } else if (nOptions == 1) {
950 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, columnSpecs,
951 (char *)columnPtr, objv[start], 0);
952 }
953 if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tvPtr->tkwin,
954 columnSpecs, nOptions, objv + start, (char *)columnPtr,
955 BLT_CONFIG_OBJV_ONLY) != TCL_OK) {
956 return TCL_ERROR;
957 }
958 Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr);
959 }
960 /*FIXME: Makes every change redo everything. */
961 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY);
962 Blt_TreeViewEventuallyRedraw(tvPtr);
963 return TCL_OK;
964}
965
966/*
967 *----------------------------------------------------------------------
968 *
969 * ColumnDeleteOp --
970 *
971 *----------------------------------------------------------------------
972 */
973/*ARGSUSED*/
974static int
975ColumnDeleteOp(tvPtr, interp, objc, objv)
976 TreeView *tvPtr;
977 Tcl_Interp *interp; /* Not used. */
978 int objc;
979 Tcl_Obj *CONST *objv;
980{
981 TreeViewColumn *columnPtr;
982 TreeViewEntry *entryPtr;
983 register int i;
984
985 for(i = 3; i < objc; i++) {
986 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[i], &columnPtr)
987 != TCL_OK) {
988 return TCL_ERROR;
989 }
990 /* Traverse the tree deleting values associated with the column. */
991 for(entryPtr = tvPtr->rootPtr; entryPtr != NULL;
992 entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
993 if (entryPtr != NULL) {
994 TreeViewValue *valuePtr, *lastPtr, *nextPtr;
995
996 lastPtr = NULL;
997 for (valuePtr = entryPtr->values; valuePtr != NULL;
998 valuePtr = nextPtr) {
999 nextPtr = valuePtr->nextPtr;
1000 if (valuePtr->columnPtr == columnPtr) {
1001 Blt_TreeViewDestroyValue(tvPtr, valuePtr);
1002 if (lastPtr == NULL) {
1003 entryPtr->values = nextPtr;
1004 } else {
1005 lastPtr->nextPtr = nextPtr;
1006 }
1007 break;
1008 }
1009 lastPtr = valuePtr;
1010 }
1011 }
1012 }
1013 DestroyColumn(tvPtr, columnPtr);
1014 }
1015 /* Deleting a column may affect the height of an entry. */
1016 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
1017 Blt_TreeViewEventuallyRedraw(tvPtr);
1018 return TCL_OK;
1019}
1020
1021/*
1022 *----------------------------------------------------------------------
1023 *
1024 * ColumnInsertOp --
1025 *
1026 * Add new columns to the tree.
1027 *
1028 *----------------------------------------------------------------------
1029 */
1030/*ARGSUSED*/
1031static int
1032ColumnInsertOp(tvPtr, interp, objc, objv)
1033 TreeView *tvPtr;
1034 Tcl_Interp *interp;
1035 int objc;
1036 Tcl_Obj *CONST *objv;
1037{
1038 Blt_ChainLink *beforePtr;
1039 Tcl_Obj *CONST *options;
1040 TreeViewColumn *columnPtr;
1041 TreeViewEntry *entryPtr;
1042 int insertPos;
1043 int nOptions;
1044 int start;
1045 register int i;
1046
1047 if (Blt_GetPositionFromObj(tvPtr->interp, objv[3], &insertPos) != TCL_OK) {
1048 return TCL_ERROR;
1049 }
1050 if ((insertPos == -1) ||
1051 (insertPos >= Blt_ChainGetLength(tvPtr->colChainPtr))) {
1052 beforePtr = NULL;
1053 } else {
1054 beforePtr = Blt_ChainGetNthLink(tvPtr->colChainPtr, insertPos);
1055 }
1056 /*
1057 * Count the column names that follow. Count the arguments until we
1058 * spot one that looks like a configuration option (i.e. starts
1059 * with a minus ("-")).
1060 */
1061 for (i = 4; i < objc; i++) {
1062 if (Blt_ObjIsOption(columnSpecs, objv[i], 0)) {
1063 break;
1064 }
1065 }
1066 start = i;
1067 nOptions = objc - i;
1068 options = objv + start;
1069
1070 for (i = 4; i < start; i++) {
1071 if (Blt_TreeViewGetColumn(NULL, tvPtr, objv[i], &columnPtr) == TCL_OK) {
1072 Tcl_AppendResult(interp, "column \"", Tcl_GetString(objv[i]),
1073 "\" already exists", (char *)NULL);
1074 return TCL_ERROR;
1075 }
1076 columnPtr = CreateColumn(tvPtr, objv[i], nOptions, options);
1077 if (columnPtr == NULL) {
1078 return TCL_ERROR;
1079 }
1080 if (beforePtr == NULL) {
1081 columnPtr->linkPtr = Blt_ChainAppend(tvPtr->colChainPtr, columnPtr);
1082 } else {
1083 columnPtr->linkPtr = Blt_ChainNewLink();
1084 Blt_ChainSetValue(columnPtr->linkPtr, columnPtr);
1085 Blt_ChainLinkBefore(tvPtr->colChainPtr, columnPtr->linkPtr,
1086 beforePtr);
1087 }
1088 /*
1089 * Traverse the tree adding column entries where needed.
1090 */
1091 for(entryPtr = tvPtr->rootPtr; entryPtr != NULL;
1092 entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
1093 Blt_TreeViewAddValue(entryPtr, columnPtr);
1094 }
1095 Blt_TreeViewTraceColumn(tvPtr, columnPtr);
1096 }
1097 Blt_TreeViewEventuallyRedraw(tvPtr);
1098 return TCL_OK;
1099}
1100
1101
1102
1103/*
1104 *----------------------------------------------------------------------
1105 *
1106 * ColumnCurrentOp --
1107 *
1108 * Make the rule to appear active.
1109 *
1110 *----------------------------------------------------------------------
1111 */
1112/*ARGSUSED*/
1113static int
1114ColumnCurrentOp(tvPtr, interp, objc, objv)
1115 TreeView *tvPtr;
1116 Tcl_Interp *interp;
1117 int objc; /* Not used. */
1118 Tcl_Obj *CONST *objv; /* Not used. */
1119{
1120 ClientData context;
1121 TreeViewColumn *columnPtr;
1122
1123 columnPtr = NULL;
1124 context = Blt_GetCurrentContext(tvPtr->bindTable);
1125 if ((context == ITEM_COLUMN_TITLE) || (context == ITEM_COLUMN_RULE)) {
1126 columnPtr = Blt_GetCurrentItem(tvPtr->bindTable);
1127 }
1128 if (context >= ITEM_STYLE) {
1129 TreeViewValue *valuePtr = context;
1130
1131 columnPtr = valuePtr->columnPtr;
1132 }
1133 if (columnPtr != NULL) {
1134 Tcl_SetResult(interp, columnPtr->key, TCL_VOLATILE);
1135 }
1136 return TCL_OK;
1137}
1138
1139/*
1140 *----------------------------------------------------------------------
1141 *
1142 * ColumnInvokeOp --
1143 *
1144 * This procedure is called to invoke a column command.
1145 *
1146 * .h column invoke columnName
1147 *
1148 * Results:
1149 * A standard Tcl result. If TCL_ERROR is returned, then
1150 * interp->result contains an error message.
1151 *
1152 *----------------------------------------------------------------------
1153 */
1154/*ARGSUSED*/
1155static int
1156ColumnInvokeOp(tvPtr, interp, objc, objv)
1157 TreeView *tvPtr;
1158 Tcl_Interp *interp; /* Not used. */
1159 int objc;
1160 Tcl_Obj *CONST *objv;
1161{
1162 TreeViewColumn *columnPtr;
1163 char *string;
1164
1165 string = Tcl_GetString(objv[3]);
1166 if (string[0] == '\0') {
1167 return TCL_OK;
1168 }
1169 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[3], &columnPtr) != TCL_OK) {
1170 return TCL_ERROR;
1171 }
1172 if ((columnPtr->state == STATE_NORMAL) && (columnPtr->titleCmd != NULL)) {
1173 int result;
1174
1175 Tcl_Preserve(tvPtr);
1176 Tcl_Preserve(columnPtr);
1177 result = Tcl_GlobalEval(interp, columnPtr->titleCmd);
1178 Tcl_Release(columnPtr);
1179 Tcl_Release(tvPtr);
1180 return result;
1181 }
1182 return TCL_OK;
1183}
1184
1185/*
1186 *----------------------------------------------------------------------
1187 *
1188 * ColumnMoveOp --
1189 *
1190 * Move a column.
1191 *
1192 * .h column move field1 position
1193 *----------------------------------------------------------------------
1194 */
1195
1196/*
1197 *----------------------------------------------------------------------
1198 *
1199 * ColumnNamesOp --
1200 *
1201 *----------------------------------------------------------------------
1202 */
1203/*ARGSUSED*/
1204static int
1205ColumnNamesOp(tvPtr, interp, objc, objv)
1206 TreeView *tvPtr;
1207 Tcl_Interp *interp;
1208 int objc; /* Not used. */
1209 Tcl_Obj *CONST *objv; /* Not used. */
1210{
1211 Blt_ChainLink *linkPtr;
1212 Tcl_Obj *listObjPtr, *objPtr;
1213 TreeViewColumn *columnPtr;
1214
1215 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1216 for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
1217 linkPtr = Blt_ChainNextLink(linkPtr)) {
1218 columnPtr = Blt_ChainGetValue(linkPtr);
1219 objPtr = Tcl_NewStringObj(columnPtr->key, -1);
1220 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1221 }
1222 Tcl_SetObjResult(interp, listObjPtr);
1223 return TCL_OK;
1224}
1225
1226/*ARGSUSED*/
1227static int
1228ColumnNearestOp(tvPtr, interp, objc, objv)
1229 TreeView *tvPtr;
1230 Tcl_Interp *interp;
1231 int objc; /* Not used. */
1232 Tcl_Obj *CONST *objv;
1233{
1234 int x, y; /* Screen coordinates of the test point. */
1235 TreeViewColumn *columnPtr;
1236 ClientData context;
1237 int checkTitle;
1238#ifdef notdef
1239 int isRoot;
1240
1241 isRoot = FALSE;
1242 string = Tcl_GetString(objv[3]);
1243
1244 if (strcmp("-root", string) == 0) {
1245 isRoot = TRUE;
1246 objv++, objc--;
1247 }
1248 if (objc != 5) {
1249 Tcl_AppendResult(interp, "wrong # args: should be \"",
1250 Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]),
1251 Tcl_GetString(objv[2]), " ?-root? x y\"", (char *)NULL);
1252 return TCL_ERROR;
1253
1254 }
1255#endif
1256 if (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[3], &x) != TCL_OK) {
1257 return TCL_ERROR;
1258 }
1259 y = 0;
1260 checkTitle = FALSE;
1261 if (objc == 5) {
1262 if (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[4], &y) != TCL_OK) {
1263 return TCL_ERROR;
1264 }
1265 checkTitle = TRUE;
1266 }
1267 columnPtr = Blt_TreeViewNearestColumn(tvPtr, x, y, &context);
1268 if ((checkTitle) && (context == NULL)) {
1269 columnPtr = NULL;
1270 }
1271 if (columnPtr != NULL) {
1272 Tcl_SetResult(interp, columnPtr->key, TCL_VOLATILE);
1273 }
1274 return TCL_OK;
1275}
1276
1277static void
1278UpdateMark(tvPtr, newMark)
1279 TreeView *tvPtr;
1280 int newMark;
1281{
1282 Drawable drawable;
1283 TreeViewColumn *columnPtr;
1284 int dx;
1285 int width;
1286
1287 columnPtr = tvPtr->resizeColumnPtr;
1288 if (columnPtr == NULL) {
1289 return;
1290 }
1291 drawable = Tk_WindowId(tvPtr->tkwin);
1292 if (drawable == None) {
1293 return;
1294 }
1295
1296 /* Erase any existing rule. */
1297 if (tvPtr->flags & TV_RULE_ACTIVE) {
1298 Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
1299 }
1300
1301 dx = newMark - tvPtr->ruleAnchor;
1302 width = columnPtr->width -
1303 (PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth);
1304 if ((columnPtr->reqMin > 0) && ((width + dx) < columnPtr->reqMin)) {
1305 dx = columnPtr->reqMin - width;
1306 }
1307 if ((columnPtr->reqMax > 0) && ((width + dx) > columnPtr->reqMax)) {
1308 dx = columnPtr->reqMax - width;
1309 }
1310 if ((width + dx) < 4) {
1311 dx = 4 - width;
1312 }
1313 tvPtr->ruleMark = tvPtr->ruleAnchor + dx;
1314
1315 /* Redraw the rule if required. */
1316 if (tvPtr->flags & TV_RULE_NEEDED) {
1317 Blt_TreeViewDrawRule(tvPtr, columnPtr, drawable);
1318 }
1319}
1320
1321/*
1322 *----------------------------------------------------------------------
1323 *
1324 * ResizeActivateOp --
1325 *
1326 * Turns on/off the resize cursor.
1327 *
1328 *----------------------------------------------------------------------
1329 */
1330/*ARGSUSED*/
1331static int
1332ResizeActivateOp(tvPtr, interp, objc, objv)
1333 TreeView *tvPtr;
1334 Tcl_Interp *interp;
1335 int objc; /* Not used. */
1336 Tcl_Obj *CONST *objv;
1337{
1338 TreeViewColumn *columnPtr;
1339 char *string;
1340
1341 string = Tcl_GetString(objv[4]);
1342 if (string[0] == '\0') {
1343 if (tvPtr->cursor != None) {
1344 Tk_DefineCursor(tvPtr->tkwin, tvPtr->cursor);
1345 } else {
1346 Tk_UndefineCursor(tvPtr->tkwin);
1347 }
1348 tvPtr->resizeColumnPtr = NULL;
1349 } else if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr)
1350 == TCL_OK) {
1351 if (tvPtr->resizeCursor != None) {
1352 Tk_DefineCursor(tvPtr->tkwin, tvPtr->resizeCursor);
1353 }
1354 tvPtr->resizeColumnPtr = columnPtr;
1355 } else {
1356 return TCL_ERROR;
1357 }
1358 return TCL_OK;
1359}
1360
1361/*
1362 *----------------------------------------------------------------------
1363 *
1364 * ResizeAnchorOp --
1365 *
1366 * Set the anchor for the resize.
1367 *
1368 *----------------------------------------------------------------------
1369 */
1370/*ARGSUSED*/
1371static int
1372ResizeAnchorOp(tvPtr, interp, objc, objv)
1373 TreeView *tvPtr;
1374 Tcl_Interp *interp;
1375 int objc; /* Not used. */
1376 Tcl_Obj *CONST *objv;
1377{
1378 int x;
1379
1380 if (Tcl_GetIntFromObj(NULL, objv[4], &x) != TCL_OK) {
1381 return TCL_ERROR;
1382 }
1383 tvPtr->ruleAnchor = x;
1384 tvPtr->flags |= TV_RULE_NEEDED;
1385 UpdateMark(tvPtr, x);
1386 return TCL_OK;
1387}
1388
1389/*
1390 *----------------------------------------------------------------------
1391 *
1392 * ResizeMarkOp --
1393 *
1394 * Sets the resize mark. The distance between the mark and the anchor
1395 * is the delta to change the width of the active column.
1396 *
1397 *----------------------------------------------------------------------
1398 */
1399/*ARGSUSED*/
1400static int
1401ResizeMarkOp(tvPtr, interp, objc, objv)
1402 TreeView *tvPtr;
1403 Tcl_Interp *interp;
1404 int objc; /* Not used. */
1405 Tcl_Obj *CONST *objv;
1406{
1407 int x;
1408
1409 if (Tcl_GetIntFromObj(NULL, objv[4], &x) != TCL_OK) {
1410 return TCL_ERROR;
1411 }
1412 tvPtr->flags |= TV_RULE_NEEDED;
1413 UpdateMark(tvPtr, x);
1414 return TCL_OK;
1415}
1416
1417/*
1418 *----------------------------------------------------------------------
1419 *
1420 * ResizeSetOp --
1421 *
1422 * Returns the new width of the column including the resize delta.
1423 *
1424 *----------------------------------------------------------------------
1425 */
1426/*ARGSUSED*/
1427static int
1428ResizeSetOp(tvPtr, interp, objc, objv)
1429 TreeView *tvPtr;
1430 Tcl_Interp *interp;
1431 int objc; /* Not used. */
1432 Tcl_Obj *CONST *objv; /* Not used. */
1433{
1434 tvPtr->flags &= ~TV_RULE_NEEDED;
1435 UpdateMark(tvPtr, tvPtr->ruleMark);
1436 if (tvPtr->resizeColumnPtr != NULL) {
1437 int width, delta;
1438 TreeViewColumn *columnPtr;
1439
1440 columnPtr = tvPtr->resizeColumnPtr;
1441 delta = (tvPtr->ruleMark - tvPtr->ruleAnchor);
1442 width = tvPtr->resizeColumnPtr->width + delta -
1443 (PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth) - 1;
1444 Tcl_SetObjResult(interp, Tcl_NewIntObj(width));
1445 }
1446 return TCL_OK;
1447}
1448
1449static Blt_OpSpec resizeOps[] =
1450{
1451 {"activate", 2, (Blt_Op)ResizeActivateOp, 5, 5, "column"},
1452 {"anchor", 2, (Blt_Op)ResizeAnchorOp, 5, 5, "x"},
1453 {"mark", 1, (Blt_Op)ResizeMarkOp, 5, 5, "x"},
1454 {"set", 1, (Blt_Op)ResizeSetOp, 4, 4, "",},
1455};
1456
1457static int nResizeOps = sizeof(resizeOps) / sizeof(Blt_OpSpec);
1458
1459/*
1460 *----------------------------------------------------------------------
1461 *
1462 * ColumnResizeOp --
1463 *
1464 *----------------------------------------------------------------------
1465 */
1466static int
1467ColumnResizeOp(tvPtr, interp, objc, objv)
1468 TreeView *tvPtr;
1469 Tcl_Interp *interp;
1470 int objc;
1471 Tcl_Obj *CONST *objv;
1472{
1473 Blt_Op proc;
1474 int result;
1475
1476 proc = Blt_GetOpFromObj(interp, nResizeOps, resizeOps, BLT_OP_ARG3,
1477 objc, objv,0);
1478 if (proc == NULL) {
1479 return TCL_ERROR;
1480 }
1481 result = (*proc) (tvPtr, interp, objc, objv);
1482 return result;
1483}
1484
1485
1486static Blt_OpSpec columnOps[] =
1487{
1488 {"activate", 1, (Blt_Op)ColumnActivateOp, 3, 4, "?field?",},
1489 {"bind", 1, (Blt_Op)ColumnBindOp, 4, 6, "tagName ?sequence command?",},
1490 {"cget", 2, (Blt_Op)ColumnCgetOp, 5, 5, "field option",},
1491 {"configure", 2, (Blt_Op)ColumnConfigureOp, 4, 0,
1492 "field ?option value?...",},
1493 {"current", 2, (Blt_Op)ColumnCurrentOp, 3, 3, "",},
1494 {"delete", 1, (Blt_Op)ColumnDeleteOp, 3, 0, "?field...?",},
1495 {"highlight", 1, (Blt_Op)ColumnActivateOp, 3, 4, "?field?",},
1496 {"insert", 3, (Blt_Op)ColumnInsertOp, 5, 0,
1497 "position field ?field...? ?option value?...",},
1498 {"invoke", 3, (Blt_Op)ColumnInvokeOp, 4, 4, "field",},
1499 {"names", 2, (Blt_Op)ColumnNamesOp, 3, 3, "",},
1500 {"nearest", 2, (Blt_Op)ColumnNearestOp, 4, 5, "x ?y?",},
1501 {"resize", 1, (Blt_Op)ColumnResizeOp, 3, 0, "arg",},
1502};
1503static int nColumnOps = sizeof(columnOps) / sizeof(Blt_OpSpec);
1504
1505/*
1506 *----------------------------------------------------------------------
1507 *
1508 * Blt_TreeViewColumnOp --
1509 *
1510 *----------------------------------------------------------------------
1511 */
1512int
1513Blt_TreeViewColumnOp(tvPtr, interp, objc, objv)
1514 TreeView *tvPtr;
1515 Tcl_Interp *interp;
1516 int objc;
1517 Tcl_Obj *CONST *objv;
1518{
1519 Blt_Op proc;
1520 int result;
1521
1522 proc = Blt_GetOpFromObj(interp, nColumnOps, columnOps, BLT_OP_ARG2,
1523 objc, objv,0);
1524 if (proc == NULL) {
1525 return TCL_ERROR;
1526 }
1527 result = (*proc) (tvPtr, interp, objc, objv);
1528 return result;
1529}
1530
1531
1532static int
1533InvokeCompare(tvPtr, e1Ptr, e2Ptr, command)
1534 TreeView *tvPtr;
1535 TreeViewEntry *e1Ptr, *e2Ptr;
1536 char *command;
1537{
1538 int result;
1539 Tcl_Obj *objv[8];
1540 int i;
1541
1542 objv[0] = Tcl_NewStringObj(command, -1);
1543 objv[1] = Tcl_NewStringObj(Tk_PathName(tvPtr->tkwin), -1);
1544 objv[2] = Tcl_NewIntObj(Blt_TreeNodeId(e1Ptr->node));
1545 objv[3] = Tcl_NewIntObj(Blt_TreeNodeId(e2Ptr->node));
1546 objv[4] = Tcl_NewStringObj(tvPtr->sortColumnPtr->key, -1);
1547
1548 if (tvPtr->flatView) {
1549 objv[5] = Tcl_NewStringObj(e1Ptr->fullName, -1);
1550 objv[6] = Tcl_NewStringObj(e2Ptr->fullName, -1);
1551 } else {
1552 objv[5] = Tcl_NewStringObj(GETLABEL(e1Ptr), -1);
1553 objv[6] = Tcl_NewStringObj(GETLABEL(e2Ptr), -1);
1554 }
1555 for(i = 0; i < 7; i++) {
1556 Tcl_IncrRefCount(objv[i]);
1557 }
1558 objv[7] = NULL;
1559 result = Tcl_EvalObjv(tvPtr->interp, 7, objv, TCL_EVAL_GLOBAL);
1560 if ((result != TCL_OK) ||
1561 (Tcl_GetIntFromObj(tvPtr->interp, Tcl_GetObjResult(tvPtr->interp),
1562 &result) != TCL_OK)) {
1563 Tcl_BackgroundError(tvPtr->interp);
1564 }
1565 for(i = 0; i < 7; i++) {
1566 Tcl_DecrRefCount(objv[i]);
1567 }
1568 Tcl_ResetResult(tvPtr->interp);
1569 return result;
1570}
1571
1572static TreeView *treeViewInstance;
1573
1574static int
1575CompareEntries(a, b)
1576 CONST void *a, *b;
1577{
1578 TreeView *tvPtr;
1579 TreeViewEntry **e1PtrPtr = (TreeViewEntry **)a;
1580 TreeViewEntry **e2PtrPtr = (TreeViewEntry **)b;
1581 Tcl_Obj *obj1, *obj2;
1582 char *s1, *s2;
1583 int result;
1584
1585 tvPtr = (*e1PtrPtr)->tvPtr;
1586 obj1 = (*e1PtrPtr)->dataObjPtr;
1587 obj2 = (*e2PtrPtr)->dataObjPtr;
1588 s1 = Tcl_GetString(obj1);
1589 s2 = Tcl_GetString(obj2);
1590 result = 0;
1591 switch (tvPtr->sortType) {
1592 case SORT_TYPE_ASCII:
1593 result = strcmp(s1, s2);
1594 break;
1595
1596 case SORT_TYPE_COMMAND:
1597 {
1598 char *cmd;
1599
1600 cmd = tvPtr->sortColumnPtr->sortCmd;
1601 if (cmd == NULL) {
1602 cmd = tvPtr->sortCmd;
1603 }
1604 if (cmd == NULL) {
1605 result = Blt_DictionaryCompare(s1, s2);
1606 } else {
1607 result = InvokeCompare(tvPtr, *e1PtrPtr, *e2PtrPtr, cmd);
1608 }
1609 }
1610 break;
1611
1612 case SORT_TYPE_DICTIONARY:
1613 result = Blt_DictionaryCompare(s1, s2);
1614 break;
1615
1616 case SORT_TYPE_INTEGER:
1617 {
1618 int i1, i2;
1619
1620 if (Tcl_GetIntFromObj(NULL, obj1, &i1)==TCL_OK) {
1621 if (Tcl_GetIntFromObj(NULL, obj2, &i2) == TCL_OK) {
1622 result = i1 - i2;
1623 } else {
1624 result = -1;
1625 }
1626 } else if (Tcl_GetIntFromObj(NULL, obj2, &i2) == TCL_OK) {
1627 result = 1;
1628 } else {
1629 result = Blt_DictionaryCompare(s1, s2);
1630 }
1631 }
1632 break;
1633
1634 case SORT_TYPE_REAL:
1635 {
1636 double r1, r2;
1637
1638 if (Tcl_GetDoubleFromObj(NULL, obj1, &r1) == TCL_OK) {
1639 if (Tcl_GetDoubleFromObj(NULL, obj2, &r2) == TCL_OK) {
1640 result = (r1 < r2) ? -1 : (r1 > r2) ? 1 : 0;
1641 } else {
1642 result = -1;
1643 }
1644 } else if (Tcl_GetDoubleFromObj(NULL, obj2, &r2) == TCL_OK) {
1645 result = 1;
1646 } else {
1647 result = Blt_DictionaryCompare(s1, s2);
1648 }
1649 }
1650 break;
1651 }
1652 if (tvPtr->sortDecreasing) {
1653 return -result;
1654 }
1655 return result;
1656}
1657
1658
1659/*
1660 *----------------------------------------------------------------------
1661 *
1662 * CompareNodes --
1663 *
1664 * Comparison routine (used by qsort) to sort a chain of subnodes.
1665 *
1666 * Results:
1667 * 1 is the first is greater, -1 is the second is greater, 0
1668 * if equal.
1669 *
1670 *----------------------------------------------------------------------
1671 */
1672static int
1673CompareNodes(n1Ptr, n2Ptr)
1674 Blt_TreeNode *n1Ptr, *n2Ptr;
1675{
1676 TreeView *tvPtr = treeViewInstance;
1677 TreeViewEntry *e1Ptr, *e2Ptr;
1678
1679 e1Ptr = Blt_NodeToEntry(tvPtr, *n1Ptr);
1680 e2Ptr = Blt_NodeToEntry(tvPtr, *n2Ptr);
1681
1682 /* Fetch the data for sorting. */
1683 if (tvPtr->sortType == SORT_TYPE_COMMAND) {
1684 e1Ptr->dataObjPtr = Tcl_NewIntObj(Blt_TreeNodeId(*n1Ptr));
1685 e2Ptr->dataObjPtr = Tcl_NewIntObj(Blt_TreeNodeId(*n2Ptr));
1686 } else if (tvPtr->sortColumnPtr == &tvPtr->treeColumn) {
1687 Tcl_DString dString;
1688
1689 Tcl_DStringInit(&dString);
1690 if (e1Ptr->fullName == NULL) {
1691 Blt_TreeViewGetFullName(tvPtr, e1Ptr, TRUE, &dString);
1692 e1Ptr->fullName = Blt_Strdup(Tcl_DStringValue(&dString));
1693 }
1694 e1Ptr->dataObjPtr = Tcl_NewStringObj(e1Ptr->fullName, -1);
1695 if (e2Ptr->fullName == NULL) {
1696 Blt_TreeViewGetFullName(tvPtr, e2Ptr, TRUE, &dString);
1697 e2Ptr->fullName = Blt_Strdup(Tcl_DStringValue(&dString));
1698 }
1699 e2Ptr->dataObjPtr = Tcl_NewStringObj(e2Ptr->fullName, -1);
1700 Tcl_DStringFree(&dString);
1701 } else {
1702 Blt_TreeKey key;
1703 Tcl_Obj *objPtr;
1704
1705 key = tvPtr->sortColumnPtr->key;
1706 if (Blt_TreeViewGetData(e1Ptr, key, &objPtr) != TCL_OK) {
1707 e1Ptr->dataObjPtr = bltEmptyStringObjPtr;
1708 } else {
1709 e1Ptr->dataObjPtr = objPtr;
1710 }
1711 if (Blt_TreeViewGetData(e2Ptr, key, &objPtr) != TCL_OK) {
1712 e2Ptr->dataObjPtr = bltEmptyStringObjPtr;
1713 } else {
1714 e2Ptr->dataObjPtr = objPtr;
1715 }
1716 }
1717 return CompareEntries(&e1Ptr, &e2Ptr);
1718}
1719
1720static int
1721SortAutoOp(tvPtr, interp, objc, objv)
1722 TreeView *tvPtr;
1723 Tcl_Interp *interp; /* Not used. */
1724 int objc;
1725 Tcl_Obj *CONST *objv;
1726{
1727
1728 if (objc == 4) {
1729 int bool;
1730 int isAuto;
1731
1732 isAuto = ((tvPtr->flags & TV_SORT_AUTO) != 0);
1733 if (Tcl_GetBooleanFromObj(interp, objv[3], &bool) != TCL_OK) {
1734 return TCL_ERROR;
1735 }
1736 if (isAuto != bool) {
1737 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
1738 Blt_TreeViewEventuallyRedraw(tvPtr);
1739 }
1740 if (bool) {
1741 tvPtr->flags |= TV_SORT_AUTO;
1742 } else {
1743 tvPtr->flags &= ~TV_SORT_AUTO;
1744 }
1745 }
1746 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(tvPtr->flags & TV_SORT_AUTO));
1747 return TCL_OK;
1748}
1749
1750/*
1751 *----------------------------------------------------------------------
1752 *
1753 * SortCgetOp --
1754 *
1755 *----------------------------------------------------------------------
1756 */
1757/*ARGSUSED*/
1758static int
1759SortCgetOp(tvPtr, interp, objc, objv)
1760 TreeView *tvPtr;
1761 Tcl_Interp *interp;
1762 int objc; /* Not used. */
1763 Tcl_Obj *CONST *objv;
1764{
1765 return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, sortSpecs,
1766 (char *)tvPtr, objv[3], 0);
1767}
1768
1769/*
1770 *----------------------------------------------------------------------
1771 *
1772 * SortConfigureOp --
1773 *
1774 * This procedure is called to process a list of configuration
1775 * options database, in order to reconfigure the one of more
1776 * entries in the widget.
1777 *
1778 * .h sort configure option value
1779 *
1780 * Results:
1781 * A standard Tcl result. If TCL_ERROR is returned, then
1782 * interp->result contains an error message.
1783 *
1784 * Side effects:
1785 * Configuration information, such as text string, colors, font,
1786 * etc. get set for tvPtr; old resources get freed, if there
1787 * were any. The hypertext is redisplayed.
1788 *
1789 *----------------------------------------------------------------------
1790 */
1791static int
1792SortConfigureOp(tvPtr, interp, objc, objv)
1793 TreeView *tvPtr;
1794 Tcl_Interp *interp;
1795 int objc;
1796 Tcl_Obj *CONST *objv;
1797{
1798 int oldType;
1799 char *oldCommand;
1800 TreeViewColumn *oldColumn;
1801
1802 if (objc == 3) {
1803 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, sortSpecs,
1804 (char *)tvPtr, (Tcl_Obj *)NULL, 0);
1805 } else if (objc == 4) {
1806 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, sortSpecs,
1807 (char *)tvPtr, objv[3], 0);
1808 }
1809 oldColumn = tvPtr->sortColumnPtr;
1810 oldType = tvPtr->sortType;
1811 oldCommand = tvPtr->sortCmd;
1812 if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, sortSpecs,
1813 objc - 3, objv + 3, (char *)tvPtr, BLT_CONFIG_OBJV_ONLY) != TCL_OK) {
1814 return TCL_ERROR;
1815 }
1816 if ((oldColumn != tvPtr->sortColumnPtr) ||
1817 (oldType != tvPtr->sortType) ||
1818 (oldCommand != tvPtr->sortCmd)) {
1819 tvPtr->flags &= ~TV_SORTED;
1820 tvPtr->flags |= (TV_DIRTY | TV_RESORT);
1821 }
1822 if (tvPtr->flags & TV_SORT_AUTO) {
1823 tvPtr->flags |= TV_SORT_PENDING;
1824 }
1825 Blt_TreeViewEventuallyRedraw(tvPtr);
1826 return TCL_OK;
1827}
1828
1829/*ARGSUSED*/
1830static int
1831SortOnceOp(tvPtr, interp, objc, objv)
1832 TreeView *tvPtr;
1833 Tcl_Interp *interp; /* Not used. */
1834 int objc;
1835 Tcl_Obj *CONST *objv;
1836{
1837 TreeViewEntry *entryPtr;
1838 int recurse, result;
1839 register int i;
1840
1841 recurse = FALSE;
1842 if (objc > 3) {
1843 char *string;
1844 int length;
1845
1846 string = Tcl_GetStringFromObj(objv[3], &length);
1847 if ((string[0] == '-') && (length > 1) &&
1848 (strncmp(string, "-recurse", length) == 0)) {
1849 objv++, objc--;
1850 recurse = TRUE;
1851 }
1852 }
1853 for (i = 3; i < objc; i++) {
1854 if (Blt_TreeViewGetEntry(tvPtr, objv[i], &entryPtr) != TCL_OK) {
1855 return TCL_ERROR;
1856 }
1857 if (recurse) {
1858 result = Blt_TreeApply(entryPtr->node, SortApplyProc, tvPtr);
1859 } else {
1860 result = SortApplyProc(entryPtr->node, tvPtr, TREE_PREORDER);
1861 }
1862 if (result != TCL_OK) {
1863 return TCL_ERROR;
1864 }
1865 }
1866 tvPtr->flags |= TV_LAYOUT;
1867 Blt_TreeViewEventuallyRedraw(tvPtr);
1868 return TCL_OK;
1869}
1870
1871/*
1872 *----------------------------------------------------------------------
1873 *
1874 * Blt_TreeViewSortOp --
1875 *
1876 * Comparison routine (used by qsort) to sort a chain of subnodes.
1877 * A simple string comparison is performed on each node name.
1878 *
1879 * .h sort auto
1880 * .h sort once -recurse root
1881 *
1882 * Results:
1883 * 1 is the first is greater, -1 is the second is greater, 0
1884 * if equal.
1885 *
1886 *----------------------------------------------------------------------
1887 */
1888static Blt_OpSpec sortOps[] =
1889{
1890 {"auto", 1, (Blt_Op)SortAutoOp, 3, 4, "?boolean?",},
1891 {"cget", 2, (Blt_Op)SortCgetOp, 4, 4, "option",},
1892 {"configure", 2, (Blt_Op)SortConfigureOp, 3, 0, "?option value?...",},
1893 {"once", 1, (Blt_Op)SortOnceOp, 3, 0, "?-recurse? node...",},
1894};
1895static int nSortOps = sizeof(sortOps) / sizeof(Blt_OpSpec);
1896
1897/*ARGSUSED*/
1898int
1899Blt_TreeViewSortOp(tvPtr, interp, objc, objv)
1900 TreeView *tvPtr;
1901 Tcl_Interp *interp; /* Not used. */
1902 int objc;
1903 Tcl_Obj *CONST *objv;
1904{
1905 Blt_Op proc;
1906 int result;
1907
1908 proc = Blt_GetOpFromObj(interp, nSortOps, sortOps, BLT_OP_ARG2, objc,
1909 objv, 0);
1910 if (proc == NULL) {
1911 return TCL_ERROR;
1912 }
1913 result = (*proc) (tvPtr, interp, objc, objv);
1914 return result;
1915}
1916
1917/*
1918 *----------------------------------------------------------------------
1919 *
1920 * SortApplyProc --
1921 *
1922 * Sorts the subnodes at a given node.
1923 *
1924 * Results:
1925 * Always returns TCL_OK.
1926 *
1927 *----------------------------------------------------------------------
1928 */
1929/*ARGSUSED*/
1930static int
1931SortApplyProc(node, clientData, order)
1932 Blt_TreeNode node;
1933 ClientData clientData;
1934 int order; /* Not used. */
1935{
1936 TreeView *tvPtr = clientData;
1937
1938 if (!Blt_TreeIsLeaf(node)) {
1939 Blt_TreeSortNode(tvPtr->tree, node, CompareNodes);
1940 }
1941 return TCL_OK;
1942}
1943
1944/*
1945 *----------------------------------------------------------------------
1946 *
1947 * Blt_TreeViewSortFlatView --
1948 *
1949 * Sorts the flatten array of entries.
1950 *
1951 *----------------------------------------------------------------------
1952 */
1953void
1954Blt_TreeViewSortFlatView(tvPtr)
1955 TreeView *tvPtr;
1956{
1957 TreeViewEntry *entryPtr, **p;
1958
1959 tvPtr->flags &= ~TV_SORT_PENDING;
1960 if ((tvPtr->sortType == SORT_TYPE_NONE) || (tvPtr->sortColumnPtr == NULL) ||
1961 (tvPtr->nEntries == 1)) {
1962 return;
1963 }
1964 if (tvPtr->flags & TV_SORTED) {
1965 int first, last;
1966 TreeViewEntry *hold;
1967
1968 if (tvPtr->sortDecreasing == tvPtr->viewIsDecreasing) {
1969 return;
1970 }
1971
1972 /*
1973 * The view is already sorted but in the wrong direction.
1974 * Reverse the entries in the array.
1975 */
1976 for (first = 0, last = tvPtr->nEntries - 1; last > first;
1977 first++, last--) {
1978 hold = tvPtr->flatArr[first];
1979 tvPtr->flatArr[first] = tvPtr->flatArr[last];
1980 tvPtr->flatArr[last] = hold;
1981 }
1982 tvPtr->viewIsDecreasing = tvPtr->sortDecreasing;
1983 tvPtr->flags |= TV_SORTED | TV_LAYOUT;
1984 return;
1985 }
1986 /* Fetch each entry's data as Tcl_Objs for sorting. */
1987 if (tvPtr->sortColumnPtr == &tvPtr->treeColumn) {
1988 for(p = tvPtr->flatArr; *p != NULL; p++) {
1989 entryPtr = *p;
1990 if (entryPtr->fullName == NULL) {
1991 Tcl_DString dString;
1992
1993 Blt_TreeViewGetFullName(tvPtr, entryPtr, TRUE, &dString);
1994 entryPtr->fullName = Blt_Strdup(Tcl_DStringValue(&dString));
1995 Tcl_DStringFree(&dString);
1996 }
1997 entryPtr->dataObjPtr = Tcl_NewStringObj(entryPtr->fullName, -1);
1998 Tcl_IncrRefCount(entryPtr->dataObjPtr);
1999 }
2000 } else {
2001 Blt_TreeKey key;
2002 Tcl_Obj *objPtr;
2003
2004 key = tvPtr->sortColumnPtr->key;
2005 for(p = tvPtr->flatArr; *p != NULL; p++) {
2006 entryPtr = *p;
2007 if (Blt_TreeViewGetData(entryPtr, key, &objPtr) != TCL_OK) {
2008 objPtr = bltEmptyStringObjPtr;
2009 }
2010 entryPtr->dataObjPtr = objPtr;
2011 Tcl_IncrRefCount(entryPtr->dataObjPtr);
2012 }
2013 }
2014 qsort((char *)tvPtr->flatArr, tvPtr->nEntries, sizeof(TreeViewEntry *),
2015 (QSortCompareProc *)CompareEntries);
2016
2017 /* Free all the Tcl_Objs used for comparison data. */
2018 for(p = tvPtr->flatArr; *p != NULL; p++) {
2019 Tcl_DecrRefCount((*p)->dataObjPtr);
2020 }
2021 tvPtr->viewIsDecreasing = tvPtr->sortDecreasing;
2022 tvPtr->flags |= TV_SORTED;
2023}
2024
2025/*
2026 *----------------------------------------------------------------------
2027 *
2028 * Blt_TreeViewSortTreeView --
2029 *
2030 * Sorts the tree array of entries.
2031 *
2032 *----------------------------------------------------------------------
2033 */
2034void
2035Blt_TreeViewSortTreeView(tvPtr)
2036 TreeView *tvPtr;
2037{
2038 tvPtr->flags &= ~TV_SORT_PENDING;
2039 if ((tvPtr->sortType != SORT_TYPE_NONE) && (tvPtr->sortColumnPtr != NULL)) {
2040 treeViewInstance = tvPtr;
2041 Blt_TreeApply(tvPtr->rootPtr->node, SortApplyProc, tvPtr);
2042 }
2043 tvPtr->viewIsDecreasing = tvPtr->sortDecreasing;
2044}
2045
2046
2047#endif /* NO_TREEVIEW */
Note: See TracBrowser for help on using the repository browser.