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