001: package snow.files;
002:
003: import snow.utils.gui.*;
004: import snow.texteditor.SimpleEditor;
005: import java.awt.Desktop;
006: import snow.utils.DateUtils;
007: import snow.sortabletable.*;
008: import java.awt.Insets;
009: import snow.utils.storage.FileUtils;
010: import snow.utils.SysUtils;
011: import javax.swing.*;
012: import javax.swing.event.*;
013: import javax.swing.filechooser.*;
014: import java.awt.BorderLayout;
015: import java.awt.FlowLayout;
016: import java.awt.event.*;
017: import java.util.*;
018: import java.io.*;
019:
020: /** Can be used in accessory panels of JFileChooser.
021: Installs a realtime filefilter, take eventual already installed filefilter in account !
022: Options: browse, search and filter files and folders, with statistics.
023:
024: */
025: public class FileChooserFilter extends JPanel {
026: final JTextField searchField = new JTextField(4);
027:
028: static final File storageFile = new File(System
029: .getProperty("user.home"),
030: ".tide_global/files_explorer.vec");
031:
032: final JFileChooser fileChooser;
033:
034: // may be null
035: private final javax.swing.filechooser.FileFilter originalFilter;
036: private javax.swing.filechooser.FileFilter filteredFilter;
037:
038: public static FileChooserFilter install(
039: final JFileChooser fileChooser) {
040: FileChooserFilter fcf = new FileChooserFilter(fileChooser);
041: return fcf;
042: }
043:
044: public FileChooserFilter(final JFileChooser fileChooser) {
045: super ();
046:
047: this .setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
048:
049: this .originalFilter = fileChooser.getFileFilter();
050: this .fileChooser = fileChooser;
051:
052: JPanel filtPan = new JPanel(new FlowLayout(FlowLayout.LEFT, 4,
053: 0));
054: add(filtPan);
055: filtPan.add(new JLabel("Filter: "));
056: filtPan.add(searchField);
057:
058: JPanel optsPan = new JPanel(new FlowLayout(FlowLayout.LEFT, 4,
059: 0));
060: add(optsPan);
061: final JButton optionsButton = new JButton("Options");
062: optionsButton.setMargin(new Insets(0, 2, 0, 2));
063: optionsButton.setFocusPainted(false);
064: optsPan.add(optionsButton);
065: optionsButton.addActionListener(new ActionListener() {
066: public void actionPerformed(ActionEvent ae) {
067: JPopupMenu popup = new JPopupMenu();
068: JMenuItem searchRec = new JMenuItem("Search file",
069: Icons.sharedSearch);
070: popup.add(searchRec);
071: searchRec.addActionListener(new ActionListener() {
072: public void actionPerformed(ActionEvent ae) {
073: Thread t = new Thread() {
074: public void run() {
075: searchRecurse();
076: }
077: };
078: t.start();
079: }
080: });
081:
082: final JMenuItem openExplorer = new JMenuItem(
083: "Explore all files (recurse)");
084: popup.addSeparator();
085: popup.add(openExplorer);
086: openExplorer.addActionListener(new ActionListener() {
087: public void actionPerformed(ActionEvent ae) {
088: Thread t = new Thread() {
089: public void run() {
090: search(true, "");
091: }
092: };
093: t.start();
094: }
095: });
096:
097: final JMenuItem openExplorer2 = new JMenuItem(
098: "Explore recent files (<7 days) (recurse)");
099: popup.add(openExplorer2);
100: openExplorer2.addActionListener(new ActionListener() {
101: public void actionPerformed(ActionEvent ae) {
102: Thread t = new Thread() {
103: public void run() {
104: search(true, "", System
105: .currentTimeMillis()
106: - 1000L * 3600 * 24 * 7); // 7 days
107: }
108: };
109: t.start();
110: }
111: });
112:
113: JMenuItem openExplorer3 = new JMenuItem(
114: "Explore all files in this folder only");
115: popup.add(openExplorer3);
116: openExplorer3.addActionListener(new ActionListener() {
117: public void actionPerformed(ActionEvent ae) {
118: Thread t = new Thread() {
119: public void run() {
120: search(false, "");
121: }
122: };
123: t.start();
124: }
125: });
126:
127: JMenuItem openFExplorer = new JMenuItem(
128: "Explore all folders");
129: popup.addSeparator();
130: popup.add(openFExplorer);
131: openFExplorer.addActionListener(new ActionListener() {
132: public void actionPerformed(ActionEvent ae) {
133: Thread t = new Thread() {
134: public void run() {
135: new DirectoryStatExplorer(fileChooser
136: .getCurrentDirectory(),
137: fileChooser);
138: }
139: };
140: t.start();
141: }
142: });
143:
144: FileIcon dir = new FileIcon(true, 15);
145: dir.setType(FileIcon.IconColor.System);
146: JMenuItem openSysExplorer = new JMenuItem(
147: "Open system file explorer", dir);
148: popup.addSeparator();
149: popup.add(openSysExplorer);
150: openSysExplorer.addActionListener(new ActionListener() {
151: public void actionPerformed(ActionEvent ae) {
152: SysUtils.openFileExplorer(fileChooser
153: .getCurrentDirectory());
154: }
155: });
156:
157: // favorites
158: final List<File> favs = getFavorites();
159: JMenu favMenu = new JMenu("Favorites");
160: popup.addSeparator();
161: popup.add(favMenu);
162:
163: final File curD = fileChooser.getCurrentDirectory();
164: if (curD != null && !favs.contains(curD)) {
165: JMenuItem addFav = new JMenuItem(
166: "Add to favorites: "
167: + fileChooser.getCurrentDirectory(),
168: Icons.sharedPlus);
169: popup.add(addFav);
170: addFav.addActionListener(new ActionListener() {
171: public void actionPerformed(ActionEvent ae) {
172: favs.add(curD);
173: saveFavorites(favs);
174: }
175: });
176: }
177:
178: final File fss = fileChooser.getSelectedFile();
179: if (fss != null
180: && fss != fileChooser.getCurrentDirectory()
181: && fss.getName().length() > 0
182: && !favs.contains(fss)) {
183: JMenuItem addFav = new JMenuItem(
184: "Add to favorites: "
185: + fileChooser.getSelectedFile(),
186: Icons.sharedPlus);
187: popup.add(addFav);
188: addFav.addActionListener(new ActionListener() {
189: public void actionPerformed(ActionEvent ae) {
190: favs.add(fss);
191: saveFavorites(favs);
192: }
193: });
194: }
195:
196: JMenuItem manFav = new JMenuItem("Manage favorites");
197: favMenu.add(manFav);
198: favMenu.addSeparator();
199: manFav.addActionListener(new ActionListener() {
200: public void actionPerformed(ActionEvent ae) {
201: // TODO: manage favorites
202: }
203: });
204:
205: for (final File favi : favs) {
206: JMenuItem fmi = new JMenuItem(""
207: + favi.getAbsolutePath());
208: favMenu.add(fmi);
209: fmi.addActionListener(new ActionListener() {
210: public void actionPerformed(ActionEvent ae) {
211: fileChooser.setSelectedFile(favi);
212: }
213: });
214: }
215:
216: if (fss != null && fss.isFile()) {
217: JMenuItem addFav = new JMenuItem(
218: "Open in internal text editor",
219: Icons.FileIcon.textFile(16));
220: popup.addSeparator();
221: popup.add(addFav);
222: addFav.addActionListener(new ActionListener() {
223: public void actionPerformed(ActionEvent ae) {
224: SimpleEditor sed = new SimpleEditor(""
225: + fss.getAbsolutePath(), true,
226: false);
227: try {
228: sed.setText(fss);
229: } catch (Exception e) {
230: e.printStackTrace();
231: }
232: }
233: });
234: }
235:
236: popup.show(optionsButton, 0, 15);
237:
238: }
239: });
240:
241: // direct search:
242: KeyAdapter kad = new KeyAdapter() {
243: @Override
244: public void keyReleased(KeyEvent ee) {
245: filterAction();
246: }
247: };
248: searchField.addKeyListener(kad);
249:
250: } // Constructor
251:
252: @SuppressWarnings("unchecked")
253: public static List<File> getFavorites() {
254: List<File> fav = new ArrayList<File>();
255: if (storageFile.exists()) {
256: try {
257: List<Object> reps = FileUtils
258: .loadVectorFromFile(storageFile);
259: List<Object> fis = (List<Object>) reps.get(1);
260: for (Object oi : fis) {
261: File fi = new File("" + oi);
262: if (fi.exists()) {
263: fav.add(fi);
264: }
265: }
266:
267: } catch (Exception e) {
268: e.printStackTrace();
269: }
270: }
271: return fav;
272: }
273:
274: public static void saveFavorites(List<File> fav) {
275: List<Object> rep = new ArrayList<Object>();
276: rep.add(1); // version
277:
278: List<Object> fis = new ArrayList<Object>();
279: rep.add(fis);
280: for (File fi : fav) {
281: fis.add(fi.getAbsolutePath());
282: }
283:
284: try {
285: FileUtils.saveVectorToFile(storageFile, rep);
286: } catch (Exception e) {
287: e.printStackTrace();
288: }
289: }
290:
291: void searchRecurse() {
292: String toSearch = JOptionPane.showInputDialog(this ,
293: "Enter the file name part to search in\n "
294: + fileChooser.getCurrentDirectory()
295: + "\npress enter to see all files.");
296: if (toSearch == null)
297: return;
298: search(true, toSearch);
299: }
300:
301: void search(boolean recurse, String toSearch) {
302: search(recurse, toSearch, -1);
303: }
304:
305: void search(boolean recurse, String toSearch, long after) {
306: toSearch = toSearch.toUpperCase();
307: String base = FileUtils.getCanonicalName(fileChooser
308: .getCurrentDirectory());
309: int baseLen = base.length();
310:
311: List<JFile> hits = new ArrayList<JFile>();
312: ProgressModalDialog pmd = new ProgressModalDialog(new JFrame(),
313: "Searching files and folders...", true);
314: pmd.start();
315: try {
316: search(recurse, hits, fileChooser.getCurrentDirectory(),
317: toSearch, baseLen, after, pmd);
318: } finally {
319: pmd.closeDialog();
320: }
321:
322: System.out.println("" + hits.size() + " hits");
323: if (hits.size() == 0) {
324: JOptionPane.showMessageDialog(this , "No file found");
325: } else if (hits.size() == 1) {
326: fileChooser.setSelectedFile(hits.get(0).f);
327: } else {
328: // show them in a sortable table...
329: final JFilesTableModel htm = new JFilesTableModel(hits);
330: final SortableTableModel stm = after > 0 ? new SortableTableModel(
331: htm, 1, true)
332: : new SortableTableModel(htm);
333: final JTable table = new JTable(stm);
334: stm.installGUI(table);
335: JDialog d = new JDialog(new JFrame(), "" + hits.size()
336: + " files found in " + base, true);
337: d.add(SortableTableUtils.createTableWithSearchBar(stm,
338: table), BorderLayout.CENTER);
339: final CloseControlPanel ccp = new CloseControlPanel(d,
340: true, true, "Select");
341: d.add(ccp, BorderLayout.SOUTH);
342: d.pack();
343: d.setLocationRelativeTo(this );
344:
345: table.addMouseListener(new MouseAdapter() {
346: @Override
347: public void mousePressed(MouseEvent me) {
348: if (me.isPopupTrigger())
349: showPopup(me);
350: }
351:
352: @Override
353: public void mouseReleased(MouseEvent me) {
354: if (me.isPopupTrigger())
355: showPopup(me);
356: }
357:
358: public void showPopup(MouseEvent me) {
359: int[] str = table.getSelectedRows();
360: if (str == null || str.length == 0)
361: return;
362:
363: if (str.length != 1)
364: return; // TODO: offer functions
365:
366: int posm = stm
367: .getIndexInUnsortedFromTablePos(str[0]);
368: final JFile sh = htm.getHitAt(posm);
369:
370: JPopupMenu pop = new JPopupMenu();
371: pop.add("" + sh.relName);
372: pop.addSeparator();
373: JMenuItem open = new JMenuItem("open (system)");
374: pop.add(open);
375: open.addActionListener(new ActionListener() {
376: public void actionPerformed(ActionEvent ae) {
377: //SysUtils.op TODO.
378: try {
379: //FAILS: file:/C:/Program%20Files/Common%20Files/Adobe/Web/adobeonlineprefs)
380: Desktop.getDesktop().open(sh.f);
381: } catch (Exception e) {
382: e.printStackTrace();
383: try {
384: //TODO: also not working
385: SysUtils.openDocumentInSystem(
386: ("" + sh.f).replace(" ",
387: "%20"), false);
388: } catch (Exception e2) {
389: e2.printStackTrace();
390: }
391: }
392: }
393: });
394:
395: if (sh.f.isFile()) {
396: JMenuItem openi = new JMenuItem(
397: "open in internal text editor",
398: Icons.FileIcon.textFile(16));
399: pop.add(openi);
400: openi.addActionListener(new ActionListener() {
401: public void actionPerformed(ActionEvent ae) {
402:
403: SimpleEditor sed = new SimpleEditor(""
404: + sh.f.getAbsolutePath(), true,
405: false);
406: try {
407: sed.setText(sh.f);
408: } catch (Exception e) {
409: e.printStackTrace();
410: }
411: }
412: });
413:
414: JMenuItem openp = new JMenuItem(
415: "open parent folder");
416: pop.add(openp);
417: openp.addActionListener(new ActionListener() {
418: public void actionPerformed(ActionEvent ae) {
419:
420: //SysUtils.op TODO.
421: try {
422: Desktop.getDesktop().open(
423: sh.f.getParentFile());
424: } catch (Exception e) {
425: e.printStackTrace();
426: }
427:
428: }
429: });
430: }
431:
432: pop.show(table, me.getX(), me.getY());
433: }
434: });
435:
436: d.setVisible(true); // MODAL.
437:
438: if (ccp.getWasAccepted()
439: && table.getSelectedRowCount() == 1) {
440: int pos = stm.getIndexInUnsortedFromTablePos(table
441: .getSelectedRow());
442: fileChooser.setSelectedFile(hits.get(pos).f);
443: }
444: stm.removeOldListeners();
445: }
446:
447: hits.clear();
448: }
449:
450: void search(final boolean recurse, final List<JFile> hits,
451: final File dir, final String toSearchUP,
452: final int baseLength, final long after,
453: final ProgressModalDialog pmd) {
454: java.io.FileFilter ff = new java.io.FileFilter() {
455: public final boolean accept(final File f) {
456: if (f.isDirectory())
457: return true; // always pass directories
458: if (after > 0 && f.lastModified() < after)
459: return false;
460:
461: if (toSearchUP.length() > 0) {
462: String relName = f.getAbsolutePath();
463: if (relName.length() < baseLength) {
464: System.out.println("Cannot relativize name: "
465: + relName);
466: } else {
467: relName = relName.substring(baseLength);
468: }
469:
470: if (relName.toUpperCase().indexOf(toSearchUP) < 0)
471: return false;
472: }
473: return true;
474: }
475: };
476:
477: // only include dir entries if not searching recent.
478: // its just nicer...
479:
480: search(ff, recurse, after < 1, hits, dir, baseLength, pmd);
481: }
482:
483: void search(final java.io.FileFilter ff, boolean recurse,
484: boolean includeDirsInHits, final List<JFile> hits,
485: final File dir, int baseLength,
486: final ProgressModalDialog pmd) {
487: if (pmd.getWasCancelled())
488: return;
489:
490: File[] childs = ff != null ? dir.listFiles(ff) : dir
491: .listFiles();
492:
493: if (childs == null) {
494: System.out.println("Null childs for " + dir);
495: return;
496: }
497:
498: for (final File ci : childs) {
499: String ap = ci.getAbsolutePath();
500: final String relName;
501: if (ap.length() < baseLength) {
502: relName = ap;
503: System.out.println("Cannot relativize name: " + ap);
504: } else {
505: relName = ap.substring(baseLength);
506: }
507:
508: // add dirs before childs...
509: if (includeDirsInHits || !ci.isDirectory()) {
510: hits.add(new JFile(ci, relName));
511: }
512:
513: if (ci.isDirectory() && recurse) {
514: search(ff, recurse, includeDirsInHits, hits, ci,
515: baseLength, pmd);
516: }
517: }
518:
519: pmd.setCommentLabel("" + hits.size() + " files found");
520: }
521:
522: private void filterAction() {
523: if (filteredFilter == null) {
524: filteredFilter = new javax.swing.filechooser.FileFilter() {
525: public String getDescription() {
526: if (originalFilter != null) {
527: return "Filtered "
528: + originalFilter.getDescription();
529: }
530: return "Filtered files";
531: }
532:
533: public boolean accept(java.io.File f) {
534: // don't accept files also refused from original
535: if (originalFilter != null) {
536: if (!originalFilter.accept(f))
537: return false;
538: }
539: String nameLow = f.getName().toLowerCase();
540: String toSearch = searchField.getText().trim()
541: .toLowerCase();
542: if (toSearch.length() == 0)
543: return true;
544: if (nameLow.indexOf(toSearch) == -1)
545: return false;
546: return true;
547: }
548: };
549:
550: fileChooser.setFileFilter(filteredFilter);
551: }
552: fileChooser.rescanCurrentDirectory();
553: }
554:
555: /** Standalone app.
556: */
557: public static void main(String[] a) {
558: JFileChooser fs = new JFileChooser();
559: FileChooserFilter fsf = new FileChooserFilter(fs);
560: fs.setAccessory(fsf);
561: fs.setFileSelectionMode(fs.FILES_AND_DIRECTORIES);
562: fs.showOpenDialog(null);
563: System.exit(0);
564: }
565:
566: }
|