package edu.ysu.itrace;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.part.ViewPart;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import edu.ysu.itrace.filters.IFilter;
import edu.ysu.itrace.filters.fixation.JSONBasicFixationFilter;
import edu.ysu.itrace.filters.fixation.OldJSONBasicFixationFilter;
import edu.ysu.itrace.filters.fixation.OldXMLBasicFixationFilter;
import edu.ysu.itrace.filters.fixation.XMLBasicFixationFilter;
/**
* ViewPart for managing and controlling the plugin.
*/
public class ControlView extends ViewPart implements IPartListener2, EventHandler{
public static final String KEY_AST = "itraceAST";
public static final String KEY_SO_DOM = "itraceSO";
public static final String KEY_BR_DOM = "itraceBR";
public static final String FATAL_ERROR_MSG = "A fatal error occurred. "
+ "Restart the plugin and try again. If "
+ "the problem persists, submit a bug report.";
private Shell rootShell;
private CopyOnWriteArrayList<Control> grayedControls =
new CopyOnWriteArrayList<Control>();
private ArrayList<IEditorReference> setupEditors = new ArrayList<IEditorReference>();
private Spinner xDrift;
private Spinner yDrift;
private CopyOnWriteArrayList<IFilter> availableFilters =
new CopyOnWriteArrayList<IFilter>();
private IEventBroker eventBroker;
@Override
public void createPartControl(Composite parent) {
eventBroker = PlatformUI.getWorkbench().getService(IEventBroker.class);
eventBroker.subscribe("iTrace/error", this);
// find root shell
rootShell = parent.getShell();
while (rootShell.getParent() != null) {
rootShell = rootShell.getParent().getShell();
}
ITrace.getDefault().setRootShell(rootShell);
ITrace.getDefault().monitorBounds = rootShell.getMonitor().getBounds();
// add listener for determining part visibility
getSite().getWorkbenchWindow().getPartService().addPartListener(this);
final String DONT_DO_THAT_MSG =
"You can't do that until you've "
+ "selected a tracker in preferences.";
// set up UI
parent.setLayout(new RowLayout());
//Button Composite start.
final Composite buttonComposite = new Composite(parent, SWT.NONE);
buttonComposite.setLayout(new GridLayout(2, false));
//Calibration Button
Button calibrateButton = new Button(buttonComposite, SWT.PUSH);
calibrateButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
true, 1, 1));
calibrateButton.setText("Calibrate");
calibrateButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ITrace.getDefault().calibrateTracker();
}
});
//Tracking start and stop button.
final Button trackingButton = new Button(buttonComposite, SWT.PUSH);
trackingButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
1, 1));
trackingButton.setText("Start Tracking");
trackingButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ITrace.getDefault().setActionBars(getViewSite().getActionBars());
if(ITrace.getDefault().toggleTracking()){
if(trackingButton.getText() == "Start Tracking"){
trackingButton.setText("Stop Tracking");
for (Control c : grayedControls) {
c.setEnabled(false);
}
}
else{
trackingButton.setText("Start Tracking");
for (Control c : grayedControls) {
c.setEnabled(true);
}
}
}
}
});
//Session Info Button
final Button infoButton = new Button(buttonComposite, SWT.PUSH);
infoButton.setText("Session Info");
infoButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ITrace.getDefault().configureSessionInfo();
}
});
grayedControls.addIfAbsent(infoButton);
//Eye Status Button
final Button statusButton = new Button(buttonComposite, SWT.PUSH);
statusButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
1, 1));
statusButton.setText("Eye Status");
statusButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ITrace.getDefault().displayEyeStatus();
}
});
//Button Composite End.
final String DONT_CHANGE_THAT_MSG =
"Don't change this value until "
+ "you've selected a tracker in preferences.";
//Tuning Composite Start.
final Composite tuningComposite = new Composite(parent, SWT.NONE);
tuningComposite.setLayout(new RowLayout(SWT.VERTICAL));
final Button highlight_tokens = new Button(tuningComposite, SWT.CHECK);
highlight_tokens.setText("Highlight Tokens");
highlight_tokens.addSelectionListener(new SelectionAdapter(){
@Override
public void widgetSelected(SelectionEvent e) {
ITrace.getDefault().activateHighlights();
}
});
final Button displayCrosshair = new Button(tuningComposite, SWT.CHECK);
displayCrosshair.setText("Display Crosshair");
displayCrosshair.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean success = ITrace.getDefault().displayCrosshair(displayCrosshair.getSelection());
if(success != displayCrosshair.getSelection()) displayCrosshair.setSelection(false);
}
});
final Composite driftComposite =
new Composite(tuningComposite, SWT.NONE);
driftComposite.setLayout(new GridLayout(2, false));
final Label xDriftLabel = new Label(driftComposite, SWT.NONE);
xDriftLabel.setText("x Drift");
final Spinner xDrift = new Spinner(driftComposite, SWT.NONE);
xDrift.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (ITrace.getDefault().getTracker() != null) {
ITrace.getDefault().setTrackerXDrift(xDrift.getSelection());
} else {
if (xDrift.getSelection() != 0) {
displayError(DONT_CHANGE_THAT_MSG);
xDrift.setSelection(0);
}
}
}
});
xDrift.setMinimum(-100);
xDrift.setMaximum(100);
xDrift.setSelection(0);
this.xDrift = xDrift;
final Label yDriftLabel = new Label(driftComposite, SWT.NONE);
yDriftLabel.setText("y Drift");
final Spinner yDrift = new Spinner(driftComposite, SWT.NONE);
yDrift.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (ITrace.getDefault().getTracker() != null) {
ITrace.getDefault().setTrackerXDrift(xDrift.getSelection());
} else {
if (yDrift.getSelection() != 0) {
displayError(DONT_CHANGE_THAT_MSG);
yDrift.setSelection(0);
}
}
}
});
yDrift.setMinimum(-100);
yDrift.setMaximum(100);
yDrift.setSelection(0);
this.yDrift = yDrift;
//Tuning composite end.
//Solvers composite begin.
final Composite solversComposite = new Composite(parent, SWT.NONE);
solversComposite.setLayout(new GridLayout(2, false));
// Configure solvers here.
final Button jsonSolverEnabled =
new Button(solversComposite, SWT.CHECK);
jsonSolverEnabled.setText("JSON Export");
jsonSolverEnabled.setSelection(true);
jsonSolverEnabled.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ITrace.getDefault().sessionInfoConfigured()) {
if (jsonSolverEnabled.getSelection()) {
ITrace.getDefault().setJsonOutput(true);
} else {
ITrace.getDefault().setJsonOutput(false);
}
} else {
ITrace.getDefault().setJsonOutput(false);
jsonSolverEnabled.setSelection(false);
displayError("You must configure your Sesssion "
+ "Info. first.");
}
}
});
grayedControls.addIfAbsent(jsonSolverEnabled);
final Button jsonSolverConfig = new Button(solversComposite, SWT.PUSH);
jsonSolverConfig.setText("...");
jsonSolverConfig.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ITrace.getDefault().sessionInfoConfigured()) {
ITrace.getDefault().displayJsonExportFile();
} else {
displayError("You must configure your Session Info. "
+ "first.");
}
}
});
grayedControls.addIfAbsent(jsonSolverConfig);
final Button xmlSolverEnabled =
new Button(solversComposite, SWT.CHECK);
xmlSolverEnabled.setText("XML Export");
xmlSolverEnabled.setSelection(true);
xmlSolverEnabled.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ITrace.getDefault().sessionInfoConfigured()) {
if (xmlSolverEnabled.getSelection()) {
ITrace.getDefault().setXmlOutput(true);
} else {
ITrace.getDefault().setXmlOutput(false);
}
} else {
ITrace.getDefault().setXmlOutput(false);
xmlSolverEnabled.setSelection(false);
displayError("You must configure your Sesssion "
+ "Info. first.");
}
}
});
grayedControls.addIfAbsent(xmlSolverEnabled);
final Button xmlSolverConfig = new Button(solversComposite, SWT.PUSH);
xmlSolverConfig.setText("...");
xmlSolverConfig.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ITrace.getDefault().sessionInfoConfigured()) {
ITrace.getDefault().displayXmlExportFile();
} else {
displayError("You must configure your Session Info. "
+ "first.");
}
}
});
grayedControls.addIfAbsent(xmlSolverConfig);
//Solver Composite end.
//Configure Filters Here
OldJSONBasicFixationFilter oldjsonBFFilter =
new OldJSONBasicFixationFilter();
OldXMLBasicFixationFilter oldxmlBFFilter =
new OldXMLBasicFixationFilter();
JSONBasicFixationFilter jsonBFFilter =
new JSONBasicFixationFilter();
XMLBasicFixationFilter xmlBFFilter =
new XMLBasicFixationFilter();
availableFilters.add(oldjsonBFFilter);
availableFilters.add(jsonBFFilter);
availableFilters.add(oldxmlBFFilter);
availableFilters.add(xmlBFFilter);
//Filter composite begin.
final Composite filterComposite = new Composite(parent, SWT.NONE);
filterComposite.setLayout(new GridLayout(2, false));
for (final IFilter filter: availableFilters) {
final Button filterButton =
new Button(filterComposite, SWT.PUSH);
filterButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
1, 1));
filterButton.setText(filter.getFilterName());
filterButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
File[] fileList = filter.filterUI();
if (fileList != null) {
for (int i = 0; i < fileList.length; i++) {
try {
filter.read(fileList[i]);
filter.process();
filter.export();
} catch(IOException exc) {
displayError(exc.getMessage());
}
}
}
}
});
grayedControls.add(filterButton);
}
//Filter composite end.
}
@Override
public void dispose() {
getSite().getWorkbenchWindow().getPartService()
.removePartListener(this);
super.dispose();
}
@Override
public void setFocus() {
}
@Override
public void partActivated(IWorkbenchPartReference partRef) {
if(partRef.getPart(false) instanceof IEditorPart) {
ITrace.getDefault().setActiveEditor((IEditorPart)partRef.getPart(false));
IEditorPart ep = (IEditorPart)partRef.getPart(true);
ITrace.getDefault().setLineManager(ep.getEditorSite().getActionBars().getStatusLineManager());
}
}
@Override
public void partBroughtToTop(IWorkbenchPartReference partRef) {
if(partRef.getPart(false) instanceof IEditorPart) {
ITrace.getDefault().setActiveEditor((IEditorPart)partRef.getPart(false));
IEditorPart ep = (IEditorPart)partRef.getPart(true);
ITrace.getDefault().setLineManager(ep.getEditorSite().getActionBars().getStatusLineManager());;
}
}
@Override
public void partClosed(IWorkbenchPartReference partRef) {
if(partRef instanceof IEditorReference){
setupEditors.remove(partRef);
ITrace.getDefault().setActionBars(getViewSite().getActionBars());
IEditorPart ep = (IEditorPart)partRef.getPart(true);
ITrace.getDefault().removeHighlighter(ep);
ITrace.getDefault().setActiveEditor(
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().getActiveEditor()
);
}
}
@Override
public void partDeactivated(IWorkbenchPartReference partRef) {
}
@Override
public void partOpened(IWorkbenchPartReference partRef) {
}
@Override
public void partInputChanged(IWorkbenchPartReference partRef) {
}
@Override
public void partVisible(IWorkbenchPartReference partRef) {
setupControls(partRef);
HandlerBindManager.bind(partRef);
}
@Override
public void partHidden(IWorkbenchPartReference partRef) {
HandlerBindManager.unbind(partRef);
}
/**
* Find controls within a part, set it up to be used by iTrace,
* and extract meta-data from it.
*
* @param partRef partRef that just became visible.
*/
private void setupControls(IWorkbenchPartReference partRef) {
IWorkbenchPart part = partRef.getPart(true);
Control control = part.getAdapter(Control.class);
//set up manager for control and managers for each child control if necessary
if (control != null) {
setupControls(part, control);
} else {
//Browser - always set up browser managers, no matter the partRef that
//has become visible
//not possible to get Browser control from a partRef
Shell workbenchShell = partRef.getPage().getWorkbenchWindow().getShell();
for (Control ctrl: workbenchShell.getChildren()) {
setupBrowsers(ctrl);
}
}
}
/**
* Recursive helper function to find and set up Browser control managers
* @param control
*/
private void setupBrowsers(Control control) {
if (control instanceof Browser) {
setupControls(null, control);
}
//If composite, look through children.
if (control instanceof Composite) {
Composite composite = (Composite) control;
Control[] children = composite.getChildren();
if (children.length > 0 && children[0] != null) {
for (Control curControl : children)
setupBrowsers(curControl);
}
}
}
/**
* Recursive function for setting up children controls for a control if it is
* a composite and setting up the main control's manager.
* @param part
* @param control
*/
private void setupControls(IWorkbenchPart part, Control control) {
//If composite, setup children controls.
if (control instanceof Composite) {
Composite composite = (Composite) control;
Control[] children = composite.getChildren();
if (children.length > 0 && children[0] != null) {
for (Control curControl : children)
setupControls(part, curControl);
}
}
if (control instanceof StyledText) {
//set up styled text manager if there is one
setupStyledText((IEditorPart) part, (StyledText) control);
} else if (control instanceof Browser) {
//set up browser manager if there is one
setupBrowser((Browser) control);
}
//TODO: no control set up for a ProjectExplorer, since there isn't an need for
//a Manager right now, might be needed in the future
}
/**
* Recursive helper method for setupControls(IWorkbenchPartReference).
*
* @param editor IEditorPart which owns the StyledText in the next
* parameter.
* @param styledText StyledText to set up.
*/
private void setupStyledText(IEditorPart editor, StyledText styledText) {
if (styledText.getData(KEY_AST) == null)
styledText.setData(KEY_AST, new AstManager(editor, styledText));
}
/**
* Recursive helper method for setupControls(IWorkbenchPartReference).
*
* @param editor IEditorPart which owns the Browser in the next
* parameter.
* @param control browser to set up.
*/
private void setupBrowser(Browser browser) {
if (browser.getData(KEY_SO_DOM) == null)
browser.setData(KEY_SO_DOM, new SOManager(browser));
if (browser.getData(KEY_BR_DOM) == null)
browser.setData(KEY_BR_DOM, new BRManager(browser));
}
private void displayError(String message) {
MessageBox error_box = new MessageBox(rootShell, SWT.ICON_ERROR);
error_box.setMessage(message);
error_box.open();
}
@Override
public void handleEvent(Event event) {
String[] propertyNames = event.getPropertyNames();
String message = (String)event.getProperty(propertyNames[0]);
displayError(message);
}
}