From a043164fd1cc1b38f03bb104f8b5240cdf5705c6 Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Sat, 28 Mar 2015 21:30:40 -0400 Subject: [PATCH] TFileOpenBox working --- README.md | 5 -- src/jexer/TApplication.java | 3 +- src/jexer/TDirectoryList.java | 87 ++++++++++++++++++++++++---- src/jexer/TDirectoryTreeItem.java | 67 +++++++++++---------- src/jexer/TField.java | 11 ++++ src/jexer/TFileOpenBox.java | 84 +++++++++++++++++---------- src/jexer/TTreeItem.java | 8 +-- src/jexer/TTreeView.java | 8 +++ src/jexer/TWidget.java | 3 +- src/jexer/demos/DemoApplication.java | 46 ++++++++++++++- src/jexer/demos/DemoTextWindow.java | 22 +++++-- 11 files changed, 255 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 693e278..be52f13 100644 --- a/README.md +++ b/README.md @@ -175,11 +175,6 @@ Many tasks remain before calling this version 1.0: 0.0.3: FINISH PORTING -- TDirectoryList - - Also add keyboard navigation -- TFileOpen - - Also add keyboard navigation - 0.0.4: NEW STUFF - Making TMenu keyboard accelerators active/inactive diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index d0c34bf..1b928dd 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -980,7 +980,8 @@ public class TApplication implements Runnable { public final void enableSecondaryEventReceiver(final TWidget widget) { assert (secondaryEventReceiver == null); assert (secondaryEventHandler == null); - assert (widget instanceof TMessageBox); + assert ((widget instanceof TMessageBox) + || (widget instanceof TFileOpenBox)); secondaryEventReceiver = widget; secondaryEventHandler = new WidgetEventHandler(this, false); (new Thread(secondaryEventHandler)).start(); diff --git a/src/jexer/TDirectoryList.java b/src/jexer/TDirectoryList.java index 3a09bf3..563d008 100644 --- a/src/jexer/TDirectoryList.java +++ b/src/jexer/TDirectoryList.java @@ -42,7 +42,7 @@ import static jexer.TKeypress.*; /** * TDirectoryList shows the files within a directory. */ -public class TDirectoryList extends TWidget { +public final class TDirectoryList extends TWidget { /** * Files in the directory. @@ -57,7 +57,26 @@ public class TDirectoryList extends TWidget { /** * Root path containing files to display. */ - public File path; + private File path; + + /** + * Set the new path to display. + * + * @param path new path to list files for + */ + public void setPath(String path) { + this.path = new File(path); + reflow(); + } + + /** + * Get the path that is being displayed. + * + * @return the path + */ + public File getPath() { + return path; + } /** * Vertical scrollbar. @@ -117,14 +136,16 @@ public class TDirectoryList extends TWidget { // Build a list of files in this directory File [] newFiles = path.listFiles(); - for (int i = 0; i < newFiles.length; i++) { - if (newFiles[i].getName().startsWith(".")) { - continue; + if (newFiles != null) { + for (int i = 0; i < newFiles.length; i++) { + if (newFiles[i].getName().startsWith(".")) { + continue; + } + if (newFiles[i].isDirectory()) { + continue; + } + files.add(newFiles[i]); } - if (newFiles[i].isDirectory()) { - continue; - } - files.add(newFiles[i]); } for (int i = 0; i < files.size(); i++) { @@ -197,6 +218,7 @@ public class TDirectoryList extends TWidget { public TDirectoryList(final TWidget parent, final String path, final int x, final int y, final int width, final int height, final TAction action) { + super(parent, x, y, width, height); this.path = new File(path); this.action = action; files = new ArrayList(); @@ -211,7 +233,7 @@ public class TDirectoryList extends TWidget { CellAttributes color = null; int begin = vScroller.getValue(); int topY = 0; - for (int i = begin; i < files.size() - 1; i++) { + for (int i = begin; i < files.size(); i++) { String line = renderFile(i); if (hScroller.getValue() < line.length()) { line = line.substring(hScroller.getValue()); @@ -234,6 +256,12 @@ public class TDirectoryList extends TWidget { } } + if (isAbsoluteActive()) { + color = getTheme().getColor("tdirectorylist"); + } else { + color = getTheme().getColor("tdirectorylist.inactive"); + } + // Pad the rest with blank lines for (int i = topY; i < getHeight() - 1; i++) { getScreen().hLineXY(0, i, getWidth() - 1, ' ', color); @@ -293,17 +321,52 @@ public class TDirectoryList extends TWidget { } else if (keypress.equals(kbRight)) { hScroller.increment(); } else if (keypress.equals(kbUp)) { - vScroller.decrement(); + if (files.size() > 0) { + if (selectedFile >= 0) { + if (selectedFile > 0) { + selectedFile--; + } + } else { + selectedFile = files.size() - 1; + } + path = files.get(selectedFile); + } } else if (keypress.equals(kbDown)) { - vScroller.increment(); + if (files.size() > 0) { + if (selectedFile >= 0) { + if (selectedFile < files.size() - 1) { + selectedFile++; + } + } else { + selectedFile = 0; + } + path = files.get(selectedFile); + } } else if (keypress.equals(kbPgUp)) { vScroller.bigDecrement(); } else if (keypress.equals(kbPgDn)) { vScroller.bigIncrement(); } else if (keypress.equals(kbHome)) { vScroller.toTop(); + if (files.size() > 0) { + selectedFile = 0; + path = files.get(selectedFile); + } } else if (keypress.equals(kbEnd)) { vScroller.toBottom(); + if (files.size() > 0) { + selectedFile = files.size() - 1; + path = files.get(selectedFile); + } + } else if (keypress.equals(kbTab)) { + getParent().switchWidget(true); + } else if (keypress.equals(kbShiftTab) || keypress.equals(kbBackTab)) { + getParent().switchWidget(false); + } else if (keypress.equals(kbEnter)) { + if (selectedFile >= 0) { + path = files.get(selectedFile); + dispatch(); + } } else { // Pass other keys (tab etc.) on super.onKeypress(keypress); diff --git a/src/jexer/TDirectoryTreeItem.java b/src/jexer/TDirectoryTreeItem.java index 01c9b46..1bb30f1 100644 --- a/src/jexer/TDirectoryTreeItem.java +++ b/src/jexer/TDirectoryTreeItem.java @@ -42,9 +42,18 @@ import java.util.LinkedList; public class TDirectoryTreeItem extends TTreeItem { /** - * Directory entry corresponding to this list item. + * File corresponding to this list item. */ - File dir; + private File file; + + /** + * Get the File corresponding to this list item. + * + * @return the File + */ + public final File getFile() { + return file; + } /** * Called when this item is expanded or collapsed. this.expanded will be @@ -52,20 +61,20 @@ public class TDirectoryTreeItem extends TTreeItem { */ @Override public void onExpand() { - // System.err.printf("onExpand() %s\n", dir); + // System.err.printf("onExpand() %s\n", file); - if (dir == null) { + if (file == null) { return; } getChildren().clear(); // Make sure we can read it before trying to. - if (dir.canRead()) { + if (file.canRead()) { setSelectable(true); } else { setSelectable(false); } - assert (dir.isDirectory()); + assert (file.isDirectory()); setExpandable(true); if ((isExpanded() == false) || (isExpandable() == false)) { @@ -73,20 +82,20 @@ public class TDirectoryTreeItem extends TTreeItem { return; } - for (File file: dir.listFiles()) { + for (File f: file.listFiles()) { // System.err.printf(" -> file %s %s\n", file, file.getName()); - if (file.getName().startsWith(".")) { + if (f.getName().startsWith(".")) { // Hide dot-files continue; } - if (!file.isDirectory()) { + if (!f.isDirectory()) { continue; } try { TDirectoryTreeItem item = new TDirectoryTreeItem(getTreeView(), - file.getCanonicalPath(), false, false); + f.getCanonicalPath(), false, false); item.level = this.level + 1; getChildren().add(item); @@ -152,52 +161,52 @@ public class TDirectoryTreeItem extends TTreeItem { super(view, text, false); - List parentPaths = new LinkedList(); + List parentFiles = new LinkedList(); boolean oldExpanded = expanded; // Convert to canonical path - File rootPath = new File(text); - rootPath = rootPath.getCanonicalFile(); + File rootFile = new File(text); + rootFile = rootFile.getCanonicalFile(); if (openParents == true) { setExpanded(true); // Go up the directory tree - File parent = rootPath.getParentFile(); + File parent = rootFile.getParentFile(); while (parent != null) { - parentPaths.add(rootPath.getName()); - rootPath = rootPath.getParentFile(); - parent = rootPath.getParentFile(); + parentFiles.add(rootFile.getName()); + rootFile = rootFile.getParentFile(); + parent = rootFile.getParentFile(); } } - dir = rootPath; - if (rootPath.getParentFile() == null) { + file = rootFile; + if (rootFile.getParentFile() == null) { // This is a filesystem root, use its full name - setText(rootPath.getCanonicalPath()); + setText(rootFile.getCanonicalPath()); } else { // This is a relative path. We got here because openParents was // false. assert (openParents == false); - setText(rootPath.getName()); + setText(rootFile.getName()); } onExpand(); if (openParents == true) { - TDirectoryTreeItem childPath = this; - Collections.reverse(parentPaths); - for (String p: parentPaths) { - for (TWidget widget: childPath.getChildren()) { + TDirectoryTreeItem childFile = this; + Collections.reverse(parentFiles); + for (String p: parentFiles) { + for (TWidget widget: childFile.getChildren()) { TDirectoryTreeItem child = (TDirectoryTreeItem) widget; if (child.getText().equals(p)) { - childPath = child; - childPath.setExpanded(true); - childPath.onExpand(); + childFile = child; + childFile.setExpanded(true); + childFile.onExpand(); break; } } } unselect(); - getTreeView().setSelected(childPath); + getTreeView().setSelected(childFile); setExpanded(oldExpanded); } getTreeView().reflow(); diff --git a/src/jexer/TField.java b/src/jexer/TField.java index 8055a38..9a3d16b 100644 --- a/src/jexer/TField.java +++ b/src/jexer/TField.java @@ -55,6 +55,17 @@ public class TField extends TWidget { return text; } + /** + * Set field text. + * + * @param text the new field text + */ + public final void setText(String text) { + this.text = text; + position = 0; + windowStart = 0; + } + /** * If true, only allow enough characters that will fit in the width. If * false, allow the field to scroll to the right. diff --git a/src/jexer/TFileOpenBox.java b/src/jexer/TFileOpenBox.java index eb2c924..44d1538 100644 --- a/src/jexer/TFileOpenBox.java +++ b/src/jexer/TFileOpenBox.java @@ -90,7 +90,6 @@ public final class TFileOpenBox extends TWindow { /** * The right-side directory list pane. */ - @SuppressWarnings("unused") private TDirectoryList directoryList; /** @@ -104,36 +103,27 @@ public final class TFileOpenBox extends TWindow { private TButton openButton; /** - * Update the fields in response to other field updates. + * See if there is a valid filename to return. If the filename is a + * directory, then * - * @param enter if true, the user manually entered a filename + * @param newFilename the filename to check and return */ - @SuppressWarnings("unused") - private void onUpdate(boolean enter) throws IOException { - String newFilename = entryField.getText(); + private void checkFilename(final String newFilename) throws IOException { File newFile = new File(newFilename); if (newFile.exists()) { - if (enter) { - if (newFile.isFile()) { - filename = entryField.getText(); - getApplication().closeWindow(this); - } - if (newFile.isDirectory()) { - treeViewRoot = new TDirectoryTreeItem(treeView, - entryField.getText(), true); - treeView.setTreeRoot(treeViewRoot, true); - treeView.reflow(); - } + if (newFile.isFile()) { + filename = newFilename; + getApplication().closeWindow(this); + return; + } + if (newFile.isDirectory()) { + treeViewRoot = new TDirectoryTreeItem(treeView, newFilename, + true); + treeView.setTreeRoot(treeViewRoot, true); + treeView.reflow(); openButton.setEnabled(false); - } else { - if (newFile.isFile()) { - openButton.setEnabled(true); - } else { - openButton.setEnabled(false); - } + directoryList.setPath(newFilename); } - } else { - openButton.setEnabled(false); } } @@ -154,13 +144,30 @@ public final class TFileOpenBox extends TWindow { entryField = addField(1, 1, getWidth() - 4, false, (new File(path)).getCanonicalPath(), new TAction() { - public void DO() {} + public void DO() { + try { + checkFilename(entryField.getText()); + } catch (IOException e) { + e.printStackTrace(); + } + } }, null); + entryField.onKeypress(new TKeypressEvent(kbEnd)); // Add directory treeView treeView = addTreeView(1, 3, 30, getHeight() - 6, new TAction() { - public void DO() {} + public void DO() { + TTreeItem item = treeView.getSelected(); + File selectedDir = ((TDirectoryTreeItem) item).getFile(); + try { + directoryList.setPath(selectedDir.getCanonicalPath()); + openButton.setEnabled(false); + activate(directoryList); + } catch (IOException e) { + e.printStackTrace(); + } + } } ); treeViewRoot = new TDirectoryTreeItem(treeView, path, true); @@ -168,7 +175,17 @@ public final class TFileOpenBox extends TWindow { // Add directory files list directoryList = addDirectoryList(path, 34, 3, 28, getHeight() - 6, new TAction() { - public void DO() {} + public void DO() { + try { + File newPath = directoryList.getPath(); + entryField.setText(newPath.getCanonicalPath()); + entryField.onKeypress(new TKeypressEvent(kbEnd)); + openButton.setEnabled(true); + activate(entryField); + } catch (IOException e) { + e.printStackTrace(); + } + } } ); @@ -189,7 +206,13 @@ public final class TFileOpenBox extends TWindow { // Setup button actions openButton = addButton(openLabel, this.getWidth() - 12, 3, new TAction() { - public void DO() {} + public void DO() { + try { + checkFilename(entryField.getText()); + } catch (IOException e) { + e.printStackTrace(); + } + } } ); openButton.setEnabled(false); @@ -203,6 +226,9 @@ public final class TFileOpenBox extends TWindow { } ); + // Default to the directory list + activate(directoryList); + // Set the secondaryFiber to run me getApplication().enableSecondaryEventReceiver(this); diff --git a/src/jexer/TTreeItem.java b/src/jexer/TTreeItem.java index 11a81a7..9fb9330 100644 --- a/src/jexer/TTreeItem.java +++ b/src/jexer/TTreeItem.java @@ -76,7 +76,7 @@ public class TTreeItem extends TWidget { /** * Set the displayable text for this item. * - * @param the displayable text for this item + * @param text the displayable text for this item */ public final void setText(final String text) { this.text = text; @@ -265,10 +265,10 @@ public class TTreeItem extends TWidget { /** * Recursively expand the tree into a linear array of items. * - * @param prefix = vertical bar of parent levels and such that is set on + * @param prefix vertical bar of parent levels and such that is set on * each child - * @param last = if true, this is the "last" leaf node of a tree - * @param additional items to add to the array + * @param last if true, this is the "last" leaf node of a tree + * @return additional items to add to the array */ public List expandTree(final String prefix, final boolean last) { List array = new ArrayList(); diff --git a/src/jexer/TTreeView.java b/src/jexer/TTreeView.java index a6855ba..c24fd0c 100644 --- a/src/jexer/TTreeView.java +++ b/src/jexer/TTreeView.java @@ -435,12 +435,20 @@ public class TTreeView extends TWidget { } } } + } else if (keypress.equals(kbTab)) { + getParent().switchWidget(true); + return; + } else if (keypress.equals(kbShiftTab) + || keypress.equals(kbBackTab)) { + getParent().switchWidget(false); + return; } else if (selectedItem != null) { // Give the TTreeItem a chance to handle arrow keys selectedItem.onKeypress(keypress); } else { // Pass other keys (tab etc.) on to TWidget's handler. super.onKeypress(keypress); + return; } // Update the screen after any thing has expanded/contracted diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index 29b6c72..91bcfce 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -762,8 +762,7 @@ public abstract class TWidget implements Comparable { public void onKeypress(final TKeypressEvent keypress) { if ((children.size() == 0) - // TODO - // || (cast(TTreeView)this) + || (this instanceof TTreeView) || (this instanceof TText) ) { diff --git a/src/jexer/demos/DemoApplication.java b/src/jexer/demos/DemoApplication.java index 95d0a54..d9bbeb7 100644 --- a/src/jexer/demos/DemoApplication.java +++ b/src/jexer/demos/DemoApplication.java @@ -31,8 +31,10 @@ package jexer.demos; import java.io.*; +import java.util.*; import jexer.*; +import jexer.event.*; import jexer.menu.*; /** @@ -74,7 +76,7 @@ public class DemoApplication extends TApplication { addWindowMenu(); } - + /** * Public constructor. * @@ -93,7 +95,47 @@ public class DemoApplication extends TApplication { super(input, output); addAllWidgets(); } - + + /** + * Handle menu events. + * + * @param menu menu event + * @return if true, the event was processed and should not be passed onto + * a window + */ + @Override + public boolean onMenu(TMenuEvent menu) { + if (menu.getId() == TMenu.MID_OPEN_FILE) { + try { + String filename = fileOpenBox("."); + if (filename != null) { + try { + File file = new File(filename); + StringBuilder fileContents = new StringBuilder(); + Scanner scanner = new Scanner(file); + String EOL = System.getProperty("line.separator"); + + try { + while(scanner.hasNextLine()) { + fileContents.append(scanner.nextLine() + EOL); + } + new DemoTextWindow(this, filename, + fileContents.toString()); + } finally { + scanner.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return true; + } + return super.onMenu(menu); + } + /** * Public constructor. * diff --git a/src/jexer/demos/DemoTextWindow.java b/src/jexer/demos/DemoTextWindow.java index 711bf3b..265c45d 100644 --- a/src/jexer/demos/DemoTextWindow.java +++ b/src/jexer/demos/DemoTextWindow.java @@ -43,15 +43,27 @@ public class DemoTextWindow extends TWindow { */ private TText textField; + /** + * Public constructor makes a text window out of any string. + * + * @param parent the main application + * @param title the text string + * @param text the text string + */ + public DemoTextWindow(final TApplication parent, final String title, + final String text) { + + super(parent, title, 0, 0, 44, 20, RESIZABLE); + textField = addText(text, 1, 1, 40, 16); + } + /** * Public constructor. * * @param parent the main application */ public DemoTextWindow(final TApplication parent) { - super(parent, "Text Areas", 0, 0, 44, 20, RESIZABLE); - - textField = addText( + this(parent, "Text Area", "This is an example of a reflowable text field. Some example text follows.\n" + "\n" + "This library implements a text-based windowing system loosely\n" + @@ -69,8 +81,8 @@ public class DemoTextWindow extends TWindow { "This library is licensed LGPL (\"GNU Lesser General Public License\")\n" + "version 3 or greater. See the file COPYING for the full license text,\n" + "which includes both the GPL v3 and the LGPL supplemental terms.\n" + -"\n", - 1, 1, 40, 16); +"\n"); + } /** -- 2.27.0