001: package tide.sources;
002:
003: import java.awt.EventQueue;
004: import java.awt.Color;
005: import java.awt.Graphics;
006: import java.awt.Component;
007: import javax.swing.table.*;
008: import java.util.*;
009: import tide.editor.MainEditorFrame;
010: import java.awt.event.*;
011: import snow.utils.storage.FileUtils;
012: import snow.utils.DateUtils;
013: import java.awt.BorderLayout;
014: import snow.utils.gui.CloseControlPanel;
015: import javax.swing.*;
016: import java.util.List;
017: import snow.sortabletable.*;
018:
019: /** Displays a practical table overview (filterable) of some project branch.
020: * (sources or libs).
021: */
022: public final class PackagesExplorer extends JDialog {
023: final List<Pack> packs = new ArrayList<Pack>();
024: final String[] columns = new String[] { "package", "sources",
025: "size [kB]", "#using", "#used", "declared", "median date",
026: "last modified dates [min, median, max]" };
027: // todo: show declared types and subtypes
028: final JTable table;
029: final SortableTableModel stm;
030: final PackagesTableModel ftm;
031: final Renderer renderer;
032: private final static String TITLE = "Project packages explorer";
033:
034: long dateOverallMin = Long.MAX_VALUE, dateOverallMax = -1;
035:
036: public PackagesExplorer(final List<? extends FileItem> items,
037: JFrame parent) {
038: super (parent, TITLE + " (" + items.size() + " files", false); // packages count is added after analysis in title
039: this .analyseInPackages(items);
040: setTitle(getTitle() + ", " + packs.size() + " packages) "
041: + " [dates range: "
042: + DateUtils.dateFormatMDY.format(dateOverallMin)
043: + " - "
044: + DateUtils.dateFormatMDY.format(dateOverallMax) + "]");
045:
046: final CloseControlPanel ccp = new CloseControlPanel(this ,
047: false, true, "Close");
048: add(ccp, BorderLayout.SOUTH);
049:
050: ftm = new PackagesTableModel();
051: stm = new SortableTableModel(ftm, 7, false); // so we see first the last modified packs
052: table = new JTable(stm);
053: renderer = new Renderer();
054: stm.installGUI(table);
055: table.setDefaultRenderer(Pack.class, renderer);
056:
057: add(new JScrollPane(table), BorderLayout.CENTER);
058:
059: final MultiSearchPanel msp = new MultiSearchPanel("Filter: ",
060: null, stm);
061: add(msp, BorderLayout.NORTH);
062:
063: EventQueue.invokeLater(new Runnable() {
064: public void run() {
065: msp.requestFocus();
066: }
067: });
068:
069: setSize(850, 700);
070: setLocation(150, 50);
071: setVisible(true);
072: /*
073: table.addMouseListener(new MouseAdapter(){
074: @Override public void mousePressed(MouseEvent me)
075: {
076: //popup/or double click jump to TODO
077: if(me.getClickCount()==2)
078: {
079: int posMod = stm.getIndexInUnsortedFromTablePos(table.getSelectedRow());
080: Pack fi = packs.get(posMod);
081: //MainEditorFrame.instance.setSourceOrItemToEditOrView(fi, true);
082: }
083: }
084: @Override public void mouseReleased(MouseEvent me)
085: {
086: }
087: }); */
088: }
089:
090: private void analyseInPackages(List<? extends FileItem> items) {
091: Map<String, Pack> packsM = new HashMap<String, Pack>();
092: for (FileItem it : items) {
093: if (!packsM.containsKey(it.getPackageName())) {
094: packsM.put(it.getPackageName(), new Pack(it
095: .getPackageName()));
096: }
097: packsM.get(it.getPackageName()).add(it);
098: }
099: packs.clear();
100: packs.addAll(packsM.values());
101: packsM.clear();
102: Collections.sort(packs);
103: for (Pack pi : packs) {
104: pi.endStat();
105: }
106: }
107:
108: class Pack implements Comparable<Pack> {
109: final String name;
110: long dateMin = Long.MAX_VALUE, dateMax = -1; //min: first created (TODO?), max: last last-mod
111: long depUsed = 0; // -1 == na (not actual)
112: long depUsing = 0; // -1 == na (not actual)
113: long charSize = 0;
114: long median = 0;
115: int sources = 0; // or class
116: int types = 0; // for sources: the number of declared types
117: List<Long> dates = new ArrayList<Long>(); // used for median
118:
119: public Pack(String name) {
120: this .name = name;
121: }
122:
123: public int compareTo(Pack b) {
124: return name.compareTo(b.name);
125: }
126:
127: public void add(FileItem fi) {
128: sources++; // or class.
129:
130: charSize += fi.getFileSize();
131: long lm = fi.getLastModified();
132: dates.add(lm);
133: if (lm < dateMin)
134: dateMin = lm;
135: if (lm > dateMax)
136: dateMax = lm;
137:
138: if (lm < dateOverallMin)
139: dateOverallMin = lm;
140: if (lm > dateOverallMax)
141: dateOverallMax = lm;
142:
143: if (fi instanceof SourceFile) {
144: SourceFile sf = (SourceFile) fi;
145: if (sf.sourceFileDependencies.areDependenciesActual()) {
146: depUsing += sf.sourceFileDependencies
147: .getClassesUsingThis_REF_().size();
148: depUsed += sf.sourceFileDependencies
149: .getClassesUsedBy_REF_().size();
150: } else {
151: // Invaliate (shows "na")
152: depUsing = -1;
153: depUsed = -1;
154: }
155: types += sf.sourceFileDependencies
156: .getDeclaredTypesNames_REF_().size();
157: } else {
158: types++;
159: depUsing = -1; // Invaliate (shows "na")
160: depUsed = -1;
161: }
162: }
163:
164: /** must be called at the end, after all sources have been added */
165: public void endStat() {
166: if (!dates.isEmpty()) {
167: median = dates.get(dates.size() / 2);
168: }
169: dates.clear(); // no more used.
170: }
171: }
172:
173: class PackagesTableModel extends FineGrainTableModel {
174: public Object getValueAt(int row, int col) {
175: Pack it = packs.get(row);
176: if (col == 0) {
177: if (it.name.length() == 0)
178: return "<unnamed scope>";
179: return it.name;
180: }
181: if (col == 1) {
182: return it.sources; //DateUtils.formatDateAndTimeHuman( it.getLastModified() );
183: }
184: if (col == 2) {
185: return it.charSize / 1000; //DateUtils.formatDateAndTimeHuman( it.getLastModified() );
186: }
187: if (col == 3) {
188: if (it.depUsing < 0)
189: return "na";
190: return it.depUsing;
191: }
192: if (col == 4) {
193: if (it.depUsed < 0)
194: return "na";
195: return it.depUsed;
196: }
197: if (col == 5) {
198: return it.types;
199: }
200: if (col == 6) {
201: return DateUtils.dateFormatMDY.format(it.median);
202: }
203: if (col == 7) {
204: return it;
205: /*DateUtils.dateFormatMDY.format( it.dateMin ) + " - "+ DateUtils.dateFormatMDY.format( it.median )
206: +" - "+DateUtils.dateFormatMDY.format( it.dateMax );*/
207: }
208:
209: return "?";
210: }
211:
212: public int getColumnAlignment(int column) {
213: if (column == 0)
214: return JLabel.LEFT;
215: return JLabel.RIGHT;
216: }
217:
218: int[] COLUMN_PREFERED_SIZES = new int[] { 26, 4, 4, 4, 4, 4, 8,
219: 20 };
220:
221: @Override
222: public int getPreferredColumnWidth(int column) {
223: if (column >= 0 && column < COLUMN_PREFERED_SIZES.length)
224: return COLUMN_PREFERED_SIZES[column];
225: return -1;
226: }
227:
228: @Override
229: public int compareForColumnSort(int row1, int row2, int col) {
230: if (col == 1) {
231: return Integer.valueOf(packs.get(row1).sources)
232: .compareTo(packs.get(row2).sources);
233: }
234:
235: if (col == 6) {
236: return Long.valueOf(packs.get(row1).median).compareTo(
237: packs.get(row2).median);
238: }
239: if (col == 7) {
240: // of interrest: look at last mod ! first not very useful
241: return Long.valueOf(packs.get(row1).dateMax).compareTo(
242: packs.get(row2).dateMax);
243: }
244:
245: // use the getValueAt
246: return super .compareForColumnSort(row1, row2, col);
247: }
248:
249: @Override
250: public String getColumnName(int col) {
251: return columns[col];
252: }
253:
254: public int getRowCount() {
255: return packs.size();
256: }
257:
258: public int getColumnCount() {
259: return columns.length;
260: }
261:
262: @Override
263: public boolean isCellEditable(int r, int c) {
264: return false;
265: }
266:
267: }
268:
269: class Renderer extends DefaultTableCellRenderer {
270: RendererIm rim = new RendererIm();
271:
272: public Component getTableCellRendererComponent(JTable table,
273: Object value, boolean isSelected, boolean hasFocus,
274: int row, int column) {
275: if (column == 7) {
276: //rim.setPreferredSize( getPreferredSize() );
277: if (isSelected) {
278: rim.setBackground(UIManager
279: .getColor("Table.selectionBackground"));
280: } else {
281: rim.setBackground(UIManager
282: .getColor("Table.background"));
283: }
284: rim.set((Pack) value);
285: return rim;
286: }
287: return super .getTableCellRendererComponent(table, value,
288: isSelected, hasFocus, row, column);
289: }
290: }
291:
292: class RendererIm extends JPanel {
293: Pack pi;
294:
295: public RendererIm() {
296: super ();
297: //setBackground(table.getBackground()); //Color.white);
298: //setSize(200,20);
299: }
300:
301: public void set(Pack pi) {
302: this .pi = pi;
303: }
304:
305: @Override
306: public void paintComponent(Graphics gr) {
307: super .paintComponent(gr); // border, background, ...
308: if (pi == null)
309: return;
310: if (dateOverallMax < 0)
311: return;
312:
313: // gray bloc from min to max
314: gr.setColor(Color.lightGray);
315: int min = (int) (relPosDate(pi.dateMin) * getWidth());
316: int max = (int) (relPosDate(pi.dateMax) * getWidth());
317: gr.fillRect(min, 2, max - min, getHeight() - 4);
318: int med = (int) (relPosDate(pi.median) * getWidth());
319: gr.setColor(Color.darkGray);
320: gr.fillRect(med, 0, 1, getHeight());
321: }
322: }
323:
324: // in [0,1]
325: private double relPosDate(long d) {
326: return (1.0 * (d - dateOverallMin))
327: / (dateOverallMax - dateOverallMin);
328: }
329:
330: }
|