X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Fttree%2FTTreeViewWidget.java;fp=src%2Fjexer%2Fttree%2FTTreeViewWidget.java;h=080a200497dfbe5389a8f62f3593688eb325fb72;hb=12b90437b5f22c2ae6e9b9b14c3b62b60f6143e5;hp=0000000000000000000000000000000000000000;hpb=b709b36e17eb8807819e51297bb398ef28ece52d;p=fanfix.git diff --git a/src/jexer/ttree/TTreeViewWidget.java b/src/jexer/ttree/TTreeViewWidget.java new file mode 100644 index 0000000..080a200 --- /dev/null +++ b/src/jexer/ttree/TTreeViewWidget.java @@ -0,0 +1,406 @@ +/* + * Jexer - Java Text User Interface + * + * The MIT License (MIT) + * + * Copyright (C) 2019 Kevin Lamonte + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 + */ +package jexer.ttree; + +import jexer.TAction; +import jexer.THScroller; +import jexer.TKeypress; +import jexer.TScrollableWidget; +import jexer.TVScroller; +import jexer.TWidget; +import jexer.bits.StringUtils; +import jexer.event.TKeypressEvent; +import jexer.event.TMouseEvent; +import jexer.event.TResizeEvent; +import static jexer.TKeypress.*; + +/** + * TTreeViewWidget wraps a tree view with horizontal and vertical scrollbars. + */ +public class TTreeViewWidget extends TScrollableWidget { + + // ------------------------------------------------------------------------ + // Variables -------------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * The TTreeView + */ + private TTreeView treeView; + + /** + * If true, move the window to put the selected item in view. This + * normally only happens once after setting treeRoot. + */ + private boolean centerWindow = false; + + /** + * Maximum width of a single line. + */ + private int maxLineWidth; + + // ------------------------------------------------------------------------ + // Constructors ----------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Public constructor. + * + * @param parent parent widget + * @param x column relative to parent + * @param y row relative to parent + * @param width width of tree view + * @param height height of tree view + */ + public TTreeViewWidget(final TWidget parent, final int x, final int y, + final int width, final int height) { + + this(parent, x, y, width, height, null); + } + + /** + * Public constructor. + * + * @param parent parent widget + * @param x column relative to parent + * @param y row relative to parent + * @param width width of tree view + * @param height height of tree view + * @param action action to perform when an item is selected + */ + public TTreeViewWidget(final TWidget parent, final int x, final int y, + final int width, final int height, final TAction action) { + + super(parent, x, y, width, height); + + treeView = new TTreeView(this, 0, 0, getWidth() - 1, getHeight() - 1, + action); + + vScroller = new TVScroller(this, getWidth() - 1, 0, getHeight() - 1); + hScroller = new THScroller(this, 0, getHeight() - 1, getWidth() - 1); + + } + + // ------------------------------------------------------------------------ + // Event handlers --------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Handle window/screen resize events. + * + * @param event resize event + */ + @Override + public void onResize(final TResizeEvent event) { + super.onResize(event); + + if (event.getType() == TResizeEvent.Type.WIDGET) { + treeView.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET, + getWidth() - 1, getHeight() - 1)); + return; + } else { + super.onResize(event); + } + } + + /** + * Handle mouse press events. + * + * @param mouse mouse button press event + */ + @Override + public void onMouseDown(final TMouseEvent mouse) { + if (mouse.isMouseWheelUp()) { + verticalDecrement(); + } else if (mouse.isMouseWheelDown()) { + verticalIncrement(); + } else { + // Pass to the TreeView or scrollbars + super.onMouseDown(mouse); + } + + // Update the view to reflect the new scrollbar positions + treeView.setTopLine(getVerticalValue()); + treeView.setLeftColumn(getHorizontalValue()); + reflowData(); + } + + /** + * Handle mouse release events. + * + * @param mouse mouse button release event + */ + @Override + public void onMouseUp(final TMouseEvent mouse) { + // Pass to the TreeView or scrollbars + super.onMouseUp(mouse); + + // Update the view to reflect the new scrollbar positions + treeView.setTopLine(getVerticalValue()); + treeView.setLeftColumn(getHorizontalValue()); + reflowData(); + } + + /** + * Handle mouse motion events. + * + * @param mouse mouse motion event + */ + @Override + public void onMouseMotion(final TMouseEvent mouse) { + // Pass to the TreeView or scrollbars + super.onMouseMotion(mouse); + + // Update the view to reflect the new scrollbar positions + treeView.setTopLine(getVerticalValue()); + treeView.setLeftColumn(getHorizontalValue()); + reflowData(); + } + + /** + * Handle keystrokes. + * + * @param keypress keystroke event + */ + @Override + public void onKeypress(final TKeypressEvent keypress) { + if (keypress.equals(kbShiftLeft) + || keypress.equals(kbCtrlLeft) + || keypress.equals(kbAltLeft) + ) { + horizontalDecrement(); + } else if (keypress.equals(kbShiftRight) + || keypress.equals(kbCtrlRight) + || keypress.equals(kbAltRight) + ) { + horizontalIncrement(); + } else if (keypress.equals(kbShiftUp) + || keypress.equals(kbCtrlUp) + || keypress.equals(kbAltUp) + ) { + verticalDecrement(); + } else if (keypress.equals(kbShiftDown) + || keypress.equals(kbCtrlDown) + || keypress.equals(kbAltDown) + ) { + verticalIncrement(); + } else if (keypress.equals(kbShiftPgUp) + || keypress.equals(kbCtrlPgUp) + || keypress.equals(kbAltPgUp) + ) { + bigVerticalDecrement(); + } else if (keypress.equals(kbShiftPgDn) + || keypress.equals(kbCtrlPgDn) + || keypress.equals(kbAltPgDn) + ) { + bigVerticalIncrement(); + } else if (keypress.equals(kbPgDn)) { + for (int i = 0; i < getHeight() - 2; i++) { + treeView.onKeypress(new TKeypressEvent(TKeypress.kbDown)); + } + reflowData(); + return; + } else if (keypress.equals(kbPgUp)) { + for (int i = 0; i < getHeight() - 2; i++) { + treeView.onKeypress(new TKeypressEvent(TKeypress.kbUp)); + } + reflowData(); + return; + } else if (keypress.equals(kbHome)) { + treeView.setSelected((TTreeItem) treeView.getChildren().get(0), + false); + treeView.setTopLine(0); + reflowData(); + return; + } else if (keypress.equals(kbEnd)) { + treeView.setSelected((TTreeItem) treeView.getChildren().get( + treeView.getChildren().size() - 1), true); + reflowData(); + return; + } else if (keypress.equals(kbTab)) { + getParent().switchWidget(true); + return; + } else if (keypress.equals(kbShiftTab) + || keypress.equals(kbBackTab)) { + getParent().switchWidget(false); + return; + } else { + treeView.onKeypress(keypress); + + // Update the scrollbars to reflect the new data position + reflowData(); + return; + } + + // Update the view to reflect the new scrollbar position + treeView.setTopLine(getVerticalValue()); + treeView.setLeftColumn(getHorizontalValue()); + reflowData(); + } + + // ------------------------------------------------------------------------ + // TScrollableWidget ------------------------------------------------------ + // ------------------------------------------------------------------------ + + /** + * Resize text and scrollbars for a new width/height. + */ + @Override + public void reflowData() { + int selectedRow = 0; + boolean foundSelectedRow = false; + + // Reset the keyboard list, expandTree() will recreate it. + for (TWidget widget: treeView.getChildren()) { + TTreeItem item = (TTreeItem) widget; + item.keyboardPrevious = null; + item.keyboardNext = null; + } + + // Expand the tree into a linear list + treeView.getChildren().clear(); + treeView.getChildren().addAll(treeView.getTreeRoot().expandTree("", + true)); + + // Locate the selected row and maximum line width + for (TWidget widget: treeView.getChildren()) { + TTreeItem item = (TTreeItem) widget; + + if (item == treeView.getSelected()) { + foundSelectedRow = true; + } + if (!foundSelectedRow) { + selectedRow++; + } + + int lineWidth = StringUtils.width(item.getText()) + + item.getPrefix().length() + 4; + if (lineWidth > maxLineWidth) { + maxLineWidth = lineWidth; + } + } + + if ((centerWindow) && (foundSelectedRow)) { + if ((selectedRow < getVerticalValue()) + || (selectedRow > getVerticalValue() + getHeight() - 2) + ) { + treeView.setTopLine(selectedRow); + centerWindow = false; + } + } + treeView.alignTree(); + + // Rescale the scroll bars + setVerticalValue(treeView.getTopLine()); + setBottomValue(treeView.getTotalLineCount() - (getHeight() - 1)); + if (getBottomValue() < getTopValue()) { + setBottomValue(getTopValue()); + } + if (getVerticalValue() > getBottomValue()) { + setVerticalValue(getBottomValue()); + } + setRightValue(maxLineWidth - 2); + if (getHorizontalValue() > getRightValue()) { + setHorizontalValue(getRightValue()); + } + + } + + // ------------------------------------------------------------------------ + // TTreeView -------------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Get the underlying TTreeView. + * + * @return the TTreeView + */ + public TTreeView getTreeView() { + return treeView; + } + + /** + * Get the root of the tree. + * + * @return the root of the tree + */ + public final TTreeItem getTreeRoot() { + return treeView.getTreeRoot(); + } + + /** + * Set the root of the tree. + * + * @param treeRoot the new root of the tree + */ + public final void setTreeRoot(final TTreeItem treeRoot) { + treeView.setTreeRoot(treeRoot); + } + + /** + * Set treeRoot. + * + * @param treeRoot ultimate root of tree + * @param centerWindow if true, move the window to put the root in view + */ + public void setTreeRoot(final TTreeItem treeRoot, + final boolean centerWindow) { + + treeView.setTreeRoot(treeRoot); + this.centerWindow = centerWindow; + } + + /** + * Get the tree view item that was selected. + * + * @return the selected item, or null if no item is selected + */ + public final TTreeItem getSelected() { + return treeView.getSelected(); + } + + /** + * Set the new selected tree view item. + * + * @param item new item that became selected + * @param centerWindow if true, move the window to put the selected into + * view + */ + public void setSelected(final TTreeItem item, final boolean centerWindow) { + treeView.setSelected(item, centerWindow); + } + + /** + * Perform user selection action. + */ + public void dispatch() { + treeView.dispatch(); + } + +}