Commit | Line | Data |
---|---|---|
a3b510ab NR |
1 | package com.googlecode.lanterna.gui2.dialogs; |
2 | ||
3 | import com.googlecode.lanterna.TerminalTextUtils; | |
4 | import com.googlecode.lanterna.TerminalSize; | |
5 | import com.googlecode.lanterna.gui2.*; | |
6 | ||
7 | import java.io.File; | |
8 | import java.util.Arrays; | |
9 | import java.util.Comparator; | |
10 | ||
11 | /** | |
12 | * Dialog that allows the user to iterate the file system and pick file to open/save | |
13 | * | |
14 | * @author Martin | |
15 | */ | |
16 | public class FileDialog extends DialogWindow { | |
17 | ||
18 | private final ActionListBox fileListBox; | |
19 | private final ActionListBox directoryListBox; | |
20 | private final TextBox fileBox; | |
21 | private final Button okButton; | |
22 | private final boolean showHiddenFilesAndDirs; | |
23 | ||
24 | private File directory; | |
25 | private File selectedFile; | |
26 | ||
27 | /** | |
28 | * Default constructor for {@code FileDialog} | |
29 | * @param title Title of the dialog | |
30 | * @param description Description of the dialog, is displayed at the top of the content area | |
31 | * @param actionLabel Label to use on the "confirm" button, for example "open" or "save" | |
32 | * @param dialogSize Rough estimation of how big you want the dialog to be | |
33 | * @param showHiddenFilesAndDirs If {@code true}, hidden files and directories will be visible | |
34 | * @param selectedObject Initially selected file node | |
35 | */ | |
36 | public FileDialog( | |
37 | String title, | |
38 | String description, | |
39 | String actionLabel, | |
40 | TerminalSize dialogSize, | |
41 | boolean showHiddenFilesAndDirs, | |
42 | File selectedObject) { | |
43 | super(title); | |
44 | this.selectedFile = null; | |
45 | this.showHiddenFilesAndDirs = showHiddenFilesAndDirs; | |
46 | ||
47 | if(selectedObject == null || !selectedObject.exists()) { | |
48 | selectedObject = new File("").getAbsoluteFile(); | |
49 | } | |
50 | selectedObject = selectedObject.getAbsoluteFile(); | |
51 | ||
52 | Panel contentPane = new Panel(); | |
53 | contentPane.setLayoutManager(new GridLayout(2)); | |
54 | ||
55 | if(description != null) { | |
56 | new Label(description) | |
57 | .setLayoutData( | |
58 | GridLayout.createLayoutData( | |
59 | GridLayout.Alignment.BEGINNING, | |
60 | GridLayout.Alignment.CENTER, | |
61 | false, | |
62 | false, | |
63 | 2, | |
64 | 1)) | |
65 | .addTo(contentPane); | |
66 | } | |
67 | ||
68 | int unitWidth = dialogSize.getColumns() / 3; | |
69 | int unitHeight = dialogSize.getRows(); | |
70 | ||
71 | new FileSystemLocationLabel() | |
72 | .setLayoutData(GridLayout.createLayoutData( | |
73 | GridLayout.Alignment.FILL, | |
74 | GridLayout.Alignment.CENTER, | |
75 | true, | |
76 | false, | |
77 | 2, | |
78 | 1)) | |
79 | .addTo(contentPane); | |
80 | ||
81 | fileListBox = new ActionListBox(new TerminalSize(unitWidth * 2, unitHeight)); | |
82 | fileListBox.withBorder(Borders.singleLine()) | |
83 | .setLayoutData(GridLayout.createLayoutData( | |
84 | GridLayout.Alignment.BEGINNING, | |
85 | GridLayout.Alignment.CENTER, | |
86 | false, | |
87 | false)) | |
88 | .addTo(contentPane); | |
89 | directoryListBox = new ActionListBox(new TerminalSize(unitWidth, unitHeight)); | |
90 | directoryListBox.withBorder(Borders.singleLine()) | |
91 | .addTo(contentPane); | |
92 | ||
93 | fileBox = new TextBox() | |
94 | .setLayoutData(GridLayout.createLayoutData( | |
95 | GridLayout.Alignment.FILL, | |
96 | GridLayout.Alignment.CENTER, | |
97 | true, | |
98 | false, | |
99 | 2, | |
100 | 1)) | |
101 | .addTo(contentPane); | |
102 | ||
103 | new Separator(Direction.HORIZONTAL) | |
104 | .setLayoutData( | |
105 | GridLayout.createLayoutData( | |
106 | GridLayout.Alignment.FILL, | |
107 | GridLayout.Alignment.CENTER, | |
108 | true, | |
109 | false, | |
110 | 2, | |
111 | 1)) | |
112 | .addTo(contentPane); | |
113 | ||
114 | okButton = new Button(actionLabel, new OkHandler()); | |
115 | Panels.grid(2, | |
116 | okButton, | |
117 | new Button(LocalizedString.Cancel.toString(), new CancelHandler())) | |
118 | .setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER, false, false, 2, 1)) | |
119 | .addTo(contentPane); | |
120 | ||
121 | if(selectedObject.isFile()) { | |
122 | directory = selectedObject.getParentFile(); | |
123 | fileBox.setText(selectedObject.getName()); | |
124 | } | |
125 | else if(selectedObject.isDirectory()) { | |
126 | directory = selectedObject; | |
127 | } | |
128 | ||
129 | reloadViews(directory); | |
130 | setComponent(contentPane); | |
131 | } | |
132 | ||
133 | /** | |
134 | * {@inheritDoc} | |
135 | * @param textGUI Text GUI to add the dialog to | |
136 | * @return The file which was selected in the dialog or {@code null} if the dialog was cancelled | |
137 | */ | |
138 | @Override | |
139 | public File showDialog(WindowBasedTextGUI textGUI) { | |
140 | selectedFile = null; | |
141 | super.showDialog(textGUI); | |
142 | return selectedFile; | |
143 | } | |
144 | ||
145 | private class OkHandler implements Runnable { | |
146 | @Override | |
147 | public void run() { | |
148 | if(!fileBox.getText().isEmpty()) { | |
149 | selectedFile = new File(directory, fileBox.getText()); | |
150 | close(); | |
151 | } | |
152 | else { | |
153 | MessageDialog.showMessageDialog(getTextGUI(), "Error", "Please select a valid file name", MessageDialogButton.OK); | |
154 | } | |
155 | } | |
156 | } | |
157 | ||
158 | private class CancelHandler implements Runnable { | |
159 | @Override | |
160 | public void run() { | |
161 | selectedFile = null; | |
162 | close(); | |
163 | } | |
164 | } | |
165 | ||
166 | private class DoNothing implements Runnable { | |
167 | @Override | |
168 | public void run() { | |
169 | } | |
170 | } | |
171 | ||
172 | private void reloadViews(final File directory) { | |
173 | directoryListBox.clearItems(); | |
174 | fileListBox.clearItems(); | |
175 | File []entries = directory.listFiles(); | |
176 | if(entries == null) { | |
177 | return; | |
178 | } | |
179 | Arrays.sort(entries, new Comparator<File>() { | |
180 | @Override | |
181 | public int compare(File o1, File o2) { | |
182 | return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); | |
183 | } | |
184 | }); | |
185 | directoryListBox.addItem("..", new Runnable() { | |
186 | @Override | |
187 | public void run() { | |
188 | FileDialog.this.directory = directory.getAbsoluteFile().getParentFile(); | |
189 | reloadViews(directory.getAbsoluteFile().getParentFile()); | |
190 | } | |
191 | }); | |
192 | for(final File entry: entries) { | |
193 | if(entry.isHidden() && !showHiddenFilesAndDirs) { | |
194 | continue; | |
195 | } | |
196 | if(entry.isDirectory()) { | |
197 | directoryListBox.addItem(entry.getName(), new Runnable() { | |
198 | @Override | |
199 | public void run() { | |
200 | FileDialog.this.directory = entry; | |
201 | reloadViews(entry); | |
202 | } | |
203 | }); | |
204 | } | |
205 | else { | |
206 | fileListBox.addItem(entry.getName(), new Runnable() { | |
207 | @Override | |
208 | public void run() { | |
209 | fileBox.setText(entry.getName()); | |
210 | setFocusedInteractable(okButton); | |
211 | } | |
212 | }); | |
213 | } | |
214 | } | |
215 | if(fileListBox.isEmpty()) { | |
216 | fileListBox.addItem("<empty>", new DoNothing()); | |
217 | } | |
218 | } | |
219 | ||
220 | private class FileSystemLocationLabel extends Label { | |
221 | public FileSystemLocationLabel() { | |
222 | super(""); | |
223 | setPreferredSize(TerminalSize.ONE); | |
224 | } | |
225 | ||
226 | @Override | |
227 | public void onBeforeDrawing() { | |
228 | TerminalSize area = getSize(); | |
229 | String absolutePath = directory.getAbsolutePath(); | |
230 | int absolutePathLengthInColumns = TerminalTextUtils.getColumnWidth(absolutePath); | |
231 | if(area.getColumns() < absolutePathLengthInColumns) { | |
232 | absolutePath = absolutePath.substring(absolutePathLengthInColumns - area.getColumns()); | |
233 | absolutePath = "..." + absolutePath.substring(Math.min(absolutePathLengthInColumns, 3)); | |
234 | } | |
235 | setText(absolutePath); | |
236 | } | |
237 | } | |
238 | } |