9a0437ccc5618ab01baffd29cc1c24295339a936
[nikiroo-utils.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 /**
63 * Button will be labeled "Open".
64 */
65 OPEN,
66
67 /**
68 * Button will be labeled "Save".
69 */
70 SAVE
71 }
72
73 /**
74 * String to return, or null if the user canceled.
75 */
76 private String filename = null;
77
78 /**
79 * Get the return string.
80 *
81 * @return the filename the user selected, or null if they canceled.
82 */
83 public String getFilename() {
84 return filename;
85 }
86
87 /**
88 * The left-side tree view pane.
89 */
90 private TTreeView treeView;
91
92 /**
93 * The data behind treeView.
94 */
95 private TDirectoryTreeItem treeViewRoot;
96
97 /**
98 * The right-side directory list pane.
99 */
100 private TDirectoryList directoryList;
101
102 /**
103 * The top row text field.
104 */
105 private TField entryField;
106
107 /**
108 * The Open or Save button.
109 */
110 private TButton openButton;
111
112 /**
113 * See if there is a valid filename to return. If the filename is a
114 * directory, then
115 *
116 * @param newFilename the filename to check and return
117 * @throws IOException of a java.io operation throws
118 */
119 private void checkFilename(final String newFilename) throws IOException {
120 File newFile = new File(newFilename);
121 if (newFile.exists()) {
122 if (newFile.isFile()) {
123 filename = newFilename;
124 getApplication().closeWindow(this);
125 return;
126 }
127 if (newFile.isDirectory()) {
128 treeViewRoot = new TDirectoryTreeItem(treeView, newFilename,
129 true);
130 treeView.setTreeRoot(treeViewRoot, true);
131 treeView.reflow();
132 openButton.setEnabled(false);
133 directoryList.setPath(newFilename);
134 }
135 }
136 }
137
138 /**
139 * Public constructor. The file open box will be centered on screen.
140 *
141 * @param application the TApplication that manages this window
142 * @param path path of selected file
143 * @param type one of the Type constants
144 * @throws IOException of a java.io operation throws
145 */
146 public TFileOpenBox(final TApplication application, final String path,
147 final Type type) throws IOException {
148
149 // Register with the TApplication
150 super(application, "", 0, 0, 76, 22, MODAL);
151
152 // Add text field
153 entryField = addField(1, 1, getWidth() - 4, false,
154 (new File(path)).getCanonicalPath(),
155 new TAction() {
156 public void DO() {
157 try {
158 checkFilename(entryField.getText());
159 } catch (IOException e) {
160 e.printStackTrace();
161 }
162 }
163 }, null);
164 entryField.onKeypress(new TKeypressEvent(kbEnd));
165
166 // Add directory treeView
167 treeView = addTreeView(1, 3, 30, getHeight() - 6,
168 new TAction() {
169 public void DO() {
170 TTreeItem item = treeView.getSelected();
171 File selectedDir = ((TDirectoryTreeItem) item).getFile();
172 try {
173 directoryList.setPath(selectedDir.getCanonicalPath());
174 openButton.setEnabled(false);
175 activate(directoryList);
176 } catch (IOException e) {
177 e.printStackTrace();
178 }
179 }
180 }
181 );
182 treeViewRoot = new TDirectoryTreeItem(treeView, path, true);
183
184 // Add directory files list
185 directoryList = addDirectoryList(path, 34, 3, 28, getHeight() - 6,
186 new TAction() {
187 public void DO() {
188 try {
189 File newPath = directoryList.getPath();
190 entryField.setText(newPath.getCanonicalPath());
191 entryField.onKeypress(new TKeypressEvent(kbEnd));
192 openButton.setEnabled(true);
193 activate(entryField);
194 } catch (IOException e) {
195 e.printStackTrace();
196 }
197 }
198 }
199 );
200
201 String openLabel = "";
202 switch (type) {
203 case OPEN:
204 openLabel = " &Open ";
205 setTitle("Open File...");
206 break;
207 case SAVE:
208 openLabel = " &Save ";
209 setTitle("Save File...");
210 break;
211 default:
212 throw new IllegalArgumentException("Invalid type: " + type);
213 }
214
215 // Setup button actions
216 openButton = addButton(openLabel, this.getWidth() - 12, 3,
217 new TAction() {
218 public void DO() {
219 try {
220 checkFilename(entryField.getText());
221 } catch (IOException e) {
222 e.printStackTrace();
223 }
224 }
225 }
226 );
227 openButton.setEnabled(false);
228
229 addButton("&Cancel", getWidth() - 12, 5,
230 new TAction() {
231 public void DO() {
232 filename = null;
233 getApplication().closeWindow(TFileOpenBox.this);
234 }
235 }
236 );
237
238 // Default to the directory list
239 activate(directoryList);
240
241 // Set the secondaryFiber to run me
242 getApplication().enableSecondaryEventReceiver(this);
243
244 // Yield to the secondary thread. When I come back from the
245 // constructor response will already be set.
246 getApplication().yield();
247 }
248
249 /**
250 * Draw me on screen.
251 */
252 @Override
253 public void draw() {
254 super.draw();
255 getScreen().vLineXY(33, 4, getHeight() - 6, GraphicsChars.WINDOW_SIDE,
256 getBackground());
257 }
258
259 /**
260 * Handle keystrokes.
261 *
262 * @param keypress keystroke event
263 */
264 @Override
265 public void onKeypress(final TKeypressEvent keypress) {
266 // Escape - behave like cancel
267 if (keypress.equals(kbEsc)) {
268 // Close window
269 filename = null;
270 getApplication().closeWindow(this);
271 return;
272 }
273
274 // Pass to my parent
275 super.onKeypress(keypress);
276 }
277
278 }