2 * Jexer - Java Text User Interface
4 * License: LGPLv3 or later
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
10 * Copyright (C) 2015 Kevin Lamonte
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
33 import java
.util
.ArrayList
;
34 import java
.util
.List
;
36 import jexer
.bits
.CellAttributes
;
37 import jexer
.bits
.GraphicsChars
;
38 import jexer
.event
.TKeypressEvent
;
39 import jexer
.event
.TMouseEvent
;
40 import static jexer
.TKeypress
.*;
43 * TTreeItem is a single item in a tree view.
45 public class TTreeItem
extends TWidget
{
48 * Hang onto reference to my parent TTreeView so I can call its reflow()
49 * when I add a child node.
51 private TTreeView view
;
54 * Get the parent TTreeView.
56 * @return the parent TTreeView
58 public final TTreeView
getTreeView() {
63 * Displayable text for this item.
68 * Get the displayable text for this item.
70 * @return the displayable text for this item
72 public final String
getText() {
77 * Set the displayable text for this item.
79 * @param the displayable text for this item
81 public final void setText(final String text
) {
86 * If true, this item is expanded in the tree view.
88 private boolean expanded
= true;
93 * @return if true, this item is expanded
95 public final boolean isExpanded() {
100 * Set expanded value.
102 * @param expanded new value
104 public final void setExpanded(boolean expanded
) {
105 this.expanded
= expanded
;
109 * If true, this item can be expanded in the tree view.
111 private boolean expandable
= false;
114 * Get expandable value.
116 * @return if true, this item is expandable
118 public final boolean isExpandable() {
123 * Set expandable value.
125 * @param expandable new value
127 public final void setExpandable(boolean expandable
) {
128 this.expandable
= expandable
;
132 * The vertical bars and such along the left side.
134 private String prefix
= "";
137 * Get the vertical bars and such along the left side.
139 * @return the vertical bars and such along the left side
141 public final String
getPrefix() {
146 * Whether or not this item is last in its parent's list of children.
148 private boolean last
= false;
151 * Tree level. Note package private access.
156 * If true, this item will not be drawn.
158 private boolean invisible
= false;
161 * Set invisible value.
163 * @param invisible new value
165 public final void setInvisible(boolean invisible
) {
166 this.invisible
= invisible
;
170 * True means selected.
172 private boolean selected
= false;
175 * Get selected value.
177 * @return if true, this item is selected
179 public final boolean isSelected() {
184 * Set selected value.
186 * @param selected new value
188 public final void setSelected(boolean selected
) {
189 this.selected
= selected
;
193 * True means select-able.
195 private boolean selectable
= true;
198 * Set selectable value.
200 * @param selectable new value
202 public final void setSelectable(boolean selectable
) {
203 this.selectable
= selectable
;
207 * Pointer to the previous keyboard-navigable item (kbUp). Note package
210 TTreeItem keyboardPrevious
= null;
213 * Pointer to the next keyboard-navigable item (kbDown). Note package
216 TTreeItem keyboardNext
= null;
219 * Public constructor.
221 * @param view root TTreeView
222 * @param text text for this item
223 * @param expanded if true, have it expanded immediately
225 public TTreeItem(final TTreeView view
, final String text
,
226 final boolean expanded
) {
228 super(view
, 0, 0, view
.getWidth() - 3, 1);
230 this.expanded
= expanded
;
233 if (view
.getTreeRoot() == null) {
234 view
.setTreeRoot(this, true);
243 * @param text text for this item
244 * @return the new child item
246 public TTreeItem
addChild(final String text
) {
247 return addChild(text
, true);
253 * @param text text for this item
254 * @param expanded if true, have it expanded immediately
255 * @return the new child item
257 public TTreeItem
addChild(final String text
, final boolean expanded
) {
258 TTreeItem item
= new TTreeItem(view
, text
, expanded
);
259 item
.level
= this.level
+ 1;
260 getChildren().add(item
);
266 * Recursively expand the tree into a linear array of items.
268 * @param prefix = vertical bar of parent levels and such that is set on
270 * @param last = if true, this is the "last" leaf node of a tree
271 * @param additional items to add to the array
273 public List
<TTreeItem
> expandTree(final String prefix
, final boolean last
) {
274 List
<TTreeItem
> array
= new ArrayList
<TTreeItem
>();
276 this.prefix
= prefix
;
279 if ((getChildren().size() == 0) || (expanded
== false)) {
283 String newPrefix
= prefix
;
288 newPrefix
+= GraphicsChars
.CP437
[0xB3];
292 for (int i
= 0; i
< getChildren().size(); i
++) {
293 TTreeItem item
= (TTreeItem
) getChildren().get(i
);
294 if (i
== getChildren().size() - 1) {
295 array
.addAll(item
.expandTree(newPrefix
, true));
297 array
.addAll(item
.expandTree(newPrefix
, false));
304 * Get the x spot for the + or - to expand/collapse.
306 * @return column of the expand/collapse button
308 private int getExpanderX() {
309 if ((level
== 0) || (!expandable
)) {
312 return prefix
.length() + 3;
316 * Recursively unselect my or my children.
318 public void unselect() {
319 if (selected
== true) {
321 view
.setSelected(null);
323 for (TWidget widget
: getChildren()) {
324 if (widget
instanceof TTreeItem
) {
325 TTreeItem item
= (TTreeItem
) widget
;
332 * Handle mouse release events.
334 * @param mouse mouse button release event
337 public void onMouseUp(final TMouseEvent mouse
) {
338 if ((mouse
.getX() == (getExpanderX() - view
.getHScroller().getValue()))
339 && (mouse
.getY() == 0)
342 // Flip expanded flag
343 expanded
= !expanded
;
344 if (expanded
== false) {
345 // Unselect children that became invisible
349 // Let subclasses do something with this
351 } else if (mouse
.getY() == 0) {
352 view
.setSelected(this);
356 // Update the screen after any thing has expanded/contracted
361 * Called when this item is expanded or collapsed. this.expanded will be
362 * true if this item was just expanded from a mouse click or keypress.
364 public void onExpand() {
365 // Default: do nothing.
374 * @param keypress keystroke event
377 public void onKeypress(final TKeypressEvent keypress
) {
378 if (keypress
.equals(kbLeft
)
379 || keypress
.equals(kbRight
)
380 || keypress
.equals(kbSpace
)
383 // Flip expanded flag
384 expanded
= !expanded
;
385 if (expanded
== false) {
386 // Unselect children that became invisible
389 view
.setSelected(this);
391 // Let subclasses do something with this
394 // Pass other keys (tab etc.) on to TWidget's handler.
395 super.onKeypress(keypress
);
400 * Draw this item to a window.
408 int offset
= -view
.getHScroller().getValue();
410 CellAttributes color
= getTheme().getColor("ttreeview");
411 CellAttributes textColor
= getTheme().getColor("ttreeview");
412 CellAttributes expanderColor
= getTheme().getColor("ttreeview.expandbutton");
413 CellAttributes selectedColor
= getTheme().getColor("ttreeview.selected");
415 if (!getParent().isAbsoluteActive()) {
416 color
= getTheme().getColor("ttreeview.inactive");
417 textColor
= getTheme().getColor("ttreeview.inactive");
421 textColor
= getTheme().getColor("ttreeview.unreadable");
424 // Blank out the background
425 getScreen().hLineXY(0, 0, getWidth(), ' ', color
);
427 String line
= prefix
;
430 line
+= GraphicsChars
.CP437
[0xC0];
432 line
+= GraphicsChars
.CP437
[0xC3];
434 line
+= GraphicsChars
.CP437
[0xC4];
439 getScreen().putStringXY(offset
, 0, line
, color
);
441 getScreen().putStringXY(offset
+ line
.length(), 0, text
,
444 getScreen().putStringXY(offset
+ line
.length(), 0, text
, textColor
);
446 if ((level
> 0) && (expandable
)) {
448 getScreen().putCharXY(offset
+ getExpanderX(), 0, '-',
451 getScreen().putCharXY(offset
+ getExpanderX(), 0, '+',