More PMD warnings
[fanfix.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 import java.util.ResourceBundle;
34
35 import jexer.bits.GraphicsChars;
36 import jexer.event.TKeypressEvent;
37 import jexer.ttree.TDirectoryTreeItem;
38 import jexer.ttree.TTreeItem;
39 import jexer.ttree.TTreeViewWidget;
40 import static jexer.TKeypress.*;
41
42 /**
43 * TFileOpenBox is a system-modal dialog for selecting a file to open. Call
44 * it like:
45 *
46 * <pre>
47 * {@code
48 * filename = application.fileOpenBox("/path/to/file.ext",
49 * TFileOpenBox.Type.OPEN);
50 * if (filename != null) {
51 * ... the user selected a file, go open it ...
52 * }
53 * }
54 * </pre>
55 *
56 */
57 public final class TFileOpenBox extends TWindow {
58
59 /**
60 * Translated strings.
61 */
62 private static final ResourceBundle i18n = ResourceBundle.getBundle(TFileOpenBox.class.getName());
63
64 // ------------------------------------------------------------------------
65 // Constants --------------------------------------------------------------
66 // ------------------------------------------------------------------------
67
68 /**
69 * TFileOpenBox can be called for either Open or Save actions.
70 */
71 public enum Type {
72 /**
73 * Button will be labeled "Open".
74 */
75 OPEN,
76
77 /**
78 * Button will be labeled "Save".
79 */
80 SAVE
81 }
82
83 // ------------------------------------------------------------------------
84 // Variables --------------------------------------------------------------
85 // ------------------------------------------------------------------------
86
87 /**
88 * String to return, or null if the user canceled.
89 */
90 private String filename = null;
91
92 /**
93 * The left-side tree view pane.
94 */
95 private TTreeViewWidget treeView;
96
97 /**
98 * The data behind treeView.
99 */
100 private TDirectoryTreeItem treeViewRoot;
101
102 /**
103 * The right-side directory list pane.
104 */
105 private TDirectoryList directoryList;
106
107 /**
108 * The top row text field.
109 */
110 private TField entryField;
111
112 /**
113 * The Open or Save button.
114 */
115 private TButton openButton;
116
117 // ------------------------------------------------------------------------
118 // Constructors -----------------------------------------------------------
119 // ------------------------------------------------------------------------
120
121 /**
122 * Public constructor. The file open box will be centered on screen.
123 *
124 * @param application the TApplication that manages this window
125 * @param path path of selected file
126 * @param type one of the Type constants
127 * @throws IOException of a java.io operation throws
128 */
129 public TFileOpenBox(final TApplication application, final String path,
130 final Type type) throws IOException {
131
132 // Register with the TApplication
133 super(application, "", 0, 0, 76, 22, MODAL);
134
135 // Add text field
136 entryField = addField(1, 1, getWidth() - 4, false,
137 (new File(path)).getCanonicalPath(),
138 new TAction() {
139 public void DO() {
140 try {
141 checkFilename(entryField.getText());
142 } catch (IOException e) {
143 e.printStackTrace();
144 }
145 }
146 }, null);
147 entryField.onKeypress(new TKeypressEvent(kbEnd));
148
149 // Add directory treeView
150 treeView = addTreeViewWidget(1, 3, 30, getHeight() - 6,
151 new TAction() {
152 public void DO() {
153 TTreeItem item = treeView.getSelected();
154 File selectedDir = ((TDirectoryTreeItem) item).getFile();
155 try {
156 directoryList.setPath(selectedDir.getCanonicalPath());
157 openButton.setEnabled(false);
158 activate(treeView);
159 } catch (IOException e) {
160 e.printStackTrace();
161 }
162 }
163 }
164 );
165 treeViewRoot = new TDirectoryTreeItem(treeView, path, true);
166
167 // Add directory files list
168 directoryList = addDirectoryList(path, 34, 3, 28, getHeight() - 6,
169 new TAction() {
170 public void DO() {
171 try {
172 File newPath = directoryList.getPath();
173 entryField.setText(newPath.getCanonicalPath());
174 entryField.onKeypress(new TKeypressEvent(kbEnd));
175 openButton.setEnabled(true);
176 activate(entryField);
177 } catch (IOException e) {
178 e.printStackTrace();
179 }
180 }
181 }
182 );
183
184 String openLabel = "";
185 switch (type) {
186 case OPEN:
187 openLabel = i18n.getString("openButton");
188 setTitle(i18n.getString("openTitle"));
189 break;
190 case SAVE:
191 openLabel = i18n.getString("saveButton");
192 setTitle(i18n.getString("saveTitle"));
193 break;
194 default:
195 throw new IllegalArgumentException("Invalid type: " + type);
196 }
197
198 // Setup button actions
199 openButton = addButton(openLabel, this.getWidth() - 12, 3,
200 new TAction() {
201 public void DO() {
202 try {
203 checkFilename(entryField.getText());
204 } catch (IOException e) {
205 e.printStackTrace();
206 }
207 }
208 }
209 );
210 openButton.setEnabled(false);
211
212 addButton(i18n.getString("cancelButton"), getWidth() - 12, 5,
213 new TAction() {
214 public void DO() {
215 filename = null;
216 getApplication().closeWindow(TFileOpenBox.this);
217 }
218 }
219 );
220
221 // Default to the directory list
222 activate(directoryList);
223
224 // Set the secondaryFiber to run me
225 getApplication().enableSecondaryEventReceiver(this);
226
227 // Yield to the secondary thread. When I come back from the
228 // constructor response will already be set.
229 getApplication().yield();
230 }
231
232 // ------------------------------------------------------------------------
233 // Event handlers ---------------------------------------------------------
234 // ------------------------------------------------------------------------
235
236 /**
237 * Handle keystrokes.
238 *
239 * @param keypress keystroke event
240 */
241 @Override
242 public void onKeypress(final TKeypressEvent keypress) {
243 // Escape - behave like cancel
244 if (keypress.equals(kbEsc)) {
245 // Close window
246 filename = null;
247 getApplication().closeWindow(this);
248 return;
249 }
250
251 if (treeView.isActive()) {
252 if ((keypress.equals(kbEnter))
253 || (keypress.equals(kbUp))
254 || (keypress.equals(kbDown))
255 || (keypress.equals(kbPgUp))
256 || (keypress.equals(kbPgDn))
257 || (keypress.equals(kbHome))
258 || (keypress.equals(kbEnd))
259 ) {
260 // Tree view will be changing, update the directory list.
261 super.onKeypress(keypress);
262
263 // This is the same action as treeView's enter.
264 TTreeItem item = treeView.getSelected();
265 File selectedDir = ((TDirectoryTreeItem) item).getFile();
266 try {
267 directoryList.setPath(selectedDir.getCanonicalPath());
268 openButton.setEnabled(false);
269 activate(treeView);
270 } catch (IOException e) {
271 e.printStackTrace();
272 }
273 return;
274 }
275 }
276
277 // Pass to my parent
278 super.onKeypress(keypress);
279 }
280
281 // ------------------------------------------------------------------------
282 // TWidget ----------------------------------------------------------------
283 // ------------------------------------------------------------------------
284
285 /**
286 * Draw me on screen.
287 */
288 @Override
289 public void draw() {
290 super.draw();
291 getScreen().vLineXY(33, 4, getHeight() - 6, GraphicsChars.WINDOW_SIDE,
292 getBackground());
293 }
294
295 // ------------------------------------------------------------------------
296 // TFileOpenBox -----------------------------------------------------------
297 // ------------------------------------------------------------------------
298
299 /**
300 * Get the return string.
301 *
302 * @return the filename the user selected, or null if they canceled.
303 */
304 public String getFilename() {
305 return filename;
306 }
307
308 /**
309 * See if there is a valid filename to return. If the filename is a
310 * directory, then
311 *
312 * @param newFilename the filename to check and return
313 * @throws IOException of a java.io operation throws
314 */
315 private void checkFilename(final String newFilename) throws IOException {
316 File newFile = new File(newFilename);
317 if (newFile.exists()) {
318 if (newFile.isFile()) {
319 filename = newFilename;
320 getApplication().closeWindow(this);
321 return;
322 }
323 if (newFile.isDirectory()) {
324 treeViewRoot = new TDirectoryTreeItem(treeView,
325 newFilename, true);
326 treeView.setTreeRoot(treeViewRoot, true);
327 openButton.setEnabled(false);
328 directoryList.setPath(newFilename);
329 }
330 }
331 }
332
333 }