/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.ie.view.widget;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.Border;
import org.openflexo.ColorCst;
import org.openflexo.foundation.DataModification;
import org.openflexo.foundation.DeletableObject;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.FlexoObservable;
import org.openflexo.foundation.FlexoObserver;
import org.openflexo.foundation.GraphicalFlexoObserver;
import org.openflexo.foundation.ie.IEObject;
import org.openflexo.foundation.ie.IEWOComponent;
import org.openflexo.foundation.ie.dm.DisplayNeedsRefresh;
import org.openflexo.foundation.ie.util.FlexoConceptualColor;
import org.openflexo.foundation.ie.widget.IEWidget;
import org.openflexo.foundation.utils.FlexoCSS;
import org.openflexo.ie.view.IESelectable;
import org.openflexo.ie.view.IEWOComponentView;
import org.openflexo.ie.view.controller.IEController;
import org.openflexo.utils.DrawUtils;
/**
* Abstract parent class for all IE widget At this level are managed following features:
* <ul>
* <li>Selection and Focus</li>
* <li>Represented object retrieving</li>
* <li>Inspection of represented object</li>
* </ul>
*
* @author bmangez, sguerin
*/
public abstract class IEWidgetView<T extends IEWidget> extends IEInnerDSWidgetView implements
/* InspectableObjectView, */GraphicalFlexoObserver, IESelectable {
protected class ObserverRegistation {
private FlexoObservable observable;
private FlexoObserver observer;
protected ObserverRegistation(FlexoObserver observer, FlexoObservable observable) {
super();
this.observer = observer;
this.observable = observable;
observable.addObserver(observer);
observerRegistations.add(this);
}
protected void removeFromObservers() {
if (observable != null) {
observable.deleteObserver(observer);
observable = null;
observer = null;
observerRegistations.remove(this);
}
}
}
private static final Logger logger = Logger.getLogger(IEWidgetView.class.getPackage().getName());
public static final String ATTRIB_DESCRIPTION_NAME = "description";
public static final String BINDING_VALUE_NAME = "value";
public static final String BINDING_TOOLTIP_NAME = "tooltip";
protected static final Border EMPTY_BORDER_1 = BorderFactory.createEmptyBorder(1, 1, 1, 1);
// ==========================================================================
// ============================= Variables
// ==================================
// ==========================================================================
private List<ObserverRegistation> observerRegistations;
private boolean _isSelected = false;
private boolean _isFocused = false;
private T _model;
protected IEWOComponentView _componentView;
// protected boolean holdsNextComputedPreferredSize = false;
// protected Dimension preferredSize = null;
// ==========================================================================
// ============================= Constructor
// ================================
// ==========================================================================
public IEWidgetView(IEController ieController, T model, boolean addDnDSupport, IEWOComponentView componentView) {
super(ieController, model, addDnDSupport);
observerRegistations = new ArrayList<IEWidgetView<T>.ObserverRegistation>();
_componentView = componentView;
_componentView.registerViewForWidget(model, this);
_model = model;
if (logger.isLoggable(Level.FINE)) {
logger.fine("Build new " + getClass().getName());
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Add " + getClass().getName() + " to pending views");
}
new ObserverRegistation(this, model);
updateTooltip();
setIsSelected(false);
setIsFocused(false);
addMouseListener(ieController.getIESelectionManager());
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
getIEController().getIESelectionManager().processMouseMoved(e);
}
});
}
protected void stopObserving(FlexoObservable observable) {
for (ObserverRegistation r : observerRegistations) {
if (r.observable == observable) {
r.removeFromObservers();
// Do not continue since we found the observer
// If you want to change this, duplicate the array or
// you will have a ConcurrentModificationException
break;
}
}
}
private String getTooltipFromModel() {
return getModel().getTooltip();
}
private void updateTooltip() {
if (getTooltipFromModel() != null && getTooltipFromModel().trim().length() > 0) {
if (getTooltipFromModel().length() <= 100) {
setToolTipText(getTooltipFromModel());
} else {
if (getTooltipFromModel().indexOf(' ', 100) > -1) {
setToolTipText(getTooltipFromModel().substring(0, getTooltipFromModel().indexOf(' ', 100)) + "...");
} else {
setToolTipText(getTooltipFromModel().substring(0, 100) + "...");
}
}
} else {
setToolTipText(null);
}
}
@Override
public IEWidgetView findViewForModel(IEObject object) {
return _componentView.findViewForModel(object);
}
public String getCSSName() {
return getModel().getCSSName();
}
public FlexoCSS getFlexoCSS() {
return getModel().getFlexoCSS();
}
public Color getMainColor() {
return colorFromConceptualColor(FlexoConceptualColor.MAIN_COLOR, getFlexoCSS());
}
public Color getTextColor() {
return colorFromConceptualColor(FlexoConceptualColor.TEXT_COLOR, getFlexoCSS());
}
public void delete() {
for (ObserverRegistation registration : new ArrayList<ObserverRegistation>(observerRegistations)) {
registration.removeFromObservers();
}
if (getParent() instanceof JComponent) {
((JComponent) getParent()).revalidate();
((JComponent) getParent()).repaint();
getParent().remove(this);
}
Component[] comp = getComponents();
for (int i = 0; i < comp.length; i++) {
if (comp[i] instanceof IEWidgetView) {
((IEWidgetView) comp[i]).delete();
}
}
_componentView.removeFrowWidgetViews(getModel());
removeAll();
}
public void setDefaultBorder() {
if (getModel().getIsRootOfPartialComponent() && getParent() != null) {
((JPanel) getParent()).setBorder(BorderFactory.createLineBorder(Color.BLUE, 3));
} else if (getParent() != null && getParent() instanceof IETDWidgetView) {
setBorder(null);
} else {
setBorder(EMPTY_BORDER_1);
}
}
// ==========================================================================
// ======================= IESelectable ============================
// ==========================================================================
/**
* Return boolean indicating if related object is selected
*
* @return boolean
*/
@Override
public boolean isSelected() {
return _isSelected;
}
@Override
public void setIsSelected(boolean b) {
_isSelected = b;
if (logger.isLoggable(Level.FINEST)) {
logger.finest("setIsSelected=" + b + " dans " + getClass().getName());
}
grabFocus();
repaint();
}
/**
* Sets related object to be focused or not
*/
@Override
public void setIsFocused(boolean b) {
_isFocused = b;
if (logger.isLoggable(Level.FINEST)) {
logger.finest("setIsFocused=" + b + " dans " + getClass().getName());
}
if (b) {
setBorder(BorderFactory.createLineBorder(ColorCst.BORDER_COLOR_FOR_FOCUSED_WIDGET));
} else {
setDefaultBorder();
}
repaint();
}
/**
* Return boolean indicating if related object is focused
*
* @return boolean
*/
@Override
public boolean isFocused() {
return _isFocused;
}
public IEWidget getSelectedObject() {
return _model;
}
@Override
public FlexoModelObject getObject() {
return getSelectedObject();
}
// ==========================================================================
// ======================= InspectableObjectView
// ============================
// ==========================================================================
@Override
public DeletableObject getDeletableObject() {
return _model;
}
// ==========================================================================
// ============================= Accessors
// ==================================
// ==========================================================================
public T getModel() {
return _model;
}
public final IEWidget getContainerModel() {
return getModel();
}
public final IEWOComponent getWOComponent() {
return _model.getWOComponent();
}
protected void switchToModel(T model) {
stopObserving(_model);
_model = model;
new ObserverRegistation(this, model);
}
public IEWidget getIEModel() {
return getModel();
}
public Point getCenter() {
return new Point(getWidth() / 2, getHeight() / 2);
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (_isSelected) {
paintSelection(g);
}
}
public void paintSelection(Graphics g) {
if (logger.isLoggable(Level.FINE)) {
logger.finer("Drawing selection");
}
Graphics2D g2 = (Graphics2D) g;
DrawUtils.turnOnAntiAlising(g2);
DrawUtils.setRenderQuality(g2);
DrawUtils.setColorRenderQuality(g2);
g2.setColor(Color.BLUE);
Dimension panelDim = getSize();
g2.fillRect(0, 0, 5, 5);
g2.fillRect(panelDim.width - 5, 0, 5, 5);
g2.fillRect(0, panelDim.height - 5, 5, 5);
g2.fillRect(panelDim.width - 5, panelDim.height - 5, 5, 5);
}
@Override
public String toString() {
return getClass().getName() + "/" + hashCode() + " view for model " + getModel();
}
public void updateConstraints() {
Container c = getParent();
IESequenceTRWidgetView tr = null;
while (c != null) {
if (c instanceof IESequenceTRWidgetView) {
tr = (IESequenceTRWidgetView) c;
}
c = c.getParent();
}
if (tr != null) {
tr.updateConstraints();
revalidate();
repaint();
}
}
/**
* Overrides update
*
* @see org.openflexo.foundation.FlexoObserver#update(org.openflexo.foundation.FlexoObservable,
* org.openflexo.foundation.DataModification)
*/
@Override
public void update(FlexoObservable observable, DataModification dataModification) {
if (observable == getModel() && dataModification instanceof DisplayNeedsRefresh) {
revalidate();
repaint();
} else if (observable == getModel() && dataModification.propertyName() != null && dataModification.propertyName().equals("tooltip")) {
updateTooltip();
}
}
}