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