/******************************************************************************* * 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.uimodel; import java.util.EventObject; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.FlowLayout; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.ImageFigure; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.LineBorder; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.RectangleFigure; import org.eclipse.draw2d.ToolbarLayout; import org.eclipse.draw2d.TreeSearch; import org.eclipse.draw2d.XYLayout; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import edu.cmu.cs.hcii.cogtool.CogToolPref; import edu.cmu.cs.hcii.cogtool.model.Design; import edu.cmu.cs.hcii.cogtool.model.DesignUtil; import edu.cmu.cs.hcii.cogtool.model.DeviceType; import edu.cmu.cs.hcii.cogtool.model.DoublePoint; import edu.cmu.cs.hcii.cogtool.model.DoubleSize; import edu.cmu.cs.hcii.cogtool.model.Frame; import edu.cmu.cs.hcii.cogtool.model.IWidget; import edu.cmu.cs.hcii.cogtool.model.InputDevice; import edu.cmu.cs.hcii.cogtool.model.TransitionSource; import edu.cmu.cs.hcii.cogtool.util.AlertHandler; import edu.cmu.cs.hcii.cogtool.util.FontUtils; import edu.cmu.cs.hcii.cogtool.util.GraphicsUtil; import edu.cmu.cs.hcii.cogtool.util.L10N; import edu.cmu.cs.hcii.cogtool.util.NameChangeAlert; import edu.cmu.cs.hcii.cogtool.util.PrecisionUtilities; import edu.cmu.cs.hcii.cogtool.util.SWTStringUtil; import edu.cmu.cs.hcii.cogtool.util.StringUtil; import edu.cmu.cs.hcii.cogtool.util.WindowUtil; import edu.cmu.cs.hcii.cogtool.view.CogToolScalableFigure; // NOTE THE NEED TO CALL dispose IF NO LONGER USING! public class DesignEditorFrame extends RectangleFigure implements CogToolScalableFigure, SelectionFigure<Frame> { public static final String LISTEN_TIME_TOOLTIP = L10N.get("DEF.ListenTimeTooltip", "User listening time (secs)"); public static final String NO_LISTEN_TIME_LABEL = L10N.get("DEF.NoListenTimeLabel", ""); public final static String SPEAKER_ICON_RESOURCE = "edu/cmu/cs/hcii/cogtool/resources/toolbar/Speaker.jpg"; private static Image SPEAKER_ICON_IMAGE = null; public static Image getSpeakerIconImage() { if (SPEAKER_ICON_IMAGE == null) { SPEAKER_ICON_IMAGE = GraphicsUtil.getImageFromResource(SPEAKER_ICON_RESOURCE); } return SPEAKER_ICON_IMAGE; } protected final static String DELETED_ICON_RESOURCE = "edu/cmu/cs/hcii/cogtool/resources/deleted_indicator.gif"; protected static final Image DELETED_IMG = GraphicsUtil.getImageFromResource(DELETED_ICON_RESOURCE); protected static final Label DELETED_TOOLTIP = new Label(L10N.get("DEF.FrameDeleted", "Frame is deleted")); public static final int MIN_HEIGHT = 2 * DesignUtil.DEVICE_HEIGHT; public static final int ALL_FIGURES = 0; // All figures public static final int ONLY_GRAPHICAL_SOURCE = 1; // IGraphicalSource protected double scale; protected boolean showToolTips; protected int sourceRolloverCursor; protected Frame frame; // model protected FrameLabel nameLabel; protected Label frameToolTip; protected boolean usesSpeaker; protected XYLayout speakerLayout = null; protected RectangleFigure speakerBox = null; protected int speakerImgWidth; protected int speakerImgHeight; protected Label speakerText; protected Label speakerTextToolTip; protected RectangleFigure divider; protected RectangleFigure timeWestBorder; protected Label listenTime; protected FrameUIModel frameUIModel; protected DefaultSEUIModel attrOverride = null; protected FrameUIModel displayAlpha; protected RectangleFigure inputDeviceBox; protected Figure frameWidgetBox; protected Map<InputDevice, GraphicalDevice> inputDevices = new HashMap<InputDevice, GraphicalDevice>(); protected Color unselectedBackground; protected boolean selected = false; protected AlertHandler transitionChangeHandler = null; /** * Just so we can tell whether it is the Frame's name label! * @author mlh */ public class FrameLabel extends Label { protected DesignEditorFrame frameFigure; public FrameLabel() { super(); frameFigure = DesignEditorFrame.this; Design design = frame.getDesign(); noteDeleted((design == null) || ! design.containsFrame(frame)); } public DesignEditorFrame getFrameFigure() { return frameFigure; } public Frame getFrame() { return frameFigure.getFrame(); } public void noteDeleted(boolean frameIsDeleted) { if (frameIsDeleted) { setIcon(DELETED_IMG); setIconAlignment(PositionConstants.LEFT); setToolTip(DELETED_TOOLTIP); } else { setIcon(null); setToolTip(null); } } } // NOT THREAD-SAFE!! protected static class FigureFilterSearch implements TreeSearch { protected int filter; public FigureFilterSearch(int figFilter) { filter = figFilter; } public void setFilter(int newFigureFilter) { filter = newFigureFilter; } public boolean accept(IFigure figure) { switch (filter) { case ONLY_GRAPHICAL_SOURCE: { return (figure instanceof GraphicalSource<?>); } case ALL_FIGURES: default: { return true; } } } public boolean prune(IFigure figure) { return false; } } public int getWidth() { return getSize().width; } public int getLabelHeight() { if (usesSpeaker) { return speakerBox.getLocation().y - getLocation().y; } return frameWidgetBox.getLocation().y - getLocation().y; } public Label getLabel() { return nameLabel; } public void noteDeleted(boolean isFrameDeleted) { nameLabel.noteDeleted(isFrameDeleted); } public DesignEditorFrame(Frame frameModel, boolean supportToolTips, int srcRolloverCursor) { this(frameModel, DesignUtil.DEFAULT_FRAME_SCALE, supportToolTips, srcRolloverCursor, WindowUtil.SELECT_CURSOR, null); } public DesignEditorFrame(Frame frameModel, double initialScale, int srcRolloverCursor, DefaultSEUIModel override) { this(frameModel, initialScale, true, // support tooltips! srcRolloverCursor, WindowUtil.SELECT_CURSOR, override); } protected static final int SPEAKER_DIVIDER_WIDTH = 2; protected static final int LISTEN_TIME_WIDTH = 70; protected void addSpeakerBox() { speakerBox.setBorder(new LineBorder(ColorConstants.black, 1)); speakerBox.setOpaque(true); Image speakerIconImg = getSpeakerIconImage(); // TODO: handle getImage returning null org.eclipse.swt.graphics.Rectangle bds = speakerIconImg.getBounds(); IFigure speakerImgFig = new ImageFigure(speakerIconImg); IFigure speakerImgToolTip = new Label(L10N.get("DEF.SpeakerText", "Speaker text")); speakerImgFig.setToolTip(speakerImgToolTip); speakerImgWidth = bds.width; speakerImgHeight = bds.height; speakerLayout.setConstraint(speakerImgFig, new Rectangle(0, 0, bds.width, bds.height)); speakerBox.add(speakerImgFig); RectangleFigure speakerEastBorder = new RectangleFigure(); speakerEastBorder.setBorder(new LineBorder(ColorConstants.black, 1)); speakerLayout.setConstraint(speakerEastBorder, new Rectangle(speakerImgWidth, 0, SPEAKER_DIVIDER_WIDTH, speakerImgHeight)); speakerBox.add(speakerEastBorder); timeWestBorder = new RectangleFigure(); timeWestBorder.setBorder(new LineBorder(ColorConstants.black, 1)); speakerBox.add(timeWestBorder); String text = frame.getSpeakerText(); speakerText = new Label(text); speakerText.setLabelAlignment(PositionConstants.LEFT); speakerTextToolTip = new Label(text); if ((text != null) && ! text.equals("")) { speakerText.setToolTip(speakerTextToolTip); } speakerBox.add(speakerText); divider = new RectangleFigure(); divider.setBorder(new LineBorder(ColorConstants.black, 1)); speakerBox.add(divider); double listenTimeInSecs = frame.getListenTimeInSecs(); listenTime = new Label((listenTimeInSecs == Frame.NO_LISTEN_TIME) ? NO_LISTEN_TIME_LABEL : Double.toString(listenTimeInSecs)); listenTime.setLabelAlignment(PositionConstants.RIGHT); speakerBox.add(listenTime); Label listenTimeToolTip = new Label(LISTEN_TIME_TOOLTIP); listenTime.setToolTip(listenTimeToolTip); } public DesignEditorFrame(Frame frameModel, double initialScale, boolean supportToolTips, int srcRolloverCursor, int rolloverCursor, // no one specifies this yet DefaultSEUIModel override) { super(); // long start = System.currentTimeMillis(); // System.out.println("DesignEditorFrame<init>:" + start + " { "); frame = frameModel; scale = initialScale; showToolTips = supportToolTips; sourceRolloverCursor = srcRolloverCursor; setCursor(WindowUtil.getCursor(rolloverCursor)); DoublePoint frameOrigin = frameModel.getFrameOrigin(); setLocation(PrecisionUtilities.getDraw2DPoint(frameOrigin)); setLayoutManager(new ToolbarLayout()); setBorder(new LineBorder(ColorConstants.black, 1)); setOpaque(true); frameToolTip = new Label(); String tooltip = SWTStringUtil.insertEllipsis(frame.getName(), 400, StringUtil.NO_FRONT, frameToolTip.getFont()); frameToolTip.setText(tooltip); nameLabel = new FrameLabel(); nameLabel.setTextAlignment(PositionConstants.CENTER); nameLabel.setBorder(new LineBorder(ColorConstants.black, 1)); nameLabel.setToolTip(frameToolTip); add(nameLabel); usesSpeaker = frame.getDesign().getDeviceTypes().contains(DeviceType.Speaker); speakerLayout = new XYLayout(); speakerBox = new RectangleFigure(); speakerBox.setLayoutManager(speakerLayout); if (usesSpeaker) { addSpeakerBox(); } add(speakerBox); frameWidgetBox = new Figure() { @Override protected boolean useLocalCoordinates() { return true; } }; frameWidgetBox.setLayoutManager(new FlowLayout()); frameWidgetBox.setBorder(new LineBorder(ColorConstants.black, 1)); add(frameWidgetBox); attrOverride = override; FrameUIModel frameUIModelAlpha = new FrameUIModel(frame, showToolTips, sourceRolloverCursor, scale, true, attrOverride); frameUIModel = frameUIModelAlpha; displayAlpha = frameUIModelAlpha; frameWidgetBox.add(frameUIModel.getContents()); // Dimension bds = getPreferredSize(); AlertHandler renameHandler = new AlertHandler() { public void handleAlert(EventObject alert) { String newName = ((Frame) alert.getSource()).getName(); nameLabel.setText(SWTStringUtil.insertEllipsis(newName, getWidth(), StringUtil.NO_FRONT, nameLabel.getFont())); frameToolTip.setText(SWTStringUtil.insertEllipsis(newName, 400, StringUtil.NO_FRONT, frameToolTip.getFont())); } }; frame.addHandler(this, NameChangeAlert.class, renameHandler); AlertHandler deviceChangeHandler = new AlertHandler() { public void handleAlert(EventObject alert) { Frame.InputDeviceChange deviceChg = (Frame.InputDeviceChange) alert; addInputDevice(deviceChg.newDevice); if (transitionChangeHandler != null) { deviceChg.newDevice.addHandler(this, TransitionSource.TransitionChange.class, transitionChangeHandler); } resetFrameSize(); } }; frame.addHandler(this, Frame.InputDeviceChange.class, deviceChangeHandler); AlertHandler speakerChangeHandler = new AlertHandler() { public void handleAlert(EventObject alert) { String text = frame.getSpeakerText(); speakerText.setText(text); if ((text != null) && ! text.equals("")) { speakerTextToolTip.setText(text); speakerText.setToolTip(speakerTextToolTip); } else { speakerText.setToolTip(null); } double listenTimeInSecs = frame.getListenTimeInSecs(); if (listenTimeInSecs == Frame.NO_LISTEN_TIME) { listenTime.setText(NO_LISTEN_TIME_LABEL); } else { text = Double.toString(listenTimeInSecs); listenTime.setText(text); } } }; frame.addHandler(this, Frame.SpeakerChange.class, speakerChangeHandler); inputDeviceBox = new RectangleFigure(); inputDeviceBox.setBorder(new LineBorder(ColorConstants.black, 1)); add(inputDeviceBox); // Set up horizontal layout // Flow Layout with a center alignment and 0 spacing, will // place the widgets nicely in a line. in the center. FlowLayout deviceBoxLayout = new FlowLayout(FlowLayout.HORIZONTAL); deviceBoxLayout.setMajorAlignment(FlowLayout.ALIGN_CENTER); deviceBoxLayout.setMinorSpacing(DesignUtil.DEVICE_SPACING); inputDeviceBox.setLayoutManager(deviceBoxLayout); // Install the input devices Iterator<InputDevice> devices = frame.getInputDevices().iterator(); while (devices.hasNext()) { addInputDevice(devices.next()); } frameUIModel.addHandler(this, FrameUIModel.WidgetShapeImageChange.class, new AlertHandler() { public void handleAlert(EventObject e) { resetFrameSize(); } }); // set the font so resetFrameSize can correctly calculate the size // needed. This causes the calculate size call to be made ONCE. // and painted ONCE, improving performance. setFont(FontUtils.DEFAULT_FONT); resetFrameSize(); nameLabel.setText(SWTStringUtil.insertEllipsis(frame.getName(), getWidth(), StringUtil.NO_FRONT, FontUtils.DEFAULT_FONT)); // Is this valid here, or do we have to wait for a repaint? unselectedBackground = getBackgroundColor(); // long end = System.currentTimeMillis(); // System.out.println((end-start) + " } " + end); } public void dispose() { frameUIModel.removeAllHandlers(this); frameUIModel.dispose(); Iterator<IWidget> sources = frame.getWidgets().iterator(); while (sources.hasNext()) { IWidget widget = sources.next(); widget.removeAllHandlers(this); } Iterator<InputDevice> devices = frame.getInputDevices().iterator(); while (devices.hasNext()) { InputDevice device = devices.next(); device.removeAllHandlers(this); } frame.removeAllHandlers(this); // Need to dispose all InputSources that were created by this class Iterator<GraphicalDevice> iter = inputDevices.values().iterator(); while (iter.hasNext()) { GraphicalDevice d = iter.next(); d.dispose(); } } public Frame getFrame() { return frame; } public Frame getModel() { return getFrame(); } public FrameUIModel getFrameUIModel() { return frameUIModel; } public void addOriginChangeHandler(AlertHandler handler) { frame.addHandler(this, Frame.OriginChange.class, handler); } public void addWidgetChangeHandler(AlertHandler handler) { frame.addHandler(this, Frame.WidgetChange.class, handler); } public void addWidgetRecoveryHandler(AlertHandler handler) { frameUIModel.addHandler(this, FrameUIModel.WidgetRecovery.class, handler); } public void addWidgetShapeChangeHandler(AlertHandler handler) { frameUIModel.addHandler(this, FrameUIModel.WidgetShapeImageChange.class, handler); } public void addTransitionChangeHandler(AlertHandler handler) { Iterator<IWidget> sources = frame.getWidgets().iterator(); while (sources.hasNext()) { IWidget widget = sources.next(); widget.addHandler(this, TransitionSource.TransitionChange.class, handler); } Iterator<InputDevice> devices = frame.getInputDevices().iterator(); while (devices.hasNext()) { InputDevice device = devices.next(); device.addHandler(this, TransitionSource.TransitionChange.class, handler); } transitionChangeHandler = handler; } public void noteDeviceTypeAdd() { usesSpeaker = frame.getDesign().getDeviceTypes().contains(DeviceType.Speaker); if (usesSpeaker) { addSpeakerBox(); resetFrameSize(); } } protected void addInputDevice(InputDevice inputDevice) { GraphicalDevice deviceFigure = new GraphicalDevice(inputDevice, GraphicsUtil.defaultWidgetColor, showToolTips, sourceRolloverCursor, displayAlpha); //TODO: toString is wrong? -- needs to be L10N! // add getLocalizedLabel to DeviceType? inputDeviceBox.add(deviceFigure); inputDevices.put(inputDevice, deviceFigure); // TODO: Remember to remove if deleted. } public static class SourceFigureIterator implements Iterator<GraphicalSource<? extends TransitionSource>> { protected Iterator<GraphicalWidget<?>> widgetFigures; protected Iterator<GraphicalDevice> deviceFigures; public SourceFigureIterator(DesignEditorFrame frameFig) { widgetFigures = new FrameUIModel.WidgetFigureIterator(frameFig.getFrameUIModel()); deviceFigures = frameFig.inputDevices.values().iterator(); } public boolean hasNext() { if (widgetFigures != null) { if (widgetFigures.hasNext()) { return true; } widgetFigures = null; } if (deviceFigures != null) { if (deviceFigures.hasNext()) { return true; } deviceFigures = null; } return false; } public GraphicalSource<? extends TransitionSource> next() { if (hasNext()) { if (widgetFigures != null) { return widgetFigures.next(); } if (deviceFigures != null) { return deviceFigures.next(); } } throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException(); } } public Iterator<GraphicalSource<? extends TransitionSource>> getSourceFigureIterator() { return new SourceFigureIterator(this); } public GraphicalWidget<?> getWidgetFigure(IWidget widget) { return frameUIModel.getWidgetFigure(widget); } public GraphicalDevice getDeviceFigure(InputDevice device) { return inputDevices.get(device); } public GraphicalSource<? extends TransitionSource> getSourceFigure(TransitionSource source) { GraphicalDevice widgetFigure = inputDevices.get(source); if (widgetFigure != null) { return widgetFigure; } IWidget widget = (IWidget) source; if (widget != null) { return getWidgetFigure(widget); } return null; } protected void resetFrameSize() { // Update the size with the preferred size of the contents. DoubleSize size = computeFrameSize(getScale()); int width = PrecisionUtilities.round(size.width); int height = PrecisionUtilities.round(size.height); // Set the initial size to force a repaint call. // Call super, since we actually want to set the Size.. vs the current // which will try and resize to the "current size" // while this is actually a flag to force a paint. super.setSize(width, height); super.setPreferredSize(width, height); // The input box has a border, which makes it take additional space // Force this to always take the extra space up by frameWidget Box if (usesSpeaker) { height -= speakerBox.getPreferredSize().height; } height -= (inputDeviceBox.getPreferredSize().height + inputDeviceBox.getInsets().getHeight()); height -= nameLabel.getPreferredSize().height; frameWidgetBox.setSize(width, height); frameWidgetBox.setPreferredSize(width, height); if (usesSpeaker) { int insetsWidth = getInsets().getWidth(); int speakerTextWidth = width - insetsWidth - (4 * SPEAKER_DIVIDER_WIDTH) - speakerImgWidth - LISTEN_TIME_WIDTH - 1; Rectangle layoutConstraint = new Rectangle(speakerImgWidth + SPEAKER_DIVIDER_WIDTH, 0, speakerTextWidth, speakerImgHeight); speakerLayout.setConstraint(speakerText, layoutConstraint); layoutConstraint = new Rectangle(speakerImgWidth + SPEAKER_DIVIDER_WIDTH + speakerTextWidth, 0, SPEAKER_DIVIDER_WIDTH, speakerImgHeight); speakerLayout.setConstraint(divider, layoutConstraint); layoutConstraint = new Rectangle(speakerImgWidth + (2 * SPEAKER_DIVIDER_WIDTH) + speakerTextWidth, 0, LISTEN_TIME_WIDTH, speakerImgHeight); speakerLayout.setConstraint(listenTime, layoutConstraint); layoutConstraint = new Rectangle(speakerImgWidth + (3 * SPEAKER_DIVIDER_WIDTH) + speakerTextWidth + LISTEN_TIME_WIDTH, 0, SPEAKER_DIVIDER_WIDTH, speakerImgHeight); speakerLayout.setConstraint(timeWestBorder, layoutConstraint); } } protected DoubleSize computeFrameSize(double zoom) { // Use scaled versions of min-width & min_height so that // even if the frame is empty, a scale operation will have an "effect" double minScale = (scale > 1) ? scale : 1.0; double width = CogToolPref.MIN_FRAME_WIDTH.getInt() * minScale; double height = MIN_HEIGHT * minScale; // Make sure the contents is at least the height of 100, and the // width of the frame. DoubleSize frameSize = frameUIModel.getPreferredSize(zoom); if (frameSize.width > width) { width = frameSize.width; } if (frameSize.height > height) { height = frameSize.height; } if (usesSpeaker) { height += speakerBox.getPreferredSize().height + speakerBox.getInsets().getHeight(); } // The input box has a border, which makes it take additional space height += inputDeviceBox.getPreferredSize().height + inputDeviceBox.getInsets().getHeight(); height += nameLabel.getPreferredSize().height; return new DoubleSize(width, height); } /** * Just a simple override to make it easier to determine performance hits. */ @Override public void paint(Graphics gc) { super.paint(gc); } public boolean isSelected() { return selected; } public void setSelected(boolean select) { if (selected != select) { selected = select; dynamicHighlight(false); } } public void dynamicHighlight(boolean highlight) { if (highlight) { setBackgroundColor(ColorConstants.gray); } else if (selected) { setBackgroundColor(ColorConstants.lightBlue); } else { setBackgroundColor(unselectedBackground); } this.repaint(); } public void setScale(double s) { if (s <= 0) { throw new IllegalArgumentException("Cannot set a non-positive scale"); } scale = s; // Apply the zoom. frameUIModel.setZoom(scale); resetFrameSize(); } public double getScale() { return scale; } @Override public void setSize(int width, int height) { resetFrameSize(); } protected static final FigureFilterSearch figureFilter = new FigureFilterSearch(ALL_FIGURES); public IFigure getFigureAtXY(int x, int y, int filter) { figureFilter.setFilter(filter); return findFigureAt(x, y, figureFilter); } public Rectangle getChildrenUtilizedAreaScaled() { return getClientArea(); } public Rectangle getChildrenUtilizedAreaUnscaled() { DoubleSize size = computeFrameSize(1.0); int width = PrecisionUtilities.round(size.width); int height = PrecisionUtilities.round(size.height); return new Rectangle(0, 0, width, height); } public void hideAllChildren() { frameUIModel.hideAllChildren(); } }