001: package tide.editor;
002:
003: import java.awt.Color;
004: import java.awt.Insets;
005: import tide.update.UpdaterUtils;
006: import java.awt.Dimension;
007: import snow.utils.storage.FileUtils;
008: import java.awt.EventQueue;
009: import java.awt.FlowLayout;
010: import javax.swing.*;
011: import javax.swing.event.*;
012: import javax.swing.border.*;
013: import java.awt.BorderLayout;
014: import java.awt.event.*;
015: import snow.utils.StringUtils;
016: import java.util.*;
017: import snow.utils.storage.AppProperties;
018: import snow.files.*;
019: import snow.utils.gui.*;
020: import java.io.*;
021: import java.util.prefs.Preferences;
022: import tide.greeting.GreetingOutline;
023:
024: /** Allow to choice at startup between creating a blank new project,
025: * or importing from Netbeans, JBuilder, Eclipse, Schmortopf !
026: * or guess from some java file.
027: */
028: public final class StartupDialog extends JDialog {
029: private boolean cancelled = true; // default when closing
030: private final JTextField searchTF = new JTextField(6);
031: final private AppProperties props;
032:
033: public boolean createNew = false;
034: public boolean openExisting = false;
035: public File searchedProj = null;
036:
037: private final List<KnownProject> knownProjects = new ArrayList<KnownProject>();
038: private MenuKeyListener mki = null;
039:
040: private final JPopupMenu popup = new JPopupMenu("Hit projs");
041:
042: public StartupDialog(final JFrame mf, final AppProperties props) {
043: super (mf, "tIDE startup", true);
044: this .setUndecorated(true); // NO TITLE
045:
046: this .props = props;
047: this .setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
048:
049: setBackground(Color.white);
050: getContentPane().setBackground(Color.white); // also required
051:
052: initializeKnownProjects();
053:
054: JPanel centerPanel = new JPanel();
055: centerPanel.setOpaque(false);
056:
057: centerPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
058: GridLayout3 gl3 = new GridLayout3(2, centerPanel);
059: add(centerPanel, BorderLayout.CENTER);
060:
061: final GreetingOutline greetingAnim = new GreetingOutline();
062: add(greetingAnim, BorderLayout.EAST);
063: greetingAnim.setBackground(getBackground());
064: Dimension gad = new Dimension(150, 200);
065: greetingAnim.setMinimumSize(gad);
066: greetingAnim.setPreferredSize(gad);
067:
068: JButton createNewProjBT = new JButton("Create a new project",
069: Icons.sharedPlus);
070: gl3.add(createNewProjBT);
071: gl3.add("");
072: createNewProjBT.addActionListener(new ActionListener() {
073: public void actionPerformed(ActionEvent ae) {
074: cancelled = false;
075: createNew = true;
076: setVisible(false);
077: }
078: });
079:
080: gl3.addSeparator();
081:
082: JButton browseBT = new JButton("Open an existing project");
083: createNewProjBT.setPreferredSize(browseBT.getPreferredSize());
084: gl3.add(browseBT);
085: gl3.add("");
086: browseBT.addActionListener(new ActionListener() {
087: public void actionPerformed(ActionEvent ae) {
088: cancelled = false;
089: openExisting = true;
090: setVisible(false);
091: }
092: });
093:
094: if (knownProjects.size() > 0) {
095: JPanel sp = new JPanel(
096: new FlowLayout(FlowLayout.LEFT, 0, 0));
097: sp.setOpaque(false);
098: gl3.add(sp);
099: gl3.add("");
100: JLabel qsl = new JLabel(" Quick search: ");
101: qsl.setForeground(Color.darkGray);
102: qsl.setFont(UIManager.getFont("SubTextFont"));
103: sp.add(qsl);
104: sp.add(searchTF);
105:
106: final JButton all = new JButton("...");
107: all.setMargin(new Insets(0, 0, 0, 0));
108: all.setFocusPainted(false);
109: sp.add(all);
110:
111: all.addActionListener(new ActionListener() {
112: public void actionPerformed(ActionEvent ae) {
113: JPopupMenu allPop = new JPopupMenu();
114: for (final KnownProject kp : knownProjects) {
115: JMenuItem mi = new JMenuItem(kp.name);
116: mi.setToolTipText("" + kp.projFile);
117: allPop.add(mi);
118: mi.addActionListener(new ActionListener() {
119: public void actionPerformed(ActionEvent ae) {
120: searchedProj = kp.projFile;
121: cancelled = false;
122: setVisible(false);
123: }
124: });
125: }
126: allPop.show(all, 0, 15);
127: }
128: });
129:
130: searchTF.addKeyListener(new KeyAdapter() {
131: @Override
132: public void keyReleased(KeyEvent ee) {
133: if (ee.getKeyCode() == KeyEvent.VK_ESCAPE)
134: return;
135: searchAction();
136: }
137: });
138:
139: popup.addMenuKeyListener(mki = new MenuKeyListener() {
140: public void menuKeyReleased(MenuKeyEvent ee) {
141: //System.out.println("mkr: "+ee.getKeyCode()+" "+ee.getKeyChar());
142: }
143:
144: public void menuKeyPressed(MenuKeyEvent ee) {
145: //System.out.println("mkp: "+ee.getKeyCode()+" "+ee.getKeyChar());
146: if (ee.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
147: String t = searchTF.getText();
148: if (t.length() > 0)
149: t = t.substring(0, t.length() - 1);
150: searchTF.setText(t);
151: searchAction();
152: }
153: }
154:
155: public void menuKeyTyped(MenuKeyEvent ee) {
156: searchTF.setText(searchTF.getText()
157: + ee.getKeyChar());
158: searchAction();
159: }
160: });
161: }
162:
163: JButton importBT = new JButton("Import", Icons.sharedWiz);
164: gl3.addSeparator();
165: gl3.addSeparator();
166: gl3.add(importBT);
167: importBT
168: .setToolTipText("<html><body>Imports an existing project from another IDE<p>"
169: + "- NetBeans (.properties files)"
170: + "<br>- Eclipse (.classpath files)"
171: + "<br>- Schmortopf (.Schmortopf files)"
172: + "<br>- Or simply an existing java file from any project"
173: + "<br> the settings will then be guessed.");
174: gl3.add("");
175: importBT.addActionListener(new ActionListener() {
176: public void actionPerformed(ActionEvent ae) {
177:
178: JFileChooser fs = new JFileChooser(Preferences
179: .userRoot().get("StartupDialog_importBTRoot",
180: ""));
181: fs
182: .setFileFilter(new javax.swing.filechooser.FileFilter() {
183: @Override
184: public boolean accept(File f) {
185: if (f.isDirectory())
186: return true;
187: String name = f.getName().toLowerCase(
188: Locale.ENGLISH);
189: if (name.endsWith(".properties"))
190: return true;
191: if (name.endsWith(".classpath"))
192: return true;
193: if (name.endsWith(".schmortopf"))
194: return true;
195: if (name.endsWith(".java"))
196: return true;
197: return false;
198: }
199:
200: public String getDescription() {
201: return "NetBeans, Eclipse, Schmortopf projects or any java source";
202: }
203: });
204: fs.setAccessory(new FileChooserFilter(fs));
205: fs
206: .setDialogTitle("Import settings from an external project");
207: int rep = fs.showOpenDialog(mf);
208: if (rep == JFileChooser.APPROVE_OPTION) {
209: searchedProj = fs.getSelectedFile();
210: Preferences.userRoot().put(
211: "StartupDialog_importBTRoot",
212: searchedProj.getParent());
213: cancelled = false;
214: openExisting = true;
215: setVisible(false);
216: }
217: }
218: });
219:
220: if (!TideUtils.isWebStartMode()) {
221: JButton update = new JButton("Look for a new version",
222: new Icons.StartIcon(10, 10, true));
223: gl3.addSeparator();
224: gl3.add(update);
225: gl3.add("");
226: update.addActionListener(UpdaterUtils.getUpdaterAction(
227: this , true));
228: }
229:
230: JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT,
231: 5, 5));
232: southPanel.setOpaque(false);
233: add(southPanel, BorderLayout.SOUTH);
234:
235: //southPanel.add(new JLabel("Version ["+StringUtils.extractFromFirstToNext_Excluded(MainEditorFrame._VERSION, "[", "]")+"]"));
236: //southPanel.add(Box.createHorizontalGlue());
237:
238: JButton cancelBT = new JButton("Quit", Icons.sharedCross);
239: cancelBT.setMargin(new Insets(0, 0, 0, 0));
240:
241: southPanel.add(cancelBT);
242: cancelBT.addActionListener(new ActionListener() {
243: public void actionPerformed(ActionEvent ae) {
244:
245: cancelled = true;
246: setVisible(false);
247: }
248: });
249:
250: pack();
251: setLocationRelativeTo(this );
252:
253: EventQueue.invokeLater(new Runnable() {
254: public void run() {
255: searchTF.requestFocusInWindow();
256: }
257: });
258:
259: ((JComponent) getContentPane()).registerKeyboardAction(
260: new ActionListener() {
261: public void actionPerformed(ActionEvent ae) {
262: cancelled = true;
263: setVisible(false);
264: }
265: }, "Escape", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,
266: 0, true),
267: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
268: /*no, modality hurts...
269: greetingAnim.addMouseListener(new MouseAdapter(){
270: @Override public void mousePressed(MouseEvent me)
271: {
272: JPopupMenu p = new JPopupMenu();
273: p.add("Some utilities:");
274: p.addSeparator();
275:
276: for(JMenuItem mi : SharedUtils.getUtilitiesMenuItems(MainEditorFrame.instance.getActualProject()))
277: {
278: p.add(mi);
279: }
280:
281: p.show(greetingAnim, me.getX(), me.getY());
282: }
283: @Override public void mouseReleased(MouseEvent me)
284: {
285: }
286: }); */
287:
288: setVisible(true); //MODAL Dialog
289:
290: greetingAnim.terminate();
291:
292: if (cancelled) {
293: System.exit(0);
294: }
295: }
296:
297: File lastOpened = null;
298:
299: private void initializeKnownProjects() {
300: String lp = Preferences.userRoot().get("tide_last_opened_proj",
301: null);
302:
303: if (lp != null) {
304: lastOpened = new File(lp);
305: if (!lastOpened.exists())
306: lastOpened = null;
307: }
308:
309: //knownProjects
310: List<String> kp = props.getArrayProperty("KnownTIDEProjects");
311: if (kp != null && !kp.isEmpty()) {
312: for (String kpi : kp) {
313: File fp = new File(kpi);
314: if (fp.exists()) {
315: KnownProject knp = new KnownProject(fp.getName(),
316: FileUtils.getCanonicalFileWithCase(fp));
317: if (lastOpened != null && fp.equals(lastOpened)) {
318: // inserts at beginning
319: this .knownProjects.add(0, knp);
320: knp.lastOpened = true;
321: } else {
322: this .knownProjects.add(knp);
323: }
324: }
325: }
326: }
327:
328: // + all proj of the last proj folder
329: File lf = new File(props.getProperty("LastProjDir", System
330: .getProperty("user.home")));
331: if (lf.isFile())
332: lf = lf.getParentFile();
333:
334: if (lf.exists()) {
335: File[] kf = lf.listFiles(new FilenameFilter() {
336: public boolean accept(File dir, String name) {
337: if (name.toLowerCase().endsWith(
338: MainEditorFrame.PROJ_File_Extension
339: .toLowerCase()))
340: return true;
341: return false;
342: }
343: });
344:
345: for (File fp : kf) {
346: KnownProject knp = new KnownProject(fp.getName(),
347: FileUtils.getCanonicalFileWithCase(fp));
348: if (!knownProjects.contains(knp)) {
349: this .knownProjects.add(knp);
350: }
351: }
352: }
353: }
354:
355: private void searchAction() {
356: String st = this .searchTF.getText().toLowerCase();
357: List<KnownProject> hits = new ArrayList<KnownProject>();
358: for (KnownProject f : knownProjects) {
359: if (f.name.toLowerCase().contains(st)) {
360: hits.add(f);
361: }
362: }
363:
364: popup.setVisible(false);
365: popup.removeAll();
366: if (hits.size() > 0 && hits.size() < 20) {
367: for (final KnownProject hit : hits) {
368: JMenuItem mi = new JMenuItem(hit.name);
369: popup.add(mi);
370: mi.addActionListener(new ActionListener() {
371: public void actionPerformed(ActionEvent ae) {
372: searchedProj = hit.projFile;
373: popup.removeMenuKeyListener(mki);
374: cancelled = false;
375: setVisible(false);
376: }
377: });
378: }
379: popup.show(searchTF, 0, searchTF.getHeight());
380: }
381: }
382:
383: class KnownProject implements Comparable<KnownProject> {
384: public File projFile;
385: public String name;
386: public boolean lastOpened = false;
387:
388: public KnownProject(String name, File pf) {
389: this .name = StringUtils.removeAfterLastIncluded(name, ".");
390: projFile = pf;
391: }
392:
393: public int compareTo(KnownProject kp2) {
394: return name.compareTo(kp2.name);
395: }
396:
397: @Override
398: public boolean equals(Object o2) {
399: if (o2 instanceof KnownProject) {
400: return ((KnownProject) o2).projFile.equals(projFile);
401: } else {
402: return false;
403: }
404: }
405:
406: @Override
407: public final String toString() {
408: return name;
409: }
410: }
411: }
|