1 /** 2 * Widget module. 3 * 4 * License: 5 * MIT. See LICENSE for full details. 6 */ 7 module tkd.widget.treeview; 8 9 /** 10 * Imports. 11 */ 12 import std.algorithm; 13 import std.array; 14 import std.regex; 15 import std.string; 16 import tkd.element.color; 17 import tkd.element.element; 18 import tkd.element.uielement; 19 import tkd.image.image; 20 import tkd.widget.anchorposition; 21 import tkd.widget.common.height; 22 import tkd.widget.common.padding; 23 import tkd.widget.common.xscrollcommand; 24 import tkd.widget.common.yscrollcommand; 25 import tkd.widget.widget; 26 27 /** 28 * The treeview widget displays a hierarchical collection of items. Each item 29 * has a textual label, an optional image, and an optional list of data values. 30 * 31 * There are two varieties of columns. The first is the main tree view column 32 * that is present all the time. The second are data columns that can be added 33 * when needed. 34 * 35 * Each tree item has a list of tags, which can be used to associate event 36 * bindings and control their appearance. Treeview widgets support horizontal 37 * and vertical scrolling with the standard scroll commands. 38 * 39 * Example: 40 * --- 41 * auto treeView = new TreeView() 42 * .setHeading("Text") 43 * .addRow(new TreeViewRow(["row1"])) 44 * .addRow(new TreeViewRow(["row2"])) 45 * .pack(); 46 * --- 47 * 48 * Common_Commands: 49 * These are injected common commands that can also be used with this widget. 50 * $(P 51 * $(LINK2 ./common/height.html, Height) $(BR) 52 * $(LINK2 ./common/padding.html, Padding) $(BR) 53 * $(LINK2 ./common/xscrollcommand.html, XScrollCommand) $(BR) 54 * $(LINK2 ./common/yscrollcommand.html, YScrollCommand) $(BR) 55 * ) 56 * 57 * Additional_Events: 58 * Additional events that can also be bound to using the $(LINK2 ../element/uielement.html#UiElement.bind, bind) method. 59 * $(P 60 * <<PrevWindow>>, 61 * <<TreeviewClose>> 62 * <<TreeviewOpen>> 63 * <<TreeviewSelect>> 64 * <Alt-Key>, 65 * <B1-Leave>, 66 * <B1-Motion>, 67 * <Button-1>, 68 * <Button-4>, 69 * <Button-5>, 70 * <ButtonRelease-1>, 71 * <Control-Button-1>, 72 * <Double-Button-1>, 73 * <Key-Down>, 74 * <Key-F10>, 75 * <Key-Left>, 76 * <Key-Next>, 77 * <Key-Prior>, 78 * <Key-Return>, 79 * <Key-Right>, 80 * <Key-Tab>, 81 * <Key-Up>, 82 * <Key-space>, 83 * <Leave>, 84 * <Motion>, 85 * <Shift-Button-1>, 86 * <Shift-Button-4>, 87 * <Shift-Button-5>, 88 * ) 89 * 90 * See_Also: 91 * $(LINK2 ./widget.html, tkd.widget.widget) 92 */ 93 class TreeView : Widget, IXScrollable!(TreeView), IYScrollable!(TreeView) 94 { 95 /** 96 * An array containing all the columns. 97 */ 98 private TreeViewColumn[] _columns; 99 100 /** 101 * Construct the widget. 102 * 103 * Params: 104 * parent = The parent of this widget. 105 * 106 * See_Also: 107 * $(LINK2 ../element/uielement.html, tkd.element.uielement) $(BR) 108 */ 109 this(UiElement parent = null) 110 { 111 super(parent); 112 this._elementId = "treeview"; 113 114 this._tk.eval("ttk::treeview %s -selectmode browse", this.id); 115 116 // Add the treeview column to the column collection. 117 this._columns ~= new TreeViewColumn(); 118 this._columns[0].init(this); 119 } 120 121 /** 122 * Get the column identifiers of the passed data column indexes. 123 * 124 * Params: 125 * indexex = The indexes of the data columns. 126 * 127 * Returns: 128 * A string array containing the columns relating to the indexes. 129 */ 130 private string[] getDataColumnIdentifiers(int[] indexes) 131 { 132 string[] columns; 133 134 for (int x = 1; x < this._columns.length; x++) 135 { 136 if (indexes.canFind(x)) 137 { 138 columns ~= this._columns[x].id; 139 } 140 } 141 142 return columns; 143 } 144 145 /** 146 * Get all column identifiers. 147 * 148 * Returns: 149 * A string array containing all column identifiers. 150 */ 151 private string[] getDataColumnIdentifiers() 152 { 153 string[] columns; 154 155 for (int x = 1; x < this._columns.length; x++) 156 { 157 columns ~= this._columns[x].id; 158 } 159 160 return columns; 161 } 162 163 /** 164 * Get the tree view elements that are currently being shown. 165 * 166 * Returns: 167 * An array cotaining all shown elements. 168 */ 169 private string[] getShownElements() 170 { 171 this._tk.eval("%s cget -show", this.id); 172 return this._tk.getResult!(string).split(); 173 } 174 175 /** 176 * Build the columns found in the column array. This is needed because the 177 * data columns always seem to forget setting if configured piece-meal. 178 */ 179 private void buildColumns() 180 { 181 this._tk.eval("%s configure -columns { \"%s\" }", this.id, this.getDataColumnIdentifiers().join("\" \"")); 182 183 for (int x = 1; x < this._columns.length; x++) 184 { 185 this.columns[x].init(this); 186 } 187 } 188 189 /** 190 * Convenience method to set the tree column heading text. 191 * 192 * Params: 193 * title = The title of the column. 194 * anchor = The anchor position of the text. 195 * 196 * Returns: 197 * This widget to aid method chaining. 198 * 199 * See_Also: 200 * $(LINK2 ./anchorposition.html, tkd.widget.anchorposition) $(BR) 201 */ 202 public auto setHeading(this T)(string title, string anchor = AnchorPosition.west) 203 { 204 this._columns[0].setHeading(title, anchor); 205 206 return cast(T) this; 207 } 208 209 /** 210 * Convenience method to set the tree column heading image. 211 * 212 * Params: 213 * image = The image to use. 214 * 215 * Returns: 216 * This widget to aid method chaining. 217 */ 218 public auto setHeadingImage(this T)(Image image) 219 { 220 this._columns[0].setHeadingImage(image); 221 222 return cast(T) this; 223 } 224 225 /** 226 * Convenience method to set the tree column command to be executed when 227 * clicking on the heading. 228 * 229 * Params: 230 * callback = The delegate callback to execute when invoking the command. 231 * 232 * Returns: 233 * This widget to aid method chaining. 234 * 235 * Callback_Arguments: 236 * These are the fields within the callback's $(LINK2 237 * ../element/element.html#CommandArgs, CommandArgs) parameter which 238 * are populated by this method when the callback is executed. 239 * $(P 240 * $(PARAM_TABLE 241 * $(PARAM_ROW CommandArgs.element, The tree column.) 242 * $(PARAM_ROW CommandArgs.uniqueData, The internal id of the tree view (An implementation detail that's not very useful).) 243 * $(PARAM_ROW CommandArgs.callback, The callback which was executed.) 244 * ) 245 * ) 246 * 247 * See_Also: 248 * $(LINK2 ../element/element.html#CommandCallback, tkd.element.element.CommandCallback) 249 */ 250 public auto setHeadingCommand(this T)(CommandCallback callback) 251 { 252 this._columns[0].setHeadingCommand(callback); 253 254 return cast(T) this; 255 } 256 257 /** 258 * Convenience method to remove the tree view column command. 259 * 260 * Returns: 261 * This widget to aid method chaining. 262 */ 263 public auto removeHeadingCommand(this T)() 264 { 265 this._columns[0].removeHeadingCommand(); 266 267 return cast(T) this; 268 } 269 270 /** 271 * Convenience method to set the minium width of the tree column. 272 * 273 * Params: 274 * minWidth = The minimum width in pixels. 275 * 276 * Returns: 277 * This widget to aid method chaining. 278 */ 279 public auto setMinWidth(this T)(int minWidth) 280 { 281 this._columns[0].setMinWidth(minWidth); 282 283 return cast(T) this; 284 } 285 286 /** 287 * Convenience method to enable or disable stretching for the tree column. 288 * This controls how this column react when other columns or the parent 289 * widget is resized. 290 * 291 * Params: 292 * stretch = true for enabling stretching, false to disable. 293 * 294 * Returns: 295 * This widget to aid method chaining. 296 */ 297 public auto setStretch(this T)(bool stretch) 298 { 299 this._columns[0].setStretch(stretch); 300 301 return cast(T) this; 302 } 303 304 /** 305 * Convenience method to set the width of the tree column. 306 * 307 * Params: 308 * width = The width in pixels. 309 * 310 * Returns: 311 * This widget to aid method chaining. 312 */ 313 public auto setWidth(this T)(int width) 314 { 315 this._columns[0].setWidth(width); 316 317 return cast(T) this; 318 } 319 320 /** 321 * Add a new column to the tree view. 322 * 323 * Params: 324 * column = The new column to add. 325 * 326 * Returns: 327 * This widget to aid method chaining. 328 */ 329 public auto addColumn(this T)(TreeViewColumn column) 330 { 331 this._columns ~= column; 332 this.buildColumns(); 333 334 return cast(T) this; 335 } 336 337 /** 338 * Add a row to the tree view. 339 * 340 * Params: 341 * row = The row to add. 342 * 343 * Returns: 344 * This widget to aid method chaining. 345 */ 346 public auto addRow(this T)(TreeViewRow row) 347 { 348 this.appendRows("", [row]); 349 350 return cast(T) this; 351 } 352 353 /** 354 * Add an array of rowr to the tree view. 355 * 356 * Params: 357 * rows = The rows to add. 358 * 359 * Returns: 360 * This widget to aid method chaining. 361 */ 362 public auto addRows(this T)(TreeViewRow[] rows) 363 { 364 this.appendRows("", rows); 365 366 return cast(T) this; 367 } 368 369 /** 370 * This method does the actualy work of adding rows to the tree view. 371 * All children are recursed and add too. 372 * 373 * Params: 374 * parentRow = The id of the parent row. Use '{}' for the top level. 375 * rows = The rows to add to the tree view. 376 */ 377 private void appendRows(string parentRow, TreeViewRow[] rows) 378 { 379 string dataValues; 380 string tags; 381 382 foreach (row; rows) 383 { 384 if (row.values.length > 1) 385 { 386 dataValues = format("\"%s\"", row.values[1 .. $].join("\" \"")); 387 } 388 389 if (row.tags.length) 390 { 391 tags = format("\"%s\"", row.tags.join("\" \"")); 392 } 393 394 this._tk.eval("%s insert {%s} end -text {%s} -values {%s} -open %s -tags {%s}", this.id, parentRow, row.values[0], dataValues, row.isOpen, tags); 395 396 row._rowId = this._tk.getResult!(string); 397 398 if (row.children.length) 399 { 400 this.appendRows(row.id, row.children); 401 } 402 } 403 } 404 405 /** 406 * Set the value of a data column, given a row id. Row id's are populated 407 * within a tree view row object once that row has been inserted into the 408 * tree view. 409 * 410 * Params: 411 * rowId = The row id. 412 * columnIndex = The 0-based data column index. 413 * value = The new value. 414 * 415 * Returns: 416 * This widget to aid method chaining. 417 */ 418 public auto updateDataColumn(this T)(string rowId, uint columnIndex, string value) 419 { 420 this._tk.eval("%s set %s %s {%s}", this.id, rowId, columnIndex, value); 421 422 return cast(T) this; 423 } 424 425 /** 426 * Set image and colors for a specific tag. 427 * Use colors from the preset color $(LINK2 ../element/color.html, list) or a web style hex color. 428 * 429 * Params: 430 * name = The name of the tag. 431 * image = The image to associate to the tag. 432 * foreground = The forground color. 433 * background = The background color. 434 * 435 * Returns: 436 * This widget to aid method chaining. 437 * 438 * See_Also: 439 * $(LINK2 ../element/color.html, tkd.widget.color) $(BR) 440 */ 441 public auto setTag(this T)(string name, Image image, string foreground = Color.default_, string background = Color.default_) 442 { 443 this._tk.eval("%s tag configure %s -image %s -foreground {%s} -background {%s}", this.id, name, image.id, foreground, background); 444 445 return cast(T) this; 446 } 447 448 /** 449 * Get the columns. 450 * 451 * Returns: 452 * An array containing all the data columns. 453 */ 454 public @property TreeViewColumn[] columns() 455 { 456 return this._columns; 457 } 458 459 /** 460 * Show all data columns in the event some or all are hidden. 461 * 462 * Returns: 463 * This widget to aid method chaining. 464 */ 465 public auto displayAllDataColumns(this T)() 466 { 467 this._tk.eval("%s configure -displaycolumns #all", this.id); 468 469 return cast(T) this; 470 } 471 472 /** 473 * Show the data columns that relate to the indexes passed. 474 * 475 * Params: 476 * indexes = The indexes of the data columns to show. 477 * 478 * Returns: 479 * This widget to aid method chaining. 480 */ 481 public auto displayDataColumns(this T)(int[] indexes) 482 { 483 this._tk.eval("%s configure -displaycolumns {\"%s\"}", this.id, this.getDataColumnIdentifiers(indexes).join("\" \"")); 484 485 return cast(T) this; 486 } 487 488 /** 489 * Set the selection mode. 490 * 491 * Params: 492 * mode = The mode of the selection. 493 * 494 * Returns: 495 * This widget to aid method chaining. 496 * 497 * See_Also: 498 * $(LINK2 ./treeview.html#TreeViewSelectionMode, tkd.widget.treeview.TreeViewSelectionMode) $(BR) 499 */ 500 public auto setSelectionMode(this T)(string mode) 501 { 502 this._tk.eval("%s configure -selectmode %s", this.id, mode); 503 504 return cast(T) this; 505 } 506 507 /** 508 * Hide the headings from all columns. 509 * 510 * Returns: 511 * This widget to aid method chaining. 512 */ 513 public auto hideHeadings(this T)() 514 { 515 this._tk.eval("%s configure -show { %s }", this.id, this.getShownElements() 516 .remove!(x => x == "headings") 517 .join(" ") 518 ); 519 520 return cast(T) this; 521 } 522 523 /** 524 * Show the headings for all columns. 525 * 526 * Returns: 527 * This widget to aid method chaining. 528 */ 529 public auto showHeadings(this T)() 530 { 531 string[] elements = this.getShownElements(); 532 elements ~= "headings"; 533 534 this._tk.eval("%s configure -show { %s }", this.id, elements.join(" ")); 535 536 return cast(T) this; 537 } 538 539 /** 540 * Hide the tree view column. 541 * 542 * Returns: 543 * This widget to aid method chaining. 544 */ 545 public auto hideTreeColumn(this T)() 546 { 547 this._tk.eval("%s configure -show { %s }", this.id, this.getShownElements() 548 .remove!(x => x == "tree") 549 .join(" ") 550 ); 551 552 return cast(T) this; 553 } 554 555 /** 556 * Show the tree view column. 557 * 558 * Returns: 559 * This widget to aid method chaining. 560 */ 561 public auto showTreeColumn(this T)() 562 { 563 string[] elements = this.getShownElements(); 564 elements ~= "tree"; 565 566 this._tk.eval("%s configure -show { %s }", this.id, elements.join(" ")); 567 568 return cast(T) this; 569 } 570 571 /** 572 * Construct a row object from a row id. 573 * 574 * Params: 575 * rowId = The id of the row to construct. 576 * 577 * Returns: 578 * A tree view row. 579 */ 580 private TreeViewRow getRowFromId(string rowId) 581 { 582 auto row = new TreeViewRow(); 583 584 this._tk.eval("%s item %s -text", this.id, rowId); 585 row._values ~= this._tk.getResult!(string); 586 587 this._tk.eval("%s item %s -values", this.id, rowId); 588 auto results = matchAll(this._tk.getResult!(string), "\"(.*?)\""); 589 foreach (result; results) 590 { 591 row._values ~= result.captures[1]; 592 } 593 594 this._tk.eval("%s item %s -open", this.id, rowId); 595 row._isOpen = this._tk.getResult!(bool); 596 597 this._tk.eval("%s item %s -tags", this.id, rowId); 598 results = matchAll(this._tk.getResult!(string), "\"(.*?)\""); 599 foreach (result; results) 600 { 601 row._tags ~= result.captures[1]; 602 } 603 604 return row; 605 } 606 607 /** 608 * Populate row objects and return them. 609 * 610 * Params: 611 * rows = An array to append the rows to. 612 * includeChildren = Specifies whether or not to include the children. 613 * 614 * Returns: 615 * AN array of tree view rows. 616 */ 617 private TreeViewRow[] populateRows(string[] rowIds, bool includeChildren) 618 { 619 TreeViewRow[] rows; 620 TreeViewRow currentRow; 621 622 foreach (rowId; rowIds) 623 { 624 currentRow = this.getRowFromId(rowId); 625 626 if (includeChildren) 627 { 628 this._tk.eval("%s children %s", this.id, rowId); 629 currentRow.children = this.populateRows(this._tk.getResult!(string).split(), includeChildren); 630 } 631 632 rows ~= currentRow; 633 } 634 635 return rows; 636 } 637 638 /** 639 * Get the row(s) selected in the tree view. 640 * 641 * Params: 642 * includeChildren = Specifies whether or not to include the children. 643 * 644 * Returns: 645 * An array containing the selected rows. 646 */ 647 public TreeViewRow[] getSelectedRows(bool includeChildren = false) 648 { 649 this._tk.eval("%s selection", this.id); 650 string[] rowIds = this._tk.getResult!(string).split(); 651 652 return this.populateRows(rowIds, includeChildren); 653 } 654 655 /** 656 * Delete all rows in the widget. 657 * 658 * Returns: 659 * This widget to aid method chaining. 660 */ 661 public auto deleteRows() 662 { 663 this._tk.eval("%s children {}", this.id); 664 this._tk.eval("%s delete {%s}", this.id, this._tk.getResult!(string)); 665 } 666 667 /** 668 * Mixin common commands. 669 */ 670 mixin Height; 671 mixin Padding; 672 mixin XScrollCommand!(TreeView); 673 mixin YScrollCommand!(TreeView); 674 } 675 676 /** 677 * A class representing a column in the tree view. 678 */ 679 class TreeViewColumn : Element 680 { 681 /** 682 * The parent of this column. 683 */ 684 private TreeView _parent; 685 686 /** 687 * The title of the heading. 688 */ 689 private string _title; 690 691 /** 692 * The anchor position of the heading title. 693 */ 694 private string _anchor = AnchorPosition.west; 695 696 /** 697 * The image of the heading. 698 */ 699 private Image _image; 700 701 /** 702 * The minimum width of the column. 703 */ 704 private int _minWidth = 20; 705 706 /** 707 * Whether to alter the size of the column when the widget is resized. 708 */ 709 private bool _stretch = true; 710 711 /** 712 * Width of the column. 713 */ 714 private int _width = 200; 715 716 /** 717 * The command associated with the heading. 718 */ 719 private CommandCallback _commandCallback; 720 721 /** 722 * Construct a new column to add the treeview column to the column 723 * collection. 724 * 725 * '#0' is the built-in Tcl/Tk display id of the tree view column. 726 * This allows access to this column even if it wasn't created by us. 727 */ 728 private this() 729 { 730 super(); 731 this.overrideGeneratedId("#0"); 732 } 733 734 /** 735 * Construct a new column. 736 * 737 * Params: 738 * title = The optional title of the heading. 739 * anchor = The anchor position of the heading title. 740 */ 741 public this(string title = null, string anchor = AnchorPosition.west) 742 { 743 this._elementId = "column"; 744 this.setHeading(title, anchor); 745 } 746 747 /** 748 * Initialise the column and attach to a parent. 749 * 750 * Params: 751 * parent = The parent tree view. 752 */ 753 private void init(TreeView parent) 754 { 755 this._parent = parent; 756 757 this.setHeading(this._title, this._anchor); 758 this.setHeadingImage(this._image); 759 this.setHeadingCommand(this._commandCallback); 760 this.setMinWidth(this._minWidth); 761 this.setStretch(this._stretch); 762 this.setWidth(this._width); 763 } 764 765 /** 766 * Set the heading title. 767 * 768 * Params: 769 * title = The title of the column. 770 * anchor = The anchor position of the text. 771 * 772 * Returns: 773 * This column to aid method chaining. 774 * 775 * See_Also: 776 * $(LINK2 ./anchorposition.html, tkd.widget.anchorposition) $(BR) 777 */ 778 public auto setHeading(this T)(string title, string anchor = AnchorPosition.west) 779 { 780 this._title = title; 781 this._anchor = anchor; 782 783 if (this._parent) 784 { 785 this._tk.eval("%s heading %s -text {%s} -anchor %s", this._parent.id, this.id, this._title, this._anchor); 786 } 787 788 return cast(T) this; 789 } 790 791 /** 792 * Set the heading image. 793 * 794 * Params: 795 * image = The image to use. 796 * 797 * Returns: 798 * This column to aid method chaining. 799 */ 800 public auto setHeadingImage(this T)(Image image) 801 { 802 this._image = image; 803 804 if (this._parent && this._image) 805 { 806 this._tk.eval("%s heading %s -text {%s} -anchor %s -image %s", this._parent.id, this.id, this._title, this._anchor, image.id); 807 } 808 809 return cast(T) this; 810 } 811 812 /** 813 * Set the column command to be executed when clicking on the heading. 814 * 815 * Params: 816 * callback = The delegate callback to execute when invoking the command. 817 * 818 * Returns: 819 * This widget to aid method chaining. 820 * 821 * Callback_Arguments: 822 * These are the fields within the callback's $(LINK2 823 * ../element/element.html#CommandArgs, CommandArgs) parameter which 824 * are populated by this method when the callback is executed. 825 * $(P 826 * $(PARAM_TABLE 827 * $(PARAM_ROW CommandArgs.element, The column that executed the callback.) 828 * $(PARAM_ROW CommandArgs.uniqueData, The internal id of the tree view (An implementation detail that's not very useful).) 829 * $(PARAM_ROW CommandArgs.callback, The callback which was executed.) 830 * ) 831 * ) 832 * 833 * See_Also: 834 * $(LINK2 ../element/element.html#CommandCallback, tkd.element.element.CommandCallback) 835 */ 836 public auto setHeadingCommand(this T)(CommandCallback callback) 837 { 838 this._commandCallback = callback; 839 840 if (this._parent && this._commandCallback) 841 { 842 string command = this.createCommand(callback, this._parent.id); 843 this._tk.eval("%s heading %s -command %s", this._parent.id, this.id, command); 844 } 845 846 return cast(T) this; 847 } 848 849 /** 850 * Remove the column command. 851 * 852 * Returns: 853 * This widget to aid method chaining. 854 */ 855 public auto removeHeadingCommand(this T)() 856 { 857 if (this._parent && this._commandCallback) 858 { 859 this._tk.deleteCommand(this.getCommandName(this._parent.id)); 860 this._tk.eval("%s heading %s -command {}", this._parent.id, this.id); 861 } 862 863 return cast(T) this; 864 } 865 866 /** 867 * Set the minium width of the column. 868 * 869 * Params: 870 * minWidth = The minimum width in pixels. 871 * 872 * Returns: 873 * This widget to aid method chaining. 874 */ 875 public auto setMinWidth(this T)(int minWidth) 876 { 877 this._minWidth = minWidth; 878 879 if (this._parent) 880 { 881 this._tk.eval("%s column %s -minwidth %s", this._parent.id, this.id, this._minWidth); 882 } 883 884 return cast(T) this; 885 } 886 887 /** 888 * Enable or disable stretching for the column. This controls how this 889 * column react when other columns or the parent widget is resized. 890 * 891 * Params: 892 * stretch = true for enabling stretching, false to disable. 893 * 894 * Returns: 895 * This widget to aid method chaining. 896 */ 897 public auto setStretch(this T)(bool stretch) 898 { 899 this._stretch = stretch; 900 901 if (this._parent) 902 { 903 this._tk.eval("%s column %s -stretch %s", this._parent.id, this.id, this._stretch); 904 } 905 906 return cast(T) this; 907 } 908 909 /** 910 * Set the width of the column. 911 * 912 * Params: 913 * width = The width in pixels. 914 * 915 * Returns: 916 * This widget to aid method chaining. 917 */ 918 public auto setWidth(this T)(int width) 919 { 920 this._width = width; 921 922 if (this._parent) 923 { 924 this._tk.eval("%s column %s -width %s", this._parent.id, this.id, this._width); 925 } 926 927 return cast(T) this; 928 } 929 } 930 931 /** 932 * A class representing a row in the tree view. 933 */ 934 class TreeViewRow 935 { 936 /** 937 * The row id. This is populated by the treeview once the row has been 938 * inserted. 939 */ 940 private string _rowId; 941 942 /** 943 * An array containing the column values. 944 */ 945 private string[] _values; 946 947 /** 948 * Boolean representing if the row was set to be open when created. 949 */ 950 private bool _isOpen; 951 952 /** 953 * An array containing the tags. 954 */ 955 private string[] _tags; 956 957 /** 958 * An array containing the child rows. 959 */ 960 public TreeViewRow[] children; 961 962 /** 963 * Constructor. 964 */ 965 private this() 966 { 967 } 968 969 /** 970 * Constructor. 971 * 972 * Params: 973 * values = The values of the columns. 974 * isOpen = Whether or not to display the row open. 975 * tags = The tags to associate to this row. 976 */ 977 public this(string[] values, bool isOpen = false, string[] tags = []) 978 { 979 assert(values.length, "There must be at least 1 value in the row."); 980 981 this._values = values; 982 this._isOpen = isOpen; 983 this._tags = tags; 984 } 985 986 /** 987 * Get the row id. This is populated by the treeview once the row has been 988 * inserted. 989 * 990 * Returns: 991 * A string containing the row id. 992 */ 993 public @property string id() 994 { 995 return this._rowId; 996 } 997 998 /** 999 * Get the data column values. 1000 * 1001 * Returns: 1002 * An array containing the data values. 1003 */ 1004 public @property string[] values() 1005 { 1006 return this._values; 1007 } 1008 1009 /** 1010 * Get if the row was open. 1011 * 1012 * Returns: 1013 * true if the row was set to be open, false if not. 1014 */ 1015 public @property bool isOpen() 1016 { 1017 return this._isOpen; 1018 } 1019 1020 /** 1021 * Get the tags. 1022 * 1023 * Returns: 1024 * An array of tags assocaited to this row. 1025 */ 1026 public @property string[] tags() 1027 { 1028 return this._tags; 1029 } 1030 1031 /** 1032 * String representation. 1033 */ 1034 debug override public string toString() 1035 { 1036 return format("Row Id: %s, Values: %s, isOpen: %s, Tags: %s, Children: %s", this.id, this.values, this.isOpen, this.tags, this.children); 1037 } 1038 } 1039 1040 /** 1041 * Tree view selection modes. 1042 */ 1043 enum TreeViewSelectionMode : string 1044 { 1045 browse = "browse", /// The default mode, allows one selection only. 1046 extended = "extended", /// Allows multiple selections to be made. 1047 none = "none", /// Disabled all selection. 1048 }