2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
32 import jexer
.THScroller
;
33 import jexer
.TKeypress
;
34 import jexer
.TScrollableWidget
;
35 import jexer
.TVScroller
;
37 import jexer
.bits
.StringUtils
;
38 import jexer
.event
.TKeypressEvent
;
39 import jexer
.event
.TMouseEvent
;
40 import static jexer
.TKeypress
.*;
43 * TTreeViewWidget wraps a tree view with horizontal and vertical scrollbars.
45 public class TTreeViewWidget
extends TScrollableWidget
{
47 // ------------------------------------------------------------------------
48 // Variables --------------------------------------------------------------
49 // ------------------------------------------------------------------------
54 private TTreeView treeView
;
57 * If true, move the window to put the selected item in view. This
58 * normally only happens once after setting treeRoot.
60 private boolean centerWindow
= false;
63 * Maximum width of a single line.
65 private int maxLineWidth
;
67 // ------------------------------------------------------------------------
68 // Constructors -----------------------------------------------------------
69 // ------------------------------------------------------------------------
74 * @param parent parent widget
75 * @param x column relative to parent
76 * @param y row relative to parent
77 * @param width width of tree view
78 * @param height height of tree view
80 public TTreeViewWidget(final TWidget parent
, final int x
, final int y
,
81 final int width
, final int height
) {
83 this(parent
, x
, y
, width
, height
, null);
89 * @param parent parent widget
90 * @param x column relative to parent
91 * @param y row relative to parent
92 * @param width width of tree view
93 * @param height height of tree view
94 * @param action action to perform when an item is selected
96 public TTreeViewWidget(final TWidget parent
, final int x
, final int y
,
97 final int width
, final int height
, final TAction action
) {
99 super(parent
, x
, y
, width
, height
);
101 treeView
= new TTreeView(this, 0, 0, getWidth() - 1, getHeight() - 1,
104 vScroller
= new TVScroller(this, getWidth() - 1, 0, getHeight() - 1);
105 hScroller
= new THScroller(this, 0, getHeight() - 1, getWidth() - 1);
109 // ------------------------------------------------------------------------
110 // Event handlers ---------------------------------------------------------
111 // ------------------------------------------------------------------------
114 * Handle mouse press events.
116 * @param mouse mouse button press event
119 public void onMouseDown(final TMouseEvent mouse
) {
120 if (mouse
.isMouseWheelUp()) {
122 } else if (mouse
.isMouseWheelDown()) {
125 // Pass to the TreeView or scrollbars
126 super.onMouseDown(mouse
);
129 // Update the view to reflect the new scrollbar positions
130 treeView
.setTopLine(getVerticalValue());
131 treeView
.setLeftColumn(getHorizontalValue());
136 * Handle mouse release events.
138 * @param mouse mouse button release event
141 public void onMouseUp(final TMouseEvent mouse
) {
142 // Pass to the TreeView or scrollbars
143 super.onMouseUp(mouse
);
145 // Update the view to reflect the new scrollbar positions
146 treeView
.setTopLine(getVerticalValue());
147 treeView
.setLeftColumn(getHorizontalValue());
152 * Handle mouse motion events.
154 * @param mouse mouse motion event
157 public void onMouseMotion(final TMouseEvent mouse
) {
158 // Pass to the TreeView or scrollbars
159 super.onMouseMotion(mouse
);
161 // Update the view to reflect the new scrollbar positions
162 treeView
.setTopLine(getVerticalValue());
163 treeView
.setLeftColumn(getHorizontalValue());
170 * @param keypress keystroke event
173 public void onKeypress(final TKeypressEvent keypress
) {
174 if (keypress
.equals(kbShiftLeft
)
175 || keypress
.equals(kbCtrlLeft
)
176 || keypress
.equals(kbAltLeft
)
178 horizontalDecrement();
179 } else if (keypress
.equals(kbShiftRight
)
180 || keypress
.equals(kbCtrlRight
)
181 || keypress
.equals(kbAltRight
)
183 horizontalIncrement();
184 } else if (keypress
.equals(kbShiftUp
)
185 || keypress
.equals(kbCtrlUp
)
186 || keypress
.equals(kbAltUp
)
189 } else if (keypress
.equals(kbShiftDown
)
190 || keypress
.equals(kbCtrlDown
)
191 || keypress
.equals(kbAltDown
)
194 } else if (keypress
.equals(kbShiftPgUp
)
195 || keypress
.equals(kbCtrlPgUp
)
196 || keypress
.equals(kbAltPgUp
)
198 bigVerticalDecrement();
199 } else if (keypress
.equals(kbShiftPgDn
)
200 || keypress
.equals(kbCtrlPgDn
)
201 || keypress
.equals(kbAltPgDn
)
203 bigVerticalIncrement();
204 } else if (keypress
.equals(kbPgDn
)) {
205 for (int i
= 0; i
< getHeight() - 2; i
++) {
206 treeView
.onKeypress(new TKeypressEvent(TKeypress
.kbDown
));
210 } else if (keypress
.equals(kbPgUp
)) {
211 for (int i
= 0; i
< getHeight() - 2; i
++) {
212 treeView
.onKeypress(new TKeypressEvent(TKeypress
.kbUp
));
216 } else if (keypress
.equals(kbHome
)) {
217 treeView
.setSelected((TTreeItem
) treeView
.getChildren().get(0),
219 treeView
.setTopLine(0);
222 } else if (keypress
.equals(kbEnd
)) {
223 treeView
.setSelected((TTreeItem
) treeView
.getChildren().get(
224 treeView
.getChildren().size() - 1), true);
227 } else if (keypress
.equals(kbTab
)) {
228 getParent().switchWidget(true);
230 } else if (keypress
.equals(kbShiftTab
)
231 || keypress
.equals(kbBackTab
)) {
232 getParent().switchWidget(false);
235 treeView
.onKeypress(keypress
);
237 // Update the scrollbars to reflect the new data position
242 // Update the view to reflect the new scrollbar position
243 treeView
.setTopLine(getVerticalValue());
244 treeView
.setLeftColumn(getHorizontalValue());
248 // ------------------------------------------------------------------------
249 // TScrollableWidget ------------------------------------------------------
250 // ------------------------------------------------------------------------
253 * Resize text and scrollbars for a new width/height.
256 public void reflowData() {
258 boolean foundSelectedRow
= false;
260 // Reset the keyboard list, expandTree() will recreate it.
261 for (TWidget widget
: treeView
.getChildren()) {
262 TTreeItem item
= (TTreeItem
) widget
;
263 item
.keyboardPrevious
= null;
264 item
.keyboardNext
= null;
267 // Expand the tree into a linear list
268 treeView
.getChildren().clear();
269 treeView
.getChildren().addAll(treeView
.getTreeRoot().expandTree("",
272 // Locate the selected row and maximum line width
273 for (TWidget widget
: treeView
.getChildren()) {
274 TTreeItem item
= (TTreeItem
) widget
;
276 if (item
== treeView
.getSelected()) {
277 foundSelectedRow
= true;
279 if (!foundSelectedRow
) {
283 int lineWidth
= StringUtils
.width(item
.getText())
284 + item
.getPrefix().length() + 4;
285 if (lineWidth
> maxLineWidth
) {
286 maxLineWidth
= lineWidth
;
290 if ((centerWindow
) && (foundSelectedRow
)) {
291 if ((selectedRow
< getVerticalValue())
292 || (selectedRow
> getVerticalValue() + getHeight() - 2)
294 treeView
.setTopLine(selectedRow
);
295 centerWindow
= false;
298 treeView
.alignTree();
300 // Rescale the scroll bars
301 setVerticalValue(treeView
.getTopLine());
302 setBottomValue(treeView
.getTotalLineCount() - (getHeight() - 1));
303 if (getBottomValue() < getTopValue()) {
304 setBottomValue(getTopValue());
306 if (getVerticalValue() > getBottomValue()) {
307 setVerticalValue(getBottomValue());
309 setRightValue(maxLineWidth
- 2);
310 if (getHorizontalValue() > getRightValue()) {
311 setHorizontalValue(getRightValue());
316 // ------------------------------------------------------------------------
317 // TTreeView --------------------------------------------------------------
318 // ------------------------------------------------------------------------
321 * Get the underlying TTreeView.
323 * @return the TTreeView
325 public TTreeView
getTreeView() {
330 * Get the root of the tree.
332 * @return the root of the tree
334 public final TTreeItem
getTreeRoot() {
335 return treeView
.getTreeRoot();
339 * Set the root of the tree.
341 * @param treeRoot the new root of the tree
343 public final void setTreeRoot(final TTreeItem treeRoot
) {
344 treeView
.setTreeRoot(treeRoot
);
350 * @param treeRoot ultimate root of tree
351 * @param centerWindow if true, move the window to put the root in view
353 public void setTreeRoot(final TTreeItem treeRoot
,
354 final boolean centerWindow
) {
356 treeView
.setTreeRoot(treeRoot
);
357 this.centerWindow
= centerWindow
;
361 * Get the tree view item that was selected.
363 * @return the selected item, or null if no item is selected
365 public final TTreeItem
getSelected() {
366 return treeView
.getSelected();
370 * Set the new selected tree view item.
372 * @param item new item that became selected
373 * @param centerWindow if true, move the window to put the selected into
376 public void setSelected(final TTreeItem item
, final boolean centerWindow
) {
377 treeView
.setSelected(item
, centerWindow
);
381 * Perform user selection action.
383 public void dispatch() {