org.netbeans.api.visual.widget.ComponentWidget Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.api.visual.widget;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
/**
* This widget allows to use an AWT/Swing component in the scene. The widget itself just represents and reserve the place
* occupied by the component. When a component is resized, then reserved place is recalculated. The component placement
* is automatically update based on the placement of the widget.
* The widget also paints the component in the satelite views.
*
* When a widget is added into the scene, it has to attach a scene listener for automatic recalculation. The attaching
* is done automatically for the first time.
*
* @author David Kaspar
*/
// TODO - addComponentResizeListener
// TODO - fix calculateClientArea method - use convertViewToScene instead
public class ComponentWidget extends Widget {
private ComponentWrapper componentWrapper;
private Component component;
private boolean componentAdded;
private boolean widgetAdded;
private double zoomFactor = Double.MIN_VALUE;
private ComponentSceneListener validateListener;
private ComponentComponentListener componentListener;
private boolean componentVisible = false;
private static class ComponentWrapper extends JComponent {
@Override
public void paint(Graphics g) {
}
void doPaint(Graphics g) {
super.paint(g);
}
};
/**
* Creates a component widget.
* @param scene the scene
* @param component the AWT/Swing component
*/
public ComponentWidget (Scene scene, Component component) {
super(scene);
componentWrapper = new ComponentWrapper();
componentWrapper.setLayout(new BorderLayout(0, 0));
componentWrapper.add(component);
this.component = component;
validateListener = null;
componentListener = new ComponentComponentListener ();
setComponentVisible (true);
}
/**
* Returns a AWT/Swing component.
* @return the AWT/Swing component
*/
public final Component getComponent () {
return component;
}
/**
* Returns whether the component should be visible.
* @return true if the component is visible
*/
public final boolean isComponentVisible () {
return componentVisible;
}
/**
* Sets whether the component should be visible.
* @param componentVisible if true, then the component is visible
*/
public final void setComponentVisible (boolean componentVisible) {
if (this.componentVisible == componentVisible)
return;
this.componentVisible = componentVisible;
attach ();
revalidate ();
}
@Override
protected final void notifyAdded () {
widgetAdded = true;
attach ();
}
@Override
protected final void notifyRemoved () {
widgetAdded = false;
}
private void attach () {
if (validateListener != null)
return;
validateListener = new ComponentSceneListener ();
getScene ().addSceneListener (validateListener);
}
private void detach () {
if (validateListener == null)
return;
getScene ().removeSceneListener (validateListener);
validateListener = null;
}
/**
* Calculates a client area from the preferred size of the component.
* @return the calculated client area
*/
@Override
protected final Rectangle calculateClientArea () {
Dimension preferredSize = component.getPreferredSize ();
zoomFactor = getScene ().getZoomFactor ();
preferredSize.width = (int) Math.floor (preferredSize.width / zoomFactor);
preferredSize.height = (int) Math.floor (preferredSize.height / zoomFactor);
return new Rectangle (preferredSize);
}
private void addComponent () {
Scene scene = getScene ();
if (! componentAdded) {
scene.getView().add(componentWrapper);
scene.getView ().revalidate ();
component.addComponentListener (componentListener);
componentAdded = true;
}
component.removeComponentListener (componentListener);
componentWrapper.setBounds(scene.convertSceneToView(convertLocalToScene(getClientArea())));
component.addComponentListener (componentListener);
component.repaint();
}
private void removeComponent () {
Scene scene = getScene ();
if (componentAdded) {
component.removeComponentListener (componentListener);
scene.getView().remove(componentWrapper);
scene.getView ().revalidate ();
componentAdded = false;
}
}
/**
* Paints the component widget.
*/
@Override
protected final void paintWidget() {
RepaintManager rm = RepaintManager.currentManager(null);
boolean isDoubleBuffered = component instanceof JComponent && rm.isDoubleBufferingEnabled();
if (isDoubleBuffered) {
rm.setDoubleBufferingEnabled(false);
}
Graphics2D graphics = getGraphics();
Rectangle bounds = getClientArea();
AffineTransform previousTransform = graphics.getTransform();
graphics.translate(bounds.x, bounds.y);
double zoomFactor = getScene().getZoomFactor();
graphics.scale(1 / zoomFactor, 1 / zoomFactor);
if (componentVisible) {
componentWrapper.doPaint(graphics);
} else {
component.paint(graphics);
}
graphics.setTransform(previousTransform);
if (isDoubleBuffered) {
rm.setDoubleBufferingEnabled(true);
}
}
private final class ComponentSceneListener implements Scene.SceneListener {
public void sceneRepaint () {
}
public void sceneValidating () {
double newZoomFactor = getScene ().getZoomFactor ();
if (Math.abs (newZoomFactor - zoomFactor) != 0.0) {
revalidate ();
zoomFactor = newZoomFactor;
}
}
public void sceneValidated () {
if (widgetAdded && componentVisible)
addComponent ();
else {
removeComponent ();
detach ();
}
}
}
private final class ComponentComponentListener implements ComponentListener {
public void componentResized (ComponentEvent e) {
revalidate ();
}
public void componentMoved (ComponentEvent e) {
revalidate ();
}
public void componentShown (ComponentEvent e) {
}
public void componentHidden (ComponentEvent e) {
}
}
}