Java tutorial
/* * Copyright (c) 2003 Frank Sauer. All rights reserved. Licenced under CPL 1.0 * (Common Public License Version 1.0). The licence is available at * http://www.eclipse.org/legal/cpl-v10.html. DISCLAIMER OF WARRANTIES AND * LIABILITY: THE SOFTWARE IS PROVIDED "AS IS". THE AUTHOR MAKES NO * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS OR IMPLIED. TO THE EXTENT NOT * PROHIBITED BY LAW, IN NO EVENT WILL THE AUTHOR BE LIABLE FOR ANY DAMAGES, * INCLUDING WITHOUT LIMITATION, LOST REVENUE, PROFITS OR DATA, OR FOR SPECIAL, * INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO ANY * FURNISHING, PRACTICING, MODIFYING OR ANY USE OF THE SOFTWARE, EVEN IF THE * AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. $id$ */ package net.sourceforge.metrics.ui.layeredpackagegraph; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map; import java.util.Set; import net.sourceforge.metrics.builder.IMetricsProgressListener; import net.sourceforge.metrics.builder.MetricsBuilder; import net.sourceforge.metrics.core.IExporter; import net.sourceforge.metrics.core.Log; import net.sourceforge.metrics.core.MetricsPlugin; import net.sourceforge.metrics.core.sources.AbstractMetricSource; import net.sourceforge.metrics.core.sources.Dispatcher; import net.sourceforge.metrics.core.sources.IGraphContributor; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.custom.TableTreeItem; import org.eclipse.swt.events.ArmListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.ProgressBar; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; /** * View that renders the metrica in a table and reacts to selection events and resource change events from the environment * * @author Frank Sauer */ public class LayeredPackageTableView extends ViewPart implements ISelectionListener, IMetricsProgressListener, IPropertyChangeListener { private final static String[] EXPLANATION = { "No metrics available for selection. To calculate and display metrics:", "", " 1) ensure you are in a java perspective using the package explorer,", " 2) select a project and enable the metrics from its context menu,", " 3) perform a full rebuild on the project.", "", "After the above steps, selecting any java element in the project will result in metrics being shown here.", "Automatic builds will keep the metrics up-to-date by re-calculating the metrics for changed elements only.", "", "To temporarily pause calculations, click the pause button. Click the resume button to resume.", "To abort all current and pending calculations, click the stop button." }; private Composite tablePage; private Composite explanationPage; private Composite cards; private StackLayout pageSelector; private int queued; private ProgressBar progressBar; private Label progressText; // private List pending; private static ArmListener armListener; private static Map<String, Set<String>> currentDependencies; private IMemento memento; private LayeredPackageGraphActionGroup mActions; private LayeredPackageTable table; private Cursor wait; private Cursor normal; private IJavaElement selection; /** * The constructor. */ public LayeredPackageTableView() { } /** * This is a callback that will allow us to create the viewer and initialize it. */ @Override public void createPartControl(Composite parent) { Composite c = new Composite(parent, SWT.NONE); c.setLayoutData(new GridData(GridData.FILL_BOTH)); c.setLayout(new GridLayout(1, false)); cards = new Composite(c, SWT.NONE); GridData data = new GridData(GridData.FILL_BOTH); pageSelector = new StackLayout(); cards.setLayoutData(data); cards.setLayout(pageSelector); explanationPage = createExplanation(cards); pageSelector.topControl = explanationPage; tablePage = new Composite(cards, SWT.NONE); tablePage.setLayout(new GridLayout(1, false)); createTable(tablePage); createStatusBar(c); getViewSite().getPage().addSelectionListener(this); mActions = new LayeredPackageGraphActionGroup(this); IActionBars actionBars = getViewSite().getActionBars(); mActions.fillActionBars(actionBars); MetricsPlugin.getDefault().addPropertyChangeListener(this); MetricsBuilder.addMetricsProgressListener(this); } private void createStatusBar(Composite c) { Composite statusbar = new Composite(c, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.horizontalSpacing = 0; layout.verticalSpacing = 0; layout.marginHeight = 0; layout.marginWidth = 0; statusbar.setLayout(layout); GridData data = new GridData(GridData.FILL_HORIZONTAL); data.grabExcessHorizontalSpace = true; data.grabExcessVerticalSpace = false; statusbar.setLayoutData(data); progressText = new Label(statusbar, SWT.NONE); data = new GridData(GridData.FILL_HORIZONTAL); data.grabExcessHorizontalSpace = true; progressText.setLayoutData(data); progressBar = new ProgressBar(statusbar, SWT.NONE); data = new GridData(); data.widthHint = 250; data.verticalAlignment = GridData.BEGINNING; progressBar.setLayoutData(data); progressBar.setMaximum(0); } private void createTable(Composite c) { table = new LayeredPackageTable(c, SWT.FULL_SELECTION); GridData data = new GridData(GridData.FILL_BOTH | SWT.H_SCROLL | SWT.V_SCROLL); data.grabExcessHorizontalSpace = true; data.grabExcessVerticalSpace = true; table.setLayoutData(data); table.initWidths(memento); table.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { TableTreeItem item = (TableTreeItem) e.item; if (item != null) { supplementTitle(item); } } public void widgetDefaultSelected(SelectionEvent e) { } }); } private Composite createExplanation(Composite stackC) { Composite exp = new Composite(stackC, SWT.NONE); exp.setLayout(new GridLayout(1, false)); for (String element : EXPLANATION) { Label l = new Label(exp, SWT.NONE); l.setText(element); } return exp; } /** * Add the metric desciption to the titlebar * * @param item */ private void supplementTitle(TableTreeItem item) { StringBuffer b = getTitlePrefix(selection); TableTreeItem root = item; // fix submitted by Jacob Eckel 5/27/03 while (root.getParentItem() != null) { root = root.getParentItem(); } b.append(" - ").append(root.getText(0)); setPartName(b.toString()); } private Cursor getWaitCursor(Display d) { if (wait == null) { wait = new Cursor(d, SWT.CURSOR_WAIT); } return wait; } private Cursor getNormalCursor(Display d) { if (normal == null) { normal = new Cursor(d, SWT.CURSOR_ARROW); } return normal; } private void setJavaElement(final IJavaElement elm, boolean force) { if (elm == null) { return; // BUG 676496 } if (force || (elm != getSelection())) { setSelection(elm); } } // private void removeAll() { // final Display display = table.getDisplay(); // display.asyncExec(new Runnable() { // public void run() { // if (!table.isDisposed()) table.removeAll(); // } // }); // } private void setStatus(final String title, final boolean busy) { final Display display = Display.getDefault(); display.asyncExec(new Runnable() { public void run() { if (table.isDisposed()) { return; } progressText.setText(title); progressText.update(); if (busy) { table.setCursor(getWaitCursor(display)); mActions.disable(); } else { table.setCursor(getNormalCursor(display)); mActions.enable(); } } }); } private void refreshTable(final AbstractMetricSource ms, final IJavaElement selection) { final Display display = Display.getDefault(); display.asyncExec(new Runnable() { public void run() { if (!table.isDisposed()) { table.setMetrics(ms); table.setCursor(getNormalCursor(table.getDisplay())); setPartName(getTitlePrefix(selection).toString()); } } }); } private StringBuffer getTitlePrefix(IJavaElement element) { StringBuffer b = new StringBuffer("Layers - "); if (element == null) { return b; } String name = element.getElementName(); if ("".equals(name)) { name = "(default package)"; } b.append(name); return b; } /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { table.setFocus(); } /** * react to selections elsewhere in the workbench * * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection) */ public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (selection instanceof IStructuredSelection) { Object first = ((IStructuredSelection) selection).getFirstElement(); if (first instanceof IJavaElement) { IJavaElement jElem = (IJavaElement) first; if (canDoMetrics(jElem)) { setJavaElement(jElem, false); } } } } /** * @param type * @return true if acceptable type for metrics calculation */ private boolean canDoMetrics(IJavaElement element) { int type = element.getElementType(); if (type == IJavaElement.CLASS_FILE) { return false; } if (type == IJavaElement.FIELD) { return false; } if (type == IJavaElement.IMPORT_CONTAINER) { return false; } if (type == IJavaElement.IMPORT_DECLARATION) { return false; } if (type == IJavaElement.INITIALIZER) { return false; } if (type == IJavaElement.PACKAGE_DECLARATION) { return false; } return true; } /** * @see org.eclipse.ui.IWorkbenchPart#dispose() */ @Override public void dispose() { getViewSite().getPage().removeSelectionListener(this); MetricsBuilder.removeMetricsProgressListener(this); if (wait != null) { wait.dispose(); } if (normal != null) { normal.dispose(); } super.dispose(); // not sure if super does this, so check it if (!table.isDisposed()) { table.dispose(); } } /** * Returns the selection. * * @return IJavaElement */ public IJavaElement getSelection() { return selection; } protected void setSelection(IJavaElement elm) { if (elm != null) { selection = elm; } AbstractMetricSource ms = Dispatcher.getAbstractMetricSource(selection); if (ms != null) { refreshTable(ms, selection); showTablePage(); } else { showExplanationPage(); } } /** * */ private void showExplanationPage() { Display.getDefault().asyncExec(new Runnable() { public void run() { pageSelector.topControl = explanationPage; cards.layout(); mActions.disable(); } }); } /** * */ private void showTablePage() { Display.getDefault().asyncExec(new Runnable() { public void run() { pageSelector.topControl = tablePage; cards.layout(); mActions.enable(); } }); } /** * display dependency graph as embedded workbench view on Windows, in a separate AWT frame on all other platforms. As of 4/30/04, only 3.0M8+ and embedded style on all platforms */ public void displayDependencyGraph() { /* * if (selection.getElementType() <= IJavaElement.PACKAGE_FRAGMENT_ROOT) { IGraphContributor source = (IGraphContributor) Dispatcher.getAbstractMetricSource(selection); if ("win32".equals(BootLoader.getWS())) { * displayDependencyGraphSWT(source.getEfferent()); } else { displayDependencyGraphAWT(source.getEfferent()); } } */// now works the same on all platforms IGraphContributor source = (IGraphContributor) Dispatcher.getAbstractMetricSource(selection); displayDependencyGraphSWT(source.getEfferent()); } private void displayDependencyGraphSWT(final Map<String, Set<String>> graph) { IWorkbenchWindow dw = PlatformUI.getWorkbench().getWorkbenchWindows()[0]; IWorkbenchPage page = dw.getActivePage(); if (page != null) { try { page.showView(LayeredPackageGraphView.class.getName()); } catch (PartInitException e) { e.printStackTrace(); } // } currentDependencies = graph; fireArmEvent(); } } /* * private void displayDependencyGraphAWT(final Map graph) { Thread awt = new Thread(new Runnable() { public void run() { final Frame frame = new Frame("Dependencies"); final DependencyGraphPanel glPanel = new DependencyGraphPanel(); * try { glPanel.createDependencies(graph); } catch (TGException e1) { Log.logError("Could not create DependencyGraphPanel", e1); } frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { * frame.remove(glPanel); frame.dispose(); } }); frame.add("Center", glPanel); frame.setSize(800,600); frame.setVisible(true); } }); awt.start(); } */ /** * */ private static void fireArmEvent() { if (armListener != null) { armListener.widgetArmed(null); } } public static Map<String, Set<String>> getDependencies() { return currentDependencies; } /** * export the selected metrics to an XML report */ public void exportXML() { if (selection != null) { Shell activeShell = new Shell(); FileDialog d = new FileDialog(activeShell, SWT.SAVE); String fileName = d.open(); if (fileName != null) { File outputFile = new File(fileName); IExporter exporter = MetricsPlugin.getDefault().getCurrentExporter(); if (exporter != null) { doExport(activeShell, outputFile, exporter); } else { MessageDialog.openWarning(activeShell, "Warning", "Sorry, exporter is not available"); } } } } private void doExport(Shell activeShell, final File outputFile, final IExporter exporter) { try { IRunnableWithProgress op = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { exporter.export(selection, outputFile, monitor); } }; new ProgressMonitorDialog(activeShell).run(true, true, op); } catch (InvocationTargetException e) { Log.logError("MetricsView::doExport", e); } catch (InterruptedException e) { outputFile.delete(); } } /* * (non-Javadoc) * * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento) */ @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); if (memento != null) { this.memento = memento; } } /* * (non-Javadoc) * * @see org.eclipse.ui.IViewPart#saveState(org.eclipse.ui.IMemento) */ @Override public void saveState(IMemento memento) { if (table != null) { table.updateWidths(memento); } super.saveState(memento); } /* * (non-Javadoc) * * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse .jface.util.PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { if (selection != null) { setJavaElement(selection, true); } } /** * @param view */ public static void setArmListener(ArmListener l) { armListener = l; } /* * (non-Javadoc) * * @see net.sourceforge.metrics.core.MetricsBuilder.MetricsProgressListener#pending (java.lang.String) */ public void pending(IJavaElement current) { setStatus("Queued: " + queued + "\tCalculating now: " + current.getElementName(), shouldBeBusy(current)); } private boolean shouldBeBusy(IJavaElement current) { boolean busy = (selection != null) && (selection.equals(current)); busy = busy || (selection != null) && (current.getHandleIdentifier().startsWith(selection.getHandleIdentifier())); return busy; } private void resetProgressBar() { Display d = Display.getDefault(); d.asyncExec(new Runnable() { public void run() { progressBar.setMaximum(0); progressBar.setSelection(0); mActions.enable(); } }); } private void incProgressBar() { Display d = Display.getDefault(); d.asyncExec(new Runnable() { public void run() { if (!progressBar.isDisposed()) { progressBar.setSelection(progressBar.getSelection() + 1); } } }); } private void addWorkToProgressBar() { Display d = Display.getDefault(); d.asyncExec(new Runnable() { public void run() { progressBar.setMaximum(queued); mActions.disable(); } }); } /* * (non-Javadoc) * * @see net.sourceforge.metrics.core.MetricsBuilder.MetricsProgressListener#completed (java.lang.String) */ public void completed(IJavaElement element, Object data) { setStatus("completed " + element.getElementName(), shouldBeBusy(element)); if ((selection != null) && (selection.equals(element))) { AbstractMetricSource ms = (AbstractMetricSource) data; refreshTable(ms, selection); } queued--; incProgressBar(); } public void queued(int count) { queued += count; addWorkToProgressBar(); } public void projectComplete(IJavaProject project, boolean aborted) { // Log.logMessage("Got projectComplete event."); queued = 0; setStatus("", false); resetProgressBar(); // force rendering of completed project boolean showProject = MetricsPlugin.getDefault().showProjectOnCompletion(); if (!aborted) { setSelection(showProject ? project : selection); } } /* * (non-Javadoc) * * @see net.sourceforge.metrics.core.MetricsBuilder.MetricsProgressListener#moved (java.lang.String, org.eclipse.core.runtime.IPath) */ public void moved(IJavaElement element, IPath fromPath) { if ((selection != null) && (selection.getPath().equals(fromPath))) { // this causes the view to refresh with new element when it // completes selection = element; } } /* * (non-Javadoc) * * @see net.sourceforge.metrics.builder.IMetricsProgressListener#paused() */ public void paused() { setStatus("Paused. " + queued + " items in the queue.", false); } static List<Set<PackageStats>> getLayers() { return LayeredPackageTable.getLayers(); } public static int getLayer(String depPackageName) { return LayeredPackageTable.getLayer(depPackageName); } }