Only allow keyboard resizing when RESIZABLE is set
[nikiroo-utils.git] / src / jexer / TFileOpenBox.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 Kevin Lamonte
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29 package jexer;
30
31 import java.io.File;
32 import java.io.IOException;
33
34 import jexer.bits.GraphicsChars;
35 import jexer.event.TKeypressEvent;
36 import static jexer.TKeypress.*;
37
38 /**
39 * TFileOpenBox is a system-modal dialog for selecting a file to open. Call
40 * it like:
41 *
42 * <p>
43 * <pre>
44 * {@code
45 * filename = application.fileOpenBox("/path/to/file.ext",
46 * TFileOpenBox.Type.OPEN);
47 * if (filename != null) {
48 * ... the user selected a file, go open it ...
49 * }
50 * }
51 * </pre>
52 *
53 */
54 public final class TFileOpenBox extends TWindow {
55
56 /**
57 * TFileOpenBox can be called for either Open or Save actions.
58 */
59 public enum Type {
60 /**
61 * Button will be labeled "Open".
62 */
63 OPEN,
64
65 /**
66 * Button will be labeled "Save".
67 */
68 SAVE
69 }
70
71 /**
72 * String to return, or null if the user canceled.
73 */
74 private String filename = null;
75
76 /**
77 * Get the return string.
78 *
79 * @return the filename the user selected, or null if they canceled.
80 */
81 public String getFilename() {
82 return filename;
83 }
84
85 /**
86 * The left-side tree view pane.
87 */
88 private TTreeView treeView;
89
90 /**
91 * The data behind treeView.
92 */
93 private TDirectoryTreeItem treeViewRoot;
94
95 /**
96 * The right-side directory list pane.
97 */
98 private TDirectoryList directoryList;
99
100 /**
101 * The top row text field.
102 */
103 private TField entryField;
104
105 /**
106 * The Open or Save button.
107 */
108 private TButton openButton;
109
110 /**
111 * See if there is a valid filename to return. If the filename is a
112 * directory, then
113 *
114 * @param newFilename the filename to check and return
115 * @throws IOException of a java.io operation throws
116 */
117 private void checkFilename(final String newFilename) throws IOException {
118 File newFile = new File(newFilename);
119 if (newFile.exists()) {
120 if (newFile.isFile()) {
121 filename = newFilename;
122 getApplication().closeWindow(this);
123 return;
124 }
125 if (newFile.isDirectory()) {
126 treeViewRoot = new TDirectoryTreeItem(treeView, newFilename,
127 true);
128 treeView.setTreeRoot(treeViewRoot, true);
129 treeView.reflowData();
130 openButton.setEnabled(false);
131 directoryList.setPath(newFilename);
132 }
133 }
134 }
135
136 /**
137 * Public constructor. The file open box will be centered on screen.
138 *
139 * @param application the TApplication that manages this window
140 * @param path path of selected file
141 * @param type one of the Type constants
142 * @throws IOException of a java.io operation throws
143 */
144 public TFileOpenBox(final TApplication application, final String path,
145 final Type type) throws IOException {
146
147 // Register with the TApplication
148 super(application, "", 0, 0, 76, 22, MODAL);
149
150 // Add text field
151 entryField = addField(1, 1, getWidth() - 4, false,
152 (new File(path)).getCanonicalPath(),
153 new TAction() {
154 public void DO() {
155 try {
156 checkFilename(entryField.getText());
157 } catch (IOException e) {
158 e.printStackTrace();
159 }
160 }
161 }, null);
162 entryField.onKeypress(new TKeypressEvent(kbEnd));
163
164 // Add directory treeView
165 treeView = addTreeView(1, 3, 30, getHeight() - 6,
166 new TAction() {
167 public void DO() {
168 TTreeItem item = treeView.getSelected();
169 File selectedDir = ((TDirectoryTreeItem) item).getFile();
170 try {
171 directoryList.setPath(selectedDir.getCanonicalPath());
172 openButton.setEnabled(false);
173 activate(directoryList);
174 } catch (IOException e) {
175 e.printStackTrace();
176 }
177 }
178 }
179 );
180 treeViewRoot = new TDirectoryTreeItem(treeView, path, true);
181
182 // Add directory files list
183 directoryList = addDirectoryList(path, 34, 3, 28, getHeight() - 6,
184 new TAction() {
185 public void DO() {
186 try {
187 File newPath = directoryList.getPath();
188 entryField.setText(newPath.getCanonicalPath());
189 entryField.onKeypress(new TKeypressEvent(kbEnd));
190 openButton.setEnabled(true);
191 activate(entryField);
192 } catch (IOException e) {
193 e.printStackTrace();
194 }
195 }
196 }
197 );
198
199 String openLabel = "";
200 switch (type) {
201 case OPEN:
202 openLabel = " &Open ";
203 setTitle("Open File...");
204 break;
205 case SAVE:
206 openLabel = " &Save ";
207 setTitle("Save File...");
208 break;
209 default:
210 throw new IllegalArgumentException("Invalid type: " + type);
211 }
212
213 // Setup button actions
214 openButton = addButton(openLabel, this.getWidth() - 12, 3,
215 new TAction() {
216 public void DO() {
217 try {
218 checkFilename(entryField.getText());
219 } catch (IOException e) {
220 e.printStackTrace();
221 }
222 }
223 }
224 );
225 openButton.setEnabled(false);
226
227 addButton("&Cancel", getWidth() - 12, 5,
228 new TAction() {
229 public void DO() {
230 filename = null;
231 getApplication().closeWindow(TFileOpenBox.this);
232 }
233 }
234 );
235
236 // Default to the directory list
237 activate(directoryList);
238
239 // Set the secondaryFiber to run me
240 getApplication().enableSecondaryEventReceiver(this);
241
242 // Yield to the secondary thread. When I come back from the
243 // constructor response will already be set.
244 getApplication().yield();
245 }
246
247 /**
248 * Draw me on screen.
249 */
250 @Override
251 public void draw() {
252 super.draw();
253 getScreen().vLineXY(33, 4, getHeight() - 6, GraphicsChars.WINDOW_SIDE,
254 getBackground());
255 }
256
257 /**
258 * Handle keystrokes.
259 *
260 * @param keypress keystroke event
261 */
262 @Override
263 public void onKeypress(final TKeypressEvent keypress) {
264 // Escape - behave like cancel
265 if (keypress.equals(kbEsc)) {
266 // Close window
267 filename = null;
268 getApplication().closeWindow(this);
269 return;
270 }
271
272 // Pass to my parent
273 super.onKeypress(keypress);
274 }
275
276 }