/*******************************************************************************
* Copyright (c) 2009 the CHISEL group and contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* the CHISEL group - initial API and implementation
*******************************************************************************/
package ca.uvic.chisel.javasketch.ui.internal.wizards;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.TreeSet;
import org.eclipse.jface.dialogs.DialogPage;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import ca.uvic.chisel.javasketch.IProgramSketch;
import ca.uvic.chisel.javasketch.SketchPlugin;
import ca.uvic.chisel.javasketch.data.model.IThread;
import ca.uvic.chisel.javasketch.data.model.ITrace;
import ca.uvic.chisel.javasketch.data.model.ITraceModel;
import ca.uvic.chisel.javasketch.data.model.ITraceModelProxy;
import ca.uvic.chisel.javasketch.ui.internal.views.EmptyThreadFilter;
/**
* @author Del Myers
*
*/
public class ExportTraceWizardPage1 extends WizardPage {
private CheckboxTreeViewer threadViewer;
private Text fileText;
private File file;
private ITrace trace;
private TreeSet<Integer> threads;
private Button filterButton;
public ExportTraceWizardPage1() {
super("Export A Trace", "Export A Trace", getTitleImage());
}
/**
* @return
*/
private static ImageDescriptor getTitleImage() {
return SketchPlugin.imageDescriptorFromPlugin("images/wizban/export-trace.png");
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createControl(Composite parent) {
Composite page = new Composite(parent, SWT.NONE);
page.setLayout(new GridLayout());
Control traceArea = createTraceArea(page);
traceArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Control fileArea = createFileArea(page);
fileArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
setControl(page);
validate();
}
/**
* @param page
* @return
*/
private Control createFileArea(Composite page) {
Composite fileLine = new Composite(page, SWT.NONE);
fileLine.setLayout(new GridLayout(3, false));
Label nameLabel = new Label(fileLine, SWT.NONE);
nameLabel.setText("File name:");
nameLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
fileText = new Text(fileLine, SWT.SINGLE | SWT.BORDER);
fileText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
setFileName(fileText.getText().trim());
}
});
fileText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
Button browseButton = new Button(fileLine, SWT.PUSH);
browseButton.setText("Browse...");
browseButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
dialog.setFilterExtensions(new String[] { "*.dvt" });
String fileName = dialog.open();
fileText.setText(fileName);
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
String fileName = getDialogSettings().get("filename");
if (fileName != null) {
fileText.setText(fileName);
}
browseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
filterButton = new Button(page, SWT.CHECK);
filterButton.setText("Exclude empty threads");
boolean showThreads = getDialogSettings().getBoolean("showAllThreads");
final ViewerFilter threadFilter = new EmptyThreadFilter();
if (!showThreads) {
filterButton.setSelection(true);
threadViewer.addFilter(threadFilter);
}
filterButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
if (filterButton.getSelection()) {
threadViewer.addFilter(threadFilter);
} else {
threadViewer.removeFilter(threadFilter);
}
threadViewer.refresh();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
filterButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
return fileLine;
}
/**
* @param page
* @return
*/
private Control createTraceArea(Composite page) {
Group traceGroup = new Group(page, SWT.NONE);
traceGroup.setLayout(new GridLayout());
traceGroup.setText("Threads To Export");
threadViewer = new CheckboxTreeViewer(traceGroup);
threadViewer.setContentProvider(new ITreeContentProvider() {
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
@Override
public void dispose() {}
@Override
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
@Override
public boolean hasChildren(Object element) {
return (element instanceof ExportTraceWizardPage1 ||
element instanceof ITrace);
}
@Override
public Object getParent(Object element) {
if (element instanceof ITrace) {
return ExportTraceWizardPage1.this;
} else if (element instanceof IThread) {
return ((IThread)element).getTrace();
}
return null;
}
@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof ExportTraceWizardPage1) {
IProgramSketch[] sketches = SketchPlugin.getDefault().getStoredSketches();
ITrace[] traces = new ITrace[sketches.length];
for (int i = 0; i < sketches.length; i++) {
traces[i] = sketches[i].getTraceData();
}
return traces;
} else if (parentElement instanceof ITrace) {
return ((ITrace)parentElement).getThreads().toArray();
}
return new Object[0];
}
});
threadViewer.setLabelProvider(new WorkbenchLabelProvider());
threadViewer.setInput(this);
threadViewer.addCheckStateListener(new ICheckStateListener() {
@Override
public void checkStateChanged(CheckStateChangedEvent event) {
boolean checked = event.getChecked();
ITraceModel element = (ITraceModel) event.getElement();
updateCheckedState(checked, element);
}
});
threadViewer.setSorter(new ViewerSorter(){
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
TreeViewer tv = (TreeViewer) viewer;
String s1 = ((ILabelProvider)tv.getLabelProvider()).getText(e1);
String s2 = ((ILabelProvider)tv.getLabelProvider()).getText(e2);
return s1.compareTo(s2);
}
});
threadViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
//set the trace
ITrace trace = ((ExportTraceWizard)getWizard()).getTrace();
if (trace == null) {
String traceID = getDialogSettings().get("trace");
//try to get it from saved information
String[] threads = getDialogSettings().getArray("threads");
if (traceID != null) {
IProgramSketch sketch = SketchPlugin.getDefault().getSketch(traceID);
if (sketch != null) {
trace = sketch.getTraceData();
if (trace != null) {
this.trace = trace;
if (threads != null && threads.length > 0) {
for (int i = 0; i < threads.length; i++) {
ITraceModelProxy proxy = trace.getElement(threads[i]);
ITraceModel element = proxy.getElement();
if (element != null) {
threadViewer.setChecked(element, true);
updateCheckedState(true, element);
}
}
} else {
threadViewer.setChecked(trace, true);
updateCheckedState(true, trace);
}
}
}
}
} else {
this.trace = trace;
threadViewer.setChecked(trace, true);
updateCheckedState(true, trace);
}
return traceGroup;
}
/**
* @param checked
* @param element
*/
protected void updateCheckedState(boolean checked,
ITraceModel element) {
Object[] ces = threadViewer.getCheckedElements();
if (checked) {
for (Object ce : ces) {
ITraceModel checkedElement = (ITraceModel) ce;
if (!checkedElement.getTrace().equals(element.getTrace())) {
threadViewer.setChecked(checkedElement, false);
}
}
if (element instanceof ITrace) {
threadViewer.setCheckedElements(element.getTrace().getThreads().toArray());
}
threadViewer.setChecked(element.getTrace(), true);
threadViewer.setGrayed(element.getTrace(), threadViewer.getCheckedElements().length < element.getTrace().getThreads().size());
} else {
if (element instanceof ITrace || threadViewer.getCheckedElements().length <= 1) {
threadViewer.setGrayedElements(new Object[0]);
threadViewer.setCheckedElements(new Object[0]);
setTrace(null);
} else {
threadViewer.setGrayChecked(element.getTrace(), true);
}
}
updateSelection();
}
/**
* @param object
*/
protected void setTrace(ITrace trace) {
this.trace = trace;
validate();
}
public void validate() {
setErrorMessage(null);
setMessage(null);
setPageComplete(true);
if (getTrace() == null) {
setErrorMessage("Please select a trace");
setPageComplete(false);
} else if (getDestinationFile() == null) {
setErrorMessage("Please select a file");
setPageComplete(false);
} else {
File file = getDestinationFile();
//check to see if the file is valid
if (!file.exists()) {
try {
file.createNewFile();
file.delete();
} catch (IOException e) {
setErrorMessage(file.getName() + " is an invalid file");
setPageComplete(false);
}
} else {
if (!file.isFile()) {
setErrorMessage(file.getName() + " is a directory");
setPageComplete(false);
} else {
setMessage(file.getName() + " already exists", DialogPage.WARNING);
getContainer().updateButtons();
}
}
}
getContainer().updateButtons();
getContainer().updateMessage();
}
/**
* @return
*/
public ITrace getTrace() {
return trace;
}
/**
* @return
*/
public File getDestinationFile() {
return file;
}
protected void setFileName(String fileName) {
file = new File(fileName);
validate();
}
protected void save() {
IDialogSettings settings = getDialogSettings();
settings.put("filename", fileText.getText());
Object[] checked = threadViewer.getCheckedElements();
ArrayList<String> threads = new ArrayList<String>();
for (Object c : checked) {
if (c instanceof ITrace) {
settings.put("trace", ((ITrace)c).getLaunchID());
} else if (c instanceof IThread) {
threads.add(((IThread)c).getIdentifier());
}
}
settings.put("showAllThreads", !filterButton.getSelection());
//save the threads
settings.put("threads", threads.toArray(new String[threads.size()]));
}
/**
*
*/
private void updateSelection() {
threads = new TreeSet<Integer>();
trace = null;
for (Object o : threadViewer.getCheckedElements()) {
if (o instanceof ITrace) {
trace = (ITrace) o;
} else if (o instanceof IThread) {
threads.add(((IThread)o).getID());
}
}
validate();
}
public int[] getThreadIDs() {
if (threads == null) {
return new int[0];
}
int[] array = new int[threads.size()];
int i = 0;
for (Integer t : threads) {
array[i++] = t;
}
return array;
}
}