/*******************************************************************************
* CogTool Copyright Notice and Distribution Terms
* CogTool 1.3, Copyright (c) 2005-2013 Carnegie Mellon University
* This software is distributed under the terms of the FSF Lesser
* Gnu Public License (see LGPL.txt).
*
* CogTool is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* CogTool is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CogTool; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* CogTool makes use of several third-party components, with the
* following notices:
*
* Eclipse SWT version 3.448
* Eclipse GEF Draw2D version 3.2.1
*
* Unless otherwise indicated, all Content made available by the Eclipse
* Foundation is provided to you under the terms and conditions of the Eclipse
* Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this
* Content and is also available at http://www.eclipse.org/legal/epl-v10.html.
*
* CLISP version 2.38
*
* Copyright (c) Sam Steingold, Bruno Haible 2001-2006
* This software is distributed under the terms of the FSF Gnu Public License.
* See COPYRIGHT file in clisp installation folder for more information.
*
* ACT-R 6.0
*
* Copyright (c) 1998-2007 Dan Bothell, Mike Byrne, Christian Lebiere &
* John R Anderson.
* This software is distributed under the terms of the FSF Lesser
* Gnu Public License (see LGPL.txt).
*
* Apache Jakarta Commons-Lang 2.1
*
* This product contains software developed by the Apache Software Foundation
* (http://www.apache.org/)
*
* jopt-simple version 1.0
*
* Copyright (c) 2004-2013 Paul R. Holser, Jr.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Mozilla XULRunner 1.9.0.5
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/.
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The J2SE(TM) Java Runtime Environment version 5.0
*
* Copyright 2009 Sun Microsystems, Inc., 4150
* Network Circle, Santa Clara, California 95054, U.S.A. All
* rights reserved. U.S.
* See the LICENSE file in the jre folder for more information.
******************************************************************************/
package edu.cmu.cs.hcii.cogtool.view;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Text;
import edu.cmu.cs.hcii.cogtool.model.APredictionResult;
import edu.cmu.cs.hcii.cogtool.model.ResultStep;
import edu.cmu.cs.hcii.cogtool.ui.PERTChartSelectionState;
import edu.cmu.cs.hcii.cogtool.uimodel.PERTChartUIModel;
import edu.cmu.cs.hcii.cogtool.util.GraphicsUtil;
import edu.cmu.cs.hcii.cogtool.util.AlertHandler;
import edu.cmu.cs.hcii.cogtool.util.ITimeSliceDisplayable;
import edu.cmu.cs.hcii.cogtool.util.L10N;
import edu.cmu.cs.hcii.cogtool.util.StringUtil;
public class PERTChartPanel extends Composite implements ITimeSliceDisplayable
{
/**
* Scrollable visualization display
*/
protected PERTInteractivePanel visPanel;
protected PERTScrollBar scrollBar;
protected PERTLabelPanel labelPanel;
protected Composite infoPanel;
protected Combo viewSelector;
//protected SWTListMultiColumn scriptItemList;
//protected Table scriptTable;
protected StyledText traceText;
protected Text operatorInfoText;
protected Label infoLabel;
protected Sash sash;
protected APredictionResult result;
protected double totalTime;
protected List<String> resourceLabels;
protected boolean infoPanelVisible = true;
protected int lastSashPosition;
// For recovery of the alert handler
protected PERTChartSelectionState chartSelectionState;
protected static Color selectionColor =
new Color(null, GraphicsUtil.getRGBFromColor(0x00d5FF));
protected static String NO_OPERATOR_SELECTED =
L10N.get("PCV.NO_OPERATOR", "No Operator Selected");
public PERTChartPanel(Composite parent,
APredictionResult predictionResult,
PERTChartUIModel uiModel)
{
this(parent, predictionResult, uiModel, true);
}
public PERTChartPanel(Composite parent,
APredictionResult predictionResult,
PERTChartUIModel uiModel,
boolean scrollBarOnBottom)
{
super(parent, SWT.NONE);
result = predictionResult;
resourceLabels = new ArrayList<String>();
setLayout(new FormLayout());
// get list of resource labels and the total time for the model run
List<ResultStep> steps = result.getModelSteps();
if (steps.size() > 0) {
// Loop through steps to get list of unique resources
// NOTE: Do we want to display all possible resources? At the moment
// this will display only the resources that are used by the model
Iterator<ResultStep> stepIterator = steps.iterator();
ResultStep thisStep;
totalTime = 0.0;
while (stepIterator.hasNext()) {
thisStep = stepIterator.next();
if (! resourceLabels.contains(thisStep.resource)) {
resourceLabels.add(thisStep.resource);
}
totalTime =
Math.max(totalTime,
thisStep.startTime + thisStep.duration);
}
resourceLabels =
PERTChartUIModel.orderResourceLabels(resourceLabels);
}
else {
totalTime = 0.0;
}
visPanel = new PERTInteractivePanel(this,
steps,
resourceLabels);
labelPanel = new PERTLabelPanel(this,
resourceLabels,
55,
10);
scrollBar = new PERTScrollBar(this,
steps,
resourceLabels);
sash = new Sash(this, SWT.VERTICAL);
// Create hideable info panel to hold trace and operator info
infoPanel = new Composite(this, SWT.NONE);
// create selection listener to respond to dragging the sash
sash.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent se)
{
widgetSelected(se);
}
public void widgetSelected(SelectionEvent se)
{
int offsetWidth = getBounds().width - se.x;
int minOffset = 250;
int maxOffset = getBounds().width - 200;
if (offsetWidth > maxOffset) {
se.doit = false;
offsetWidth = maxOffset;
}
if (offsetWidth < minOffset) {
se.doit = false;
offsetWidth = minOffset;
}
if (se.doit) {
((FormData) sash.getLayoutData()).right =
new FormAttachment(100, (-1 * offsetWidth));
layout();
}
}
});
// Create listener to scroll visualizationScrollPanel in response to the
// visScrollBar
scrollBar.addHandler(this,
PERTScrollBar.ScrollEvent.class,
new AlertHandler() {
public void handleAlert(EventObject alert)
{
final PERTScrollBar.ScrollEvent sEvent =
(PERTScrollBar.ScrollEvent) alert;
visPanel.displayTimeSlice(sEvent.start, sEvent.end);
}
});
infoPanel.setLayout(new FormLayout());
infoLabel = new Label(infoPanel, SWT.HORIZONTAL);
infoLabel.setText("Show:");
viewSelector = new Combo(infoPanel, SWT.READ_ONLY);
viewSelector.add("Trace");
viewSelector.add("Operator Info");
//this.viewSelector.add("Script Steps");
viewSelector.select(0);
viewSelector.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent se)
{
widgetSelected(se);
}
public void widgetSelected(SelectionEvent se)
{
int index = viewSelector.getSelectionIndex();
traceText.setVisible((index == 0));
operatorInfoText.setVisible((index == 1));
}
});
// Create trace viewer for tab folder
traceText =
new StyledText(infoPanel,
SWT.MULTI | SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL );
traceText.setSelectionBackground(selectionColor);
traceText.setFont(new Font(getDisplay(), "Monaco", 10, SWT.NORMAL));
Iterator<String> traceIt = result.getTraceLines().iterator();
StringBuilder tt = new StringBuilder();
//TODO: Really long traces cause the system to hang here. Fix it!
int lineCount = 0;
while ((traceIt.hasNext()) && (lineCount < 10000)) {
lineCount++;
tt.append(traceIt.next() + "\n");
}
traceText.setText(tt.toString());
//this.traceText.append(tt);
traceText.setSelection(0);
traceText.showSelection();
// create operator info text for tab folder
operatorInfoText = new Text(infoPanel,
SWT.MULTI | SWT.READ_ONLY);
operatorInfoText.setText(NO_OPERATOR_SELECTED);
// create script steps for tab folder
// this.scriptTable = new Table(this.infoTabFolder,
// SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);
// this.scriptTable.setFont(FontUtils.SYMBOL_FONT);
// this.scriptItemList = new SWTListMultiColumn(this.scriptTable,
// new String[] { "Frame",
// "Action",
// "Widget" },
// uiModel.getScriptUIModel());
//
//
// this.scriptItemList.setListContents(script.getScriptSteps());
// Lay out info panel
FormData fData = new FormData();
fData.top = new FormAttachment(0,5);
fData.left = new FormAttachment(0,0);
infoLabel.setLayoutData(fData);
fData = new FormData();
fData.top = new FormAttachment(0,0);
fData.left = new FormAttachment(infoLabel, 5);
viewSelector.setLayoutData(fData);
fData = new FormData();
fData.top = new FormAttachment(viewSelector,5);
fData.left = new FormAttachment(0, 0);
fData.right = new FormAttachment(100, -5);
fData.bottom = new FormAttachment(100, -5);
traceText.setLayoutData(fData);
operatorInfoText.setLayoutData(fData);
operatorInfoText.setVisible(false);
// Lay out view
FormData sashFormData = new FormData();
sashFormData.top = new FormAttachment(0,0);
sashFormData.right = new FormAttachment(100, -500);
sashFormData.bottom = new FormAttachment(100, 0);
FormData infoFormData = new FormData();
infoFormData.top = new FormAttachment(0, 0);
infoFormData.left = new FormAttachment(sash, 0);
infoFormData.right = new FormAttachment(100, 0);
infoFormData.bottom = new FormAttachment(100, 0);
FormData scrollBarFormData = new FormData();
scrollBarFormData.left = new FormAttachment(0, 5);
scrollBarFormData.right = new FormAttachment(sash, 0);
if (scrollBarOnBottom) {
scrollBarFormData.bottom = new FormAttachment(100, 0);
scrollBarFormData.top = new FormAttachment(100, -100);
}
else {
scrollBarFormData.top = new FormAttachment(0, 0);
scrollBarFormData.bottom = new FormAttachment(0, 100);
}
FormData labelFormData = new FormData();
labelFormData.left = new FormAttachment(0,0);
labelFormData.right = new FormAttachment(0, 135);
if (scrollBarOnBottom) {
labelFormData.top = new FormAttachment(0,0);
labelFormData.bottom = new FormAttachment(scrollBar, 0);
}
else {
labelFormData.top = new FormAttachment(scrollBar,0);
labelFormData.bottom = new FormAttachment(100, 0);
}
FormData visFormData = new FormData();
visFormData.left = new FormAttachment(labelPanel, 0);
visFormData.right = new FormAttachment(sash, 0);
if (scrollBarOnBottom) {
visFormData.top = new FormAttachment(0, 0);
visFormData.bottom = new FormAttachment(scrollBar, 0);
}
else {
visFormData.top = new FormAttachment(scrollBar, 0);
visFormData.bottom = new FormAttachment(100, 0);
}
// Set the layout data to the important objects
visPanel.setLayoutData(visFormData);
scrollBar.setLayoutData(scrollBarFormData);
infoPanel.setLayoutData(infoFormData);
labelPanel.setLayoutData(labelFormData);
sash.setLayoutData(sashFormData);
// set initial visible region to first 1/4 of the trace
scrollBar.changeRegion(0.0, totalTime / 4.0);
}
@Override
public void dispose()
{
chartSelectionState.removeAllHandlers(this);
super.dispose();
}
public void toggleInfoPanel()
{
sash.setVisible(false);
infoLabel.setVisible(false);
}
protected MenuFactory.MenuType[] neededMenus()
{
return new MenuFactory.MenuType[] { MenuFactory.MenuType.FileMenu,
MenuFactory.MenuType.EditMenu,
MenuFactory.MenuType.WindowMenu,
MenuFactory.MenuType.HelpMenu };
}
public PERTInteractivePanel getVisScrollPanel()
{
return visPanel;
}
public PERTInteractivePanel getVisPanel()
{
return visPanel;
}
public PERTScrollBar getVisScrollBar()
{
return scrollBar;
}
public StyledText getTextCtrl()
{
return traceText;
}
public void setResult(APredictionResult res)
{
result = res;
List<ResultStep> steps = res.getModelSteps();
Iterator<ResultStep> stepIterator = steps.iterator();
ResultStep thisStep;
resourceLabels = new ArrayList<String>();
while (stepIterator.hasNext()) {
thisStep = stepIterator.next();
if (! resourceLabels.contains(thisStep.resource)) {
resourceLabels.add(thisStep.resource);
}
totalTime =
Math.max(totalTime,
thisStep.startTime + thisStep.duration);
}
resourceLabels =
PERTChartUIModel.orderResourceLabels(resourceLabels);
scrollBar.setResultSteps(steps, resourceLabels);
visPanel.setResultSteps(steps, resourceLabels);
labelPanel.setResourceLabels(resourceLabels);
Iterator<String> traceIt = result.getTraceLines().iterator();
StringBuilder tt = new StringBuilder();
//TODO: Really long traces cause the system to hang here. Fix it!
int lineCount = 0;
while ((traceIt.hasNext()) && (lineCount < 10000)) {
lineCount++;
tt.append(traceIt.next() + "\n");
}
traceText.setText(tt.toString());
}
/**
* Associate this view with a PERTChartSelectionState so that, when a new
* operator is selected, this view adds the operator info to the
* operatorInfoPanel.
*
* @param selection
*/
public void observeSelectionState(PERTChartSelectionState selection)
{
chartSelectionState = selection;
visPanel.observeSelectionState(chartSelectionState);
scrollBar.observeSelectionState(chartSelectionState);
AlertHandler handler = new AlertHandler() {
public void handleAlert(EventObject alert)
{
List<ResultStep> selectedStepList =
((PERTChartSelectionState.SelectionChange) alert).selectedSteps;
String trace = traceText.getText();
int startPos = -1;
int endPos = -1;
operatorInfoText.setText("");
Iterator<ResultStep> stepIt = selectedStepList.iterator();
while (stepIt.hasNext()) {
ResultStep step = stepIt.next();
operatorInfoText.append(step.toString() + "\n\n\n\n");
if (startPos < 0) {
startPos =
Math.max(0,
StringUtil.getCharPosFromLineNum(trace,
step.traceStart));
}
else {
startPos =
Math.min(startPos,
StringUtil.getCharPosFromLineNum(trace,
step.traceStart));
}
endPos =
Math.max(endPos,
StringUtil.getCharPosFromLineNum(trace,
step.traceEnd));
}
if (selectedStepList.size() == 0) {
operatorInfoText.setText(NO_OPERATOR_SELECTED);
}
if ((startPos > -1) && (endPos > -1)) {
traceText.setSelection(startPos, endPos);
traceText.showSelection();
}
}
};
chartSelectionState.addHandler(this,
PERTChartSelectionState.SelectionChange.class,
handler);
}
public void displayTimeSlice(double start, double end)
{
scrollBar.displayTimeSlice(start, end);
}
public double getNativeTotalTime()
{
return visPanel.getNativeTotalTime();
}
public double getTotalTime()
{
return totalTime;
}
public void setTotalTime(double tt)
{
totalTime = Math.max(tt, visPanel.getNativeTotalTime());
visPanel.setTotalTime(totalTime);
scrollBar.setTotalTime(totalTime);
visPanel.resizeVisualization(null);
scrollBar.resizeVisualization(null);
}
}