001    /*
002     * Copyright 2007 Jeffrey Palm.
003     */
004    
005    import java.awt.*;
006    import java.awt.event.*;
007    import java.io.*;
008    import java.util.*;
009    import java.util.List;
010    import javax.swing.*;
011    import javax.swing.event.*;
012    import javax.swing.table.*;
013    
014    class MainFrame extends JFrame {
015    
016      private SortableTableExample t;
017      private final tables del;
018    
019      MainFrame(tables del) {   
020        super(Constants.TITLE);
021        this.del = del;
022    
023        JToolBar tb = new JToolBar();
024        tb.add(new JButton(new AbstractAction("Quit") {
025            public void actionPerformed(ActionEvent e) {
026              System.exit(0);
027            }
028          }));
029        tb.add(new JButton(new AbstractAction("Open") {
030            public void actionPerformed(ActionEvent e) {
031              try {
032                JFileChooser fc = new JFileChooser();
033                int res = fc.showOpenDialog(MainFrame.this);
034                if (res != JFileChooser.APPROVE_OPTION) return;
035                File sel = fc.getSelectedFile();
036                Util.log(this,"have file: " + sel);
037              } catch (Exception ee) {ee.printStackTrace();}
038            }
039          }));
040        tb.add(new JButton(new AbstractAction("Paste") {
041            public void actionPerformed(ActionEvent e) {
042              try {
043                final PasteFrame[] pfs = new PasteFrame[1];
044                PasteFrame pf = new PasteFrame(new Runnable() {
045                    public void run() {
046                      String s = pfs[0].getInnerText();
047                      Finder f = createFinder(s);
048                      if (f != null) find(f);
049                    }
050                  });
051                pfs[0] = pf;
052                pf.pack();
053                CenterHelper.center(pf);
054                pf.setVisible(true);
055              } catch (Exception ee) {ee.printStackTrace();}
056            }
057          }));
058        tb.add(new JButton(new AbstractAction("Output") {
059            public void actionPerformed(ActionEvent e) {
060              try {
061    
062              } catch (Exception ee) {ee.printStackTrace();}
063            }
064          }));
065    
066        add(tb,BorderLayout.NORTH);
067    
068        this.t = new SortableTableExample();
069        getContentPane().add(t, BorderLayout.CENTER);
070        setSize(900,600);
071        setPreferredSize(new Dimension(900,600));
072        
073        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
074    
075      }
076    
077      /**
078       * Decide what kind of finder to use for the plain text passed in.
079       * @param s plain text -- maybe CSV
080       */
081      private Finder createFinder(String s) {
082        //
083        // This is going to be be stupid But we'll look at all the lines
084        // and use the delimeter that shows up the same number of times on
085        // each line
086        //
087        char[] delims = {'\t',',',':'};
088        String delimStr = null;
089        outer: for (int i=0; i<delims.length; i++) {
090          char delim = delims[i];
091          BufferedReader in = null;
092          try {
093            in = new BufferedReader(new InputStreamReader(new StringInputStream(s)));
094            String line;
095            int num = -1;
096            int cnt = 0;
097            inner: while ((line = in.readLine()) != null) {
098              cnt = 0;
099              for (int j=0; j<line.length(); j++) {
100                if (line.charAt(j) == delim) cnt++;
101              }
102              System.out.println(delim + " " + num + ":" + cnt);
103              if (num == -1) { // first time
104                num = cnt;
105              } else if (cnt > 0) {
106                if (num != cnt) break inner;
107              }
108            }
109            String nextLine = in.readLine();
110            //
111            // If we're here we have a delim to use
112            //
113            if (nextLine != null && (num <= 0 || cnt != num)) continue;
114            delimStr = String.valueOf(delim);
115            break outer;
116          } catch (Exception e) {
117            Util.handle(this,e);
118          } finally {
119            try {if (in != null) in.close();} catch (Exception ee) {Util.handle(this,ee);}
120          }
121        }
122        Util.log(this,"delim "+delimStr);
123        if (delimStr != null) {
124          Util.log(this,"have a finder");
125          return new DelimFinder(delimStr,s);
126        }
127        return null;
128      }
129    
130      private boolean running = false;
131      
132      private void find(final Finder finder) {
133        
134        // only run one at a time
135        if (running) return;
136    
137        try {
138          new Thread(new Runnable() {
139              public void run() {
140                running = true;
141                try {
142                  findInternal(finder);
143                } catch (Exception e) {
144                  e.printStackTrace();
145                } finally {
146                  running = false;
147                }
148              }
149            }).start();
150        } catch (Exception e) {e.printStackTrace();}
151      }
152    
153      private void findInternal(Finder finder) throws Exception {
154    
155        final P p = new P();
156    
157        final boolean going[] = new boolean[]{true};
158        
159        JFrame info = new JFrame();
160        info.getContentPane().add(p);
161        info.addWindowListener(new WindowAdapter() {
162            public void windowClosing(WindowEvent e) {
163              going[0] = false;
164            }
165          });
166        info.pack();
167        CenterHelper.center(info);
168        info.setVisible(true);
169    
170        
171        p.setMax(finder.getWork());
172        
173        int i = 0;
174        int total = 0;
175        
176        
177        t.removeAllRows();
178    
179        boolean first = true;
180        while (finder.hasNext()) {
181          List ress = finder.next(p);
182          for (Iterator jt = ress.iterator(); jt.hasNext();) {
183            List res = (List)jt.next();
184            if (res == null) continue;        
185            Object[] data = res.toArray();
186            if (first) {
187              String[] headerStr = new String[data.length];
188              for (int j=0; j<headerStr.length; j++) headerStr[j] = "";
189              t.setHeader(headerStr);
190              first = false;
191            }
192            t.addRow(data);
193            t.repaint();
194          }        
195          if (!going[0]) break;
196        }
197        t.repaint();
198    
199        info.setVisible(false);
200        info.dispose();
201        
202      }
203      //
204      // http://www.java2s.com/Code/Java/Swing-Components/SortableTableExample.htm
205      //
206      /**
207       * @version 1.0 02/25/99
208       */
209      class SortableTableExample extends JPanel { 
210    
211        void removeAllRows() {
212          while (dm.getRowCount() > 0) dm.removeRow(0);
213        }
214    
215    
216        void addRow(Object[] row) {
217          dm.addRow(row);
218        }
219    
220        final SortableTableModel dm;
221        final JTable table;
222    
223        SortableTableExample() {
224          this(new String[]{ });
225        }
226    
227        void setHeader(String[] headerStr) {
228          int[] columnWidth = new int[headerStr.length];
229          for (int i=0; i<columnWidth.length; i++) columnWidth[i] = 150;
230          dm.setColumnIdentifiers(headerStr);
231          SortButtonRenderer renderer = new SortButtonRenderer();
232          TableColumnModel model = table.getColumnModel();
233          int n = headerStr.length;
234          for (int i = 0; i < n; i++) {
235            model.getColumn(i).setHeaderRenderer(renderer);
236            model.getColumn(i).setPreferredWidth(columnWidth[i]);
237          }
238    
239          JTableHeader header = table.getTableHeader();
240          header.addMouseListener(new HeaderListener(header, renderer));
241        }
242    
243        public SortableTableExample(String[] headerStr) {
244          setLayout(new BorderLayout());    
245    
246          dm = new SortableTableModel() {
247              public Class getColumnClass(int col) {
248                return String.class;
249              }
250    
251              public boolean isCellEditable(int row, int col) {
252                return false;
253              }
254    
255            };
256    
257          table = new JTable(dm);
258    
259          table.setShowGrid(false);
260          table.setShowVerticalLines(true);
261          table.setShowHorizontalLines(false);
262          table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
263          table.setColumnSelectionAllowed(true);
264    
265          class Lis implements MouseListener,KeyListener {
266    
267            private int keyDown = -1;
268            
269            // MouseListener
270            public void mouseClicked(MouseEvent e) {}
271            public void mousePressed(MouseEvent e) {
272              if (keyDown != KeyEvent.VK_CONTROL) return;
273              //
274              // Show a menu of all the things we can do
275              //
276              showMenu();
277            }
278            public void mouseReleased(MouseEvent e) {}
279            public void mouseEntered(MouseEvent e) {}
280            public void mouseExited(MouseEvent e) {}
281    
282            // KeyListener
283            public void keyTyped(KeyEvent e) {}
284            public void keyPressed(KeyEvent e) {keyDown = e.getKeyCode();}
285            public void keyReleased(KeyEvent e) {keyDown = -1;}
286    
287          }
288          Lis lis = new Lis();
289          table.addMouseListener(lis);
290          table.addKeyListener(lis);
291    
292          setHeader(headerStr);
293    
294          JScrollPane pane = new JScrollPane(table);
295          add(pane, BorderLayout.CENTER);
296        }
297    
298        private void showMenu() {
299          Util.log(this,"Showing menu");
300          //
301          // Collect all the selected values
302          // TODO: This sucks
303          List sel = new ArrayList();
304          for (int i=0, I=table.getRowCount(); i<I; i++) {
305            for (int j=0, J=table.getColumnCount(); j<J; j++) {
306              if (table.isCellSelected(i,j)) sel.add(table.getValueAt(i,j));
307            }
308          }
309          //
310          // Represent the actions we can do
311          //
312          List folds = del.getFolds();
313          Collections.sort(folds, new Comparator() {
314              public int compare(Object o1, Object o2) {
315                return ((Fold)o1).name().compareTo(((Fold)o2).name());
316              }
317            });
318          Fold selFold = (Fold)JOptionPane.showInputDialog(this,"Select a function","Select a function",
319                                                           JOptionPane.INFORMATION_MESSAGE,
320                                                           null,folds.toArray(),folds.get(0));
321          if (selFold != null) {
322            Object res = selFold.fold(sel);
323            JPanel p = Util.xp();
324            p.add(new JLabel("The " + selFold.name() + " is "));
325            JTextField txt = new JTextField(String.valueOf(res));
326            p.add(txt);
327            Util.showMsg(p);
328          }
329        }
330    
331        class HeaderListener extends MouseAdapter {
332          JTableHeader header;
333    
334          SortButtonRenderer renderer;
335    
336          HeaderListener(JTableHeader header, SortButtonRenderer renderer) {
337            this.header = header;
338            this.renderer = renderer;
339          }
340    
341          public void mousePressed(MouseEvent e) {
342            int col = header.columnAtPoint(e.getPoint());
343            int sortCol = header.getTable().convertColumnIndexToModel(col);
344            renderer.setPressedColumn(col);
345            renderer.setSelectedColumn(col);
346            header.repaint();
347    
348            if (header.getTable().isEditing()) {
349              header.getTable().getCellEditor().stopCellEditing();
350            }
351    
352            boolean isAscent;
353            if (SortButtonRenderer.DOWN == renderer.getState(col)) {
354              isAscent = true;
355            } else {
356              isAscent = false;
357            }
358            ((SortableTableModel) header.getTable().getModel()).sortByColumn(sortCol, isAscent);
359          }
360          
361          public void mouseReleased(MouseEvent e) {
362            int col = header.columnAtPoint(e.getPoint());
363            renderer.setPressedColumn(-1); // clear
364            header.repaint();
365          }
366        }
367    
368      }
369    
370      static class SortableTableModel extends DefaultTableModel {
371    
372        int[] indexes;
373    
374        TableSorter sorter;
375    
376        public SortableTableModel() {
377        }
378    
379        public Object getValueAt(int row, int col) {
380          int rowIndex = row;
381          if (indexes != null) {
382            rowIndex = indexes[row];
383          }
384          return super.getValueAt(rowIndex, col);
385        }
386    
387        public void setValueAt(Object value, int row, int col) {
388          int rowIndex = row;
389          if (indexes != null) {
390            rowIndex = indexes[row];
391          }
392          super.setValueAt(value, rowIndex, col);
393        }
394    
395        public void sortByColumn(int column, boolean isAscent) {
396          if (sorter == null) {
397            sorter = new TableSorter(this);
398          }
399          sorter.sort(column, isAscent);
400          fireTableDataChanged();
401        }
402    
403        public int[] getIndexes() {
404          int n = getRowCount();
405          if (indexes != null) {
406            if (indexes.length == n) {
407              return indexes;
408            }
409          }
410          indexes = new int[n];
411          for (int i = 0; i < n; i++) {
412            indexes[i] = i;
413          }
414          return indexes;
415        }
416      }
417    
418      static class TableSorter {
419        SortableTableModel model;
420    
421        public TableSorter(SortableTableModel model) {
422          this.model = model;
423        }
424    
425        //n2 selection
426        public void sort(int column, boolean isAscent) {
427          int n = model.getRowCount();
428          int[] indexes = model.getIndexes();
429    
430          for (int i = 0; i < n - 1; i++) {
431            int k = i;
432            for (int j = i + 1; j < n; j++) {
433              if (isAscent) {
434                if (compare(column, j, k) < 0) {
435                  k = j;
436                }
437              } else {
438                if (compare(column, j, k) > 0) {
439                  k = j;
440                }
441              }
442            }
443            int tmp = indexes[i];
444            indexes[i] = indexes[k];
445            indexes[k] = tmp;
446          }
447        }
448    
449        // comparaters
450    
451        public int compare(int column, int row1, int row2) {
452          Object o1 = model.getValueAt(row1, column);
453          Object o2 = model.getValueAt(row2, column);
454          if (o1 == null && o2 == null) {
455            return 0;
456          } else if (o1 == null) {
457            return -1;
458          } else if (o2 == null) {
459            return 1;
460          } else {
461            Class type = model.getColumnClass(column);
462            if (type.getSuperclass() == Number.class) {
463              return compare((Number) o1, (Number) o2);
464            } else if (type == String.class) {
465              return ((String) o1).compareTo((String) o2);
466            } else if (type == Date.class) {
467              return compare((Date) o1, (Date) o2);
468            } else if (type == Boolean.class) {
469              return compare((Boolean) o1, (Boolean) o2);
470            } else {
471              return ((String) o1).compareTo((String) o2);
472            }
473          }
474        }
475    
476        public int compare(Number o1, Number o2) {
477          double n1 = o1.doubleValue();
478          double n2 = o2.doubleValue();
479          if (n1 < n2) {
480            return -1;
481          } else if (n1 > n2) {
482            return 1;
483          } else {
484            return 0;
485          }
486        }
487    
488        public int compare(Date o1, Date o2) {
489          long n1 = o1.getTime();
490          long n2 = o2.getTime();
491          if (n1 < n2) {
492            return -1;
493          } else if (n1 > n2) {
494            return 1;
495          } else {
496            return 0;
497          }
498        }
499    
500        public int compare(Boolean o1, Boolean o2) {
501          boolean b1 = o1.booleanValue();
502          boolean b2 = o2.booleanValue();
503          if (b1 == b2) {
504            return 0;
505          } else if (b1) {
506            return 1;
507          } else {
508            return -1;
509          }
510        }
511    
512      }
513    
514      static class SortButtonRenderer extends JButton implements TableCellRenderer {
515        public static final int NONE = 0;
516    
517        public static final int DOWN = 1;
518    
519        public static final int UP = 2;
520    
521        int pushedColumn;
522    
523        Hashtable state;
524    
525        JButton downButton, upButton;
526    
527        public SortButtonRenderer() {
528          pushedColumn = -1;
529          state = new Hashtable();
530    
531          setMargin(new Insets(0, 0, 0, 0));
532          setHorizontalTextPosition(LEFT);
533          setIcon(new BlankIcon());
534    
535          downButton = new JButton();
536          downButton.setMargin(new Insets(0, 0, 0, 0));
537          downButton.setHorizontalTextPosition(LEFT);
538          downButton
539            .setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
540          downButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN,
541                                                       false, true));
542    
543          upButton = new JButton();
544          upButton.setMargin(new Insets(0, 0, 0, 0));
545          upButton.setHorizontalTextPosition(LEFT);
546          upButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
547          upButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.UP, false,
548                                                     true));
549    
550        }
551    
552        public Component getTableCellRendererComponent(JTable table, Object value,
553                                                       boolean isSelected, boolean hasFocus, 
554                                                       int row, int column) {
555          JButton button = this;
556          Object obj = state.get(new Integer(column));
557          if (obj != null) {
558            if (((Integer) obj).intValue() == DOWN) {
559              button = downButton;
560            } else {
561              button = upButton;
562            }
563          }
564          button.setText((value == null) ? "" : value.toString());
565          boolean isPressed = (column == pushedColumn);
566          button.getModel().setPressed(isPressed);
567          button.getModel().setArmed(isPressed);
568          return button;
569        }
570    
571        public void setPressedColumn(int col) {
572          pushedColumn = col;
573        }
574    
575        public void setSelectedColumn(int col) {
576          if (col < 0)
577            return;
578          Integer value = null;
579          Object obj = state.get(new Integer(col));
580          if (obj == null) {
581            value = new Integer(DOWN);
582          } else {
583            if (((Integer) obj).intValue() == DOWN) {
584              value = new Integer(UP);
585            } else {
586              value = new Integer(DOWN);
587            }
588          }
589          state.clear();
590          state.put(new Integer(col), value);
591        }
592    
593        public int getState(int col) {
594          int retValue;
595          Object obj = state.get(new Integer(col));
596          if (obj == null) {
597            retValue = NONE;
598          } else {
599            if (((Integer) obj).intValue() == DOWN) {
600              retValue = DOWN;
601            } else {
602              retValue = UP;
603            }
604          }
605          return retValue;
606        }
607      }
608    
609      static class BevelArrowIcon implements Icon {
610        public static final int UP = 0; // direction
611    
612        public static final int DOWN = 1;
613    
614        private static final int DEFAULT_SIZE = 11;
615    
616        private Color edge1;
617    
618        private Color edge2;
619    
620        private Color fill;
621    
622        private int size;
623    
624        private int direction;
625    
626        public BevelArrowIcon(int direction, boolean isRaisedView,
627                              boolean isPressedView) {
628          if (isRaisedView) {
629            if (isPressedView) {
630              init(UIManager.getColor("controlLtHighlight"), UIManager
631                   .getColor("controlDkShadow"), UIManager
632                   .getColor("controlShadow"), DEFAULT_SIZE, direction);
633            } else {
634              init(UIManager.getColor("controlHighlight"), UIManager
635                   .getColor("controlShadow"), UIManager
636                   .getColor("control"), DEFAULT_SIZE, direction);
637            }
638          } else {
639            if (isPressedView) {
640              init(UIManager.getColor("controlDkShadow"), UIManager
641                   .getColor("controlLtHighlight"), UIManager
642                   .getColor("controlShadow"), DEFAULT_SIZE, direction);
643            } else {
644              init(UIManager.getColor("controlShadow"), UIManager
645                   .getColor("controlHighlight"), UIManager
646                   .getColor("control"), DEFAULT_SIZE, direction);
647            }
648          }
649        }
650    
651        public BevelArrowIcon(Color edge1, Color edge2, Color fill, int size,
652                              int direction) {
653          init(edge1, edge2, fill, size, direction);
654        }
655    
656        public void paintIcon(Component c, Graphics g, int x, int y) {
657          switch (direction) {
658          case DOWN:
659            drawDownArrow(g, x, y);
660            break;
661          case UP:
662            drawUpArrow(g, x, y);
663            break;
664          }
665        }
666    
667        public int getIconWidth() {
668          return size;
669        }
670    
671        public int getIconHeight() {
672          return size;
673        }
674    
675        private void init(Color edge1, Color edge2, Color fill, int size,
676                          int direction) {
677          this.edge1 = edge1;
678          this.edge2 = edge2;
679          this.fill = fill;
680          this.size = size;
681          this.direction = direction;
682        }
683    
684        private void drawDownArrow(Graphics g, int xo, int yo) {
685          g.setColor(edge1);
686          g.drawLine(xo, yo, xo + size - 1, yo);
687          g.drawLine(xo, yo + 1, xo + size - 3, yo + 1);
688          g.setColor(edge2);
689          g.drawLine(xo + size - 2, yo + 1, xo + size - 1, yo + 1);
690          int x = xo + 1;
691          int y = yo + 2;
692          int dx = size - 6;
693          while (y + 1 < yo + size) {
694            g.setColor(edge1);
695            g.drawLine(x, y, x + 1, y);
696            g.drawLine(x, y + 1, x + 1, y + 1);
697            if (0 < dx) {
698              g.setColor(fill);
699              g.drawLine(x + 2, y, x + 1 + dx, y);
700              g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
701            }
702            g.setColor(edge2);
703            g.drawLine(x + dx + 2, y, x + dx + 3, y);
704            g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
705            x += 1;
706            y += 2;
707            dx -= 2;
708          }
709          g.setColor(edge1);
710          g.drawLine(xo + (size / 2), yo + size - 1, xo + (size / 2), yo + size
711                     - 1);
712        }
713    
714        private void drawUpArrow(Graphics g, int xo, int yo) {
715          g.setColor(edge1);
716          int x = xo + (size / 2);
717          g.drawLine(x, yo, x, yo);
718          x--;
719          int y = yo + 1;
720          int dx = 0;
721          while (y + 3 < yo + size) {
722            g.setColor(edge1);
723            g.drawLine(x, y, x + 1, y);
724            g.drawLine(x, y + 1, x + 1, y + 1);
725            if (0 < dx) {
726              g.setColor(fill);
727              g.drawLine(x + 2, y, x + 1 + dx, y);
728              g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
729            }
730            g.setColor(edge2);
731            g.drawLine(x + dx + 2, y, x + dx + 3, y);
732            g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
733            x -= 1;
734            y += 2;
735            dx += 2;
736          }
737          g.setColor(edge1);
738          g.drawLine(xo, yo + size - 3, xo + 1, yo + size - 3);
739          g.setColor(edge2);
740          g.drawLine(xo + 2, yo + size - 2, xo + size - 1, yo + size - 2);
741          g.drawLine(xo, yo + size - 1, xo + size, yo + size - 1);
742        }
743    
744      }
745    
746      static class BlankIcon implements Icon {
747        private Color fillColor;
748    
749        private int size;
750    
751        public BlankIcon() {
752          this(null, 11);
753        }
754    
755        public BlankIcon(Color color, int size) {
756          //UIManager.getColor("control")
757          //UIManager.getColor("controlShadow")
758          fillColor = color;
759    
760          this.size = size;
761        }
762    
763        public void paintIcon(Component c, Graphics g, int x, int y) {
764          if (fillColor != null) {
765            g.setColor(fillColor);
766            g.drawRect(x, y, size - 1, size - 1);
767          }
768        }
769    
770        public int getIconWidth() {
771          return size;
772        }
773    
774        public int getIconHeight() {
775          return size;
776        }
777      }
778    
779    
780    }