00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package ikayaki.gui;
00024
00025 import ikayaki.Ikayaki;
00026 import ikayaki.Project;
00027 import ikayaki.Settings;
00028 import ikayaki.util.LastExecutor;
00029
00030 import javax.swing.*;
00031 import javax.swing.event.PopupMenuEvent;
00032 import javax.swing.event.PopupMenuListener;
00033 import java.awt.*;
00034 import java.awt.event.ActionEvent;
00035 import java.awt.event.ActionListener;
00036 import java.awt.event.KeyAdapter;
00037 import java.awt.event.KeyEvent;
00038 import java.io.File;
00039 import java.io.FileFilter;
00040 import java.util.Arrays;
00041
00050 public class ProjectExplorerPanel extends ProjectComponent {
00054 private final ProjectComponent parent;
00055
00059 private final JPanel browsePanel = new JPanel();
00060
00066 private final JComboBox browserField;
00067 private final FittedComboBoxRenderer browserFieldRenderer;
00068 private final JTextField browserFieldEditor;
00069 private final ComponentFlasher browserFieldFlasher;
00070
00074 boolean browserFieldPopupIsAutocomplete = false;
00075
00079
00080
00084 boolean browserFieldUpdatingPopup = false;
00085
00086 private final JButton browseButton;
00087
00088 private final ProjectExplorerTable explorerTable;
00089 private final JScrollPane explorerTableScrollPane;
00090
00091 private NewProjectPanel newProjectPanel;
00092
00096 private final LastExecutor autocompleteExecutor = new LastExecutor(100, true);
00097
00101 private File directory = null;
00102
00108 public ProjectExplorerPanel(ProjectComponent parent) {
00109 this(parent, null);
00110 }
00111
00119 public ProjectExplorerPanel(ProjectComponent parent, Project project) {
00120 this.parent = parent;
00121
00122
00123 browserField = new JComboBox(getDirectoryHistory());
00124 browserField.setEditable(true);
00125 browserField.setBackground(Color.WHITE);
00126 browserFieldEditor = (JTextField) browserField.getEditor().getEditorComponent();
00127 browserFieldFlasher = new ComponentFlasher(browserFieldEditor);
00128 browserFieldEditor.setFocusTraversalKeysEnabled(false);
00129
00130
00131 browserFieldRenderer = new FittedComboBoxRenderer(browserFieldEditor);
00132 browserField.setRenderer(browserFieldRenderer);
00133
00134
00135 browseButton = new JButton("Browse...");
00136
00137
00138 browsePanel.setLayout(new BorderLayout());
00139
00140 browsePanel.add(browserField, BorderLayout.CENTER);
00141 browsePanel.add(browseButton, BorderLayout.EAST);
00142
00143
00144 explorerTable = new ProjectExplorerTable(this.parent);
00145 explorerTableScrollPane = new JScrollPane(explorerTable);
00146
00147 explorerTableScrollPane.getViewport().setBackground(Color.WHITE);
00148
00149
00150 newProjectPanel = new NewProjectPanel();
00151
00152 this.setLayout(new BorderLayout());
00153 this.add(browsePanel, BorderLayout.NORTH);
00154 this.add(explorerTableScrollPane, BorderLayout.CENTER);
00155 this.add(newProjectPanel, BorderLayout.SOUTH);
00156
00157
00158 if (project != null) {
00159 setDirectory(project.getFile().getParentFile());
00160 } else {
00161 setDirectory(Settings.getLastDirectory());
00162 }
00163
00164
00165
00166
00167
00168
00173 browseButton.addActionListener(new ActionListener() {
00174 public void actionPerformed(ActionEvent e) {
00175 JFileChooser fc = new JFileChooser(directory);
00176 fc.setDialogTitle("Change directory");
00177 fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
00178
00179 if (fc.showOpenDialog(browseButton) == JFileChooser.APPROVE_OPTION) {
00180 setDirectory(fc.getSelectedFile());
00181 }
00182 }
00183 });
00184
00189 browserField.addActionListener(new ActionListener() {
00190 public void actionPerformed(ActionEvent e) {
00191
00192 if (browserFieldUpdatingPopup) return;
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 Object item = browserField.getEditor().getItem();
00208 File dir = item instanceof File ? (File) item : new File((String) item).getAbsoluteFile();
00209
00210
00211 if (!setDirectory(dir)) browserFieldFlasher.flash();
00212 }
00213 });
00214
00218 browserField.addPopupMenuListener(new PopupMenuListener() {
00219 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
00220
00221 if (browserFieldPopupIsAutocomplete) {
00222 browserFieldPopupIsAutocomplete = false;
00223
00224
00225 setBrowserFieldPopup(getDirectoryHistory(), false);
00226
00227 }
00228 }
00229
00230 public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
00231 }
00232
00233 public void popupMenuCanceled(PopupMenuEvent e) {
00234 }
00235 });
00236
00242 browserFieldEditor.addKeyListener(new KeyAdapter() {
00243 public void keyPressed(KeyEvent e) {
00244 if (e.getKeyCode() == KeyEvent.VK_TAB) {
00245
00246 if ((e.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
00247
00248 e.setModifiers(e.getModifiers() ^ KeyEvent.SHIFT_MASK);
00249 e.setKeyCode(KeyEvent.VK_UP);
00250 } else {
00251 e.setKeyCode(KeyEvent.VK_DOWN);
00252 }
00253 }
00254 }
00255
00256 public void keyTyped(KeyEvent e) {
00257 if (e.getKeyChar() == KeyEvent.VK_ESCAPE) {
00258 browserField.setSelectedItem(directory);
00259
00260 return;
00261 } else if (e.getKeyChar() == KeyEvent.VK_ENTER) {
00262 return;
00263 } else if (e.getKeyChar() == KeyEvent.VK_TAB) return;
00264
00265 if (e.getModifiers() == KeyEvent.CTRL_MASK && e.getKeyChar() == KeyEvent.VK_DELETE) {
00266
00267 int pos = browserFieldEditor.getCaretPosition();
00268 String text = browserFieldEditor.getText();
00269 String textA = text.substring(0, pos);
00270 String textB = text.substring(pos);
00271 textA = textA.substring(0, Math.max(0, textA.lastIndexOf(System.getProperty("file.separator"))));
00272 browserFieldEditor.setText(textA + textB);
00273 browserFieldEditor.setCaretPosition(textA.length());
00274
00275 } else if ((e.getModifiers() & KeyEvent.ALT_MASK) != 0 || (e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
00276
00277 browserField.hidePopup();
00278 return;
00279 }
00280
00281 autocompleteExecutor.execute(new Runnable() {
00282 public void run() {
00283 doAutoComplete();
00284 }
00285 });
00286 }
00287 });
00288 }
00289
00295 public void setProject(Project project) {
00296 super.setProject(project);
00297
00298
00299 browserField.hidePopup();
00300 setBrowserFieldPopup(getDirectoryHistory(), false);
00301
00302
00303 if (project != null && project.getType() != Project.Type.CALIBRATION) {
00304 setDirectory(project.getFile().getParentFile());
00305 } else {
00306 explorerTable.setDirectory(directory);
00307 }
00308
00309
00310 if (project != null) project.addProjectListener(explorerTable);
00311 }
00312
00319 private boolean setDirectory(File directory) {
00320 if (directory == null || !directory.isDirectory()) return false;
00321
00322 this.directory = directory;
00323
00324
00325 browserField.setSelectedItem(this.directory);
00326 explorerTable.setDirectory(this.directory);
00327
00328 return true;
00329 }
00330
00336 private File[] getDirectoryHistory() {
00337 return Settings.getDirectoryHistory();
00338 }
00339
00346 private File[] getAutocompleteFiles(String dirmatch) {
00347 File dirfile = new File(dirmatch);
00348 if (!dirfile.isAbsolute()) return File.listRoots();
00349 File dir = dirfile.isDirectory() ? dirfile : dirfile.getParentFile();
00350
00351
00352 if (dir == null) {
00353 dir = directory;
00354 } else if (!dir.isDirectory()) return new File[0];
00355
00356 final String match = dirfile.isDirectory() ? "" : dirfile.getName();
00357
00358 File[] files = dir.listFiles(new FileFilter() {
00359 public boolean accept(File file) {
00360 return (file.isDirectory() && file.getName().toLowerCase().startsWith(match.toLowerCase()));
00361 }
00362 });
00363
00364
00365 Arrays.sort(files);
00366 return files;
00367 }
00368
00372 private void doAutoComplete() {
00373 final File[] files = getAutocompleteFiles(browserField.getEditor().getItem().toString());
00374
00375
00376 SwingUtilities.invokeLater(new Runnable() {
00377 public void run() {
00378
00379
00380 browserFieldPopupIsAutocomplete = false;
00381 browserField.hidePopup();
00382
00383 browserFieldPopupIsAutocomplete = true;
00384 setBrowserFieldPopup(files, true);
00385 if (files.length > 0) browserField.showPopup();
00386 }
00387 });
00388 }
00389
00396 private void setBrowserFieldPopup(File[] files, boolean uniformFit) {
00397
00398 browserFieldUpdatingPopup = true;
00399
00400 String browserFieldEditorText = browserFieldEditor.getText();
00401 int browserFieldEditorCursorPosition = browserFieldEditor.getCaretPosition();
00402
00403 browserField.removeAllItems();
00404 for (File file : files) browserField.addItem(file);
00405
00406
00407 if (uniformFit) {
00408 int maxFitValue = 0;
00409 for (int i = 0; i < browserField.getItemCount(); i++) {
00410 Object item = browserField.getItemAt(i);
00411 int fitValue = browserFieldRenderer.fitValue(item);
00412 maxFitValue = Math.max(maxFitValue, fitValue);
00413 }
00414 browserFieldRenderer.setFitLimit(maxFitValue);
00415 } else {
00416 browserFieldRenderer.setFitLimit(-1);
00417 }
00418
00419 browserField.setSelectedIndex(-1);
00420 browserFieldEditor.setText(browserFieldEditorText);
00421 browserFieldEditor.setCaretPosition(browserFieldEditorCursorPosition);
00422
00423 browserFieldUpdatingPopup = false;
00424 }
00425
00431 private void setBrowserFieldCursorToEnd() {
00432 browserFieldEditor.setCaretPosition(browserFieldEditor.getDocument().getLength());
00433 }
00434
00438 private class NewProjectPanel extends JPanel {
00439
00440 private final JTextField newProjectName;
00441 private final JComboBox newProjectType;
00442 private final JButton createNewProjectButton;
00443 private final JPanel flowPanel;
00444 private final ComponentFlasher newProjectNameFlasher;
00445
00446 public NewProjectPanel() {
00447 super(new BorderLayout());
00448
00449 newProjectName = new JTextField();
00450 newProjectType = new JComboBox(Project.Type.values());
00451 newProjectType.removeItem(Project.Type.CALIBRATION);
00452 newProjectType.setSelectedItem(Project.Type.AF);
00453 newProjectType.setBackground(Color.WHITE);
00454 createNewProjectButton = new JButton("Create New");
00455
00456 flowPanel = new JPanel(new BorderLayout());
00457 flowPanel.add(newProjectType, BorderLayout.WEST);
00458 flowPanel.add(createNewProjectButton, BorderLayout.EAST);
00459
00460 this.add(newProjectName, BorderLayout.CENTER);
00461 this.add(flowPanel, BorderLayout.EAST);
00462
00463 newProjectNameFlasher = new ComponentFlasher(newProjectName);
00464
00471 createNewProjectButton.addActionListener(new ActionListener() {
00472 public void actionPerformed(ActionEvent e) {
00473 String name = newProjectName.getText();
00474 if (name.length() > 0 && !name.toLowerCase().endsWith(Ikayaki.FILE_TYPE)) {
00475 name += Ikayaki.FILE_TYPE;
00476 }
00477
00478 Project.Type type = (Project.Type) newProjectType.getSelectedItem();
00479 File file = new File(directory, name);
00480 Project created = Project.createProject(file, type);
00481
00482 if (created == null) {
00483 newProjectNameFlasher.flash();
00484 newProjectName.requestFocusInWindow();
00485 } else {
00486 parent.setProject(created);
00487 newProjectName.setText("");
00488 }
00489 }
00490 });
00491
00495 newProjectName.addActionListener(new ActionListener() {
00496 public void actionPerformed(ActionEvent e) {
00497 createNewProjectButton.doClick();
00498 }
00499 });
00500 }
00501 }
00502 }