/*
* (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.fib.editor.view;
import java.awt.Component;
import java.awt.Container;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceContext;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import org.openflexo.fib.controller.FIBController;
import org.openflexo.fib.editor.controller.DraggedFIBComponent;
import org.openflexo.fib.editor.controller.ExistingElementDrag;
import org.openflexo.fib.editor.controller.FIBEditorController;
import org.openflexo.fib.editor.controller.FIBEditorPalette;
import org.openflexo.fib.editor.view.container.FIBEditableSplitPanelView;
import org.openflexo.fib.model.FIBAddingNotification;
import org.openflexo.fib.model.FIBAttributeNotification;
import org.openflexo.fib.model.FIBColor;
import org.openflexo.fib.model.FIBComponent;
import org.openflexo.fib.model.FIBContainer;
import org.openflexo.fib.model.FIBFont;
import org.openflexo.fib.model.FIBModelNotification;
import org.openflexo.fib.model.FIBMultipleValues;
import org.openflexo.fib.model.FIBNumber;
import org.openflexo.fib.model.FIBPanel;
import org.openflexo.fib.model.FIBRemovingNotification;
import org.openflexo.fib.model.FIBTab;
import org.openflexo.fib.model.FIBWidget;
import org.openflexo.fib.view.FIBContainerView;
import org.openflexo.fib.view.FIBView;
import org.openflexo.fib.view.FIBWidgetView;
import org.openflexo.fib.view.container.FIBPanelView;
import org.openflexo.fib.view.container.FIBTabPanelView;
import org.openflexo.fib.view.container.FIBTabView;
import org.openflexo.fib.view.widget.FIBColorWidget;
import org.openflexo.fib.view.widget.FIBFontWidget;
import org.openflexo.fib.view.widget.FIBNumberWidget;
import org.openflexo.logging.FlexoLogger;
import org.openflexo.swing.Focusable;
public class FIBEditableViewDelegate<M extends FIBComponent, J extends JComponent> implements MouseListener, FocusListener, Focusable {
static final Logger logger = FlexoLogger.getLogger(FIBEditableViewDelegate.class.getPackage().getName());
private FIBEditableView<M, J> view;
private DragSource dragSource;
private MoveDGListener dgListener;
private MoveDSListener dsListener;
private int dragAction = DnDConstants.ACTION_MOVE;
public FIBEditableViewDelegate(FIBEditableView<M, J> view) {
this.view = view;
view.getJComponent().setFocusable(true);
view.getJComponent().setRequestFocusEnabled(true);
recursivelyAddListenersTo(view.getJComponent());
// view.getJComponent().addMouseListener(this);
// view.getJComponent().addFocusListener(this);
view.getEditorController().registerViewDelegate(this);
if (view.getPlaceHolders() != null) {
for (PlaceHolder ph : view.getPlaceHolders()) {
// Listen to drag'n'drop events
new FIBDropTarget(ph);
}
}
dragSource = DragSource.getDefaultDragSource();
dsListener = new MoveDSListener();
dgListener = new MoveDGListener();
if (!(view instanceof FIBEditableSplitPanelView)) {
DragGestureRecognizer newDGR = dragSource.createDefaultDragGestureRecognizer(view.getDynamicJComponent(), dragAction,
dgListener);
}
}
public void delete() {
logger.fine("Delete delegate view=" + view);
recursivelyDeleteListenersFrom(view.getJComponent());
view.getEditorController().unregisterViewDelegate(this);
view = null;
}
private void recursivelyAddListenersTo(Component c) {
/*for (MouseListener ml : c.getMouseListeners()) {
c.removeMouseListener(ml);
}*/
c.addMouseListener(this);
c.addFocusListener(this);
// Listen to drag'n'drop events
new FIBDropTarget(view);
if (c instanceof Container) {
for (Component c2 : ((Container) c).getComponents()) {
if (!isComponentRootComponentForAnyFIBView(c2)) {
recursivelyAddListenersTo(c2);
}
}
}
}
private void recursivelyDeleteListenersFrom(Component c) {
c.removeMouseListener(this);
c.removeFocusListener(this);
if (c instanceof Container) {
for (Component c2 : ((Container) c).getComponents()) {
if (!isComponentRootComponentForAnyFIBView(c2)) {
recursivelyDeleteListenersFrom(c2);
}
}
}
}
private boolean isComponentRootComponentForAnyFIBView(Component c) {
Enumeration<FIBView<?, ?>> en = getController().getViews();
while (en.hasMoreElements()) {
FIBView<?, ?> v = en.nextElement();
if (v.getResultingJComponent() == c) {
return true;
}
}
return false;
}
public FIBEditorController getEditorController() {
return view.getEditorController();
}
public FIBController getController() {
return view.getEditorController().getController();
}
public M getFIBComponent() {
return view.getComponent();
}
public JComponent getJComponent() {
return view.getJComponent();
}
@Override
public boolean isFocused() {
return getEditorController().getFocusedObject() == getFIBComponent();
}
@Override
public void setFocused(boolean focused) {
getEditorController().setFocusedObject(getFIBComponent());
}
private List<Object> placeHolderVisibleRequesters = new ArrayList<Object>();
public void addToPlaceHolderVisibleRequesters(Object requester) {
if (!placeHolderVisibleRequesters.contains(requester)) {
placeHolderVisibleRequesters.add(requester);
updatePlaceHoldersVisibility();
}
}
public void removeFromPlaceHolderVisibleRequesters(Object requester) {
if (placeHolderVisibleRequesters.remove(requester)) {
updatePlaceHoldersVisibility();
}
}
private boolean updatePlaceHoldersVisibilityRequested = false;
private void updatePlaceHoldersVisibility() {
if (updatePlaceHoldersVisibilityRequested) {
return;
}
updatePlaceHoldersVisibilityRequested = true;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (view != null) {
boolean visible = placeHolderVisibleRequesters.size() > 0;
if (view.getPlaceHolders() != null) {
for (PlaceHolder ph : view.getPlaceHolders()) {
ph.setVisible(visible);
}
}
updatePlaceHoldersVisibilityRequested = false;
}
}
});
}
@Override
public void mouseClicked(MouseEvent e) {
getEditorController().setSelectedObject(getFIBComponent());
view.getJComponent().requestFocusInWindow();
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger() || e.getButton() == MouseEvent.BUTTON3) {
getEditorController().getContextualMenu().displayPopupMenu(getFIBComponent(), view.getJComponent(), e);
}
}
@Override
public void focusLost(FocusEvent e) {
// getController().setSelectedObject(null);
}
@Override
public void focusGained(FocusEvent e) {
getEditorController().setSelectedObject(getFIBComponent());
}
@Override
public void mouseEntered(MouseEvent e) {
getEditorController().setFocusedObject(getFIBComponent());
}
@Override
public void mouseExited(MouseEvent e) {
getEditorController().setFocusedObject(null);
}
public void receivedModelNotifications(Observable o, FIBModelNotification dataModification) {
// System.out.println("receivedModelNotifications o=" + o + " dataModification=" + dataModification);
if (view == null) {
logger.warning("Received ModelNotifications for null view !!!");
return;
}
if (o instanceof FIBContainer && view instanceof FIBContainerView) {
if (dataModification instanceof FIBAddingNotification) {
if (((FIBAddingNotification) dataModification).getAddedValue() instanceof FIBComponent) {
// addSubComponent((FIBComponent)((FIBAddingNotification)dataModification).getAddedValue());
((FIBContainerView) view).updateLayout();
}
} else if (dataModification instanceof FIBRemovingNotification) {
if (((FIBRemovingNotification) dataModification).getRemovedValue() instanceof FIBComponent) {
// addSubComponent((FIBComponent)((FIBAddingNotification)dataModification).getAddedValue());
((FIBContainerView) view).updateLayout();
}
} else if (dataModification instanceof FIBAttributeNotification) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBContainer.Parameters.subComponents) {
((FIBContainerView) view).updateLayout();
}
}
}
if (o instanceof FIBTab && view instanceof FIBTabView) {
if (dataModification instanceof FIBAttributeNotification) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBTab.Parameters.title) {
if (view.getParentView() instanceof FIBTabPanelView) {
// Arghlll how do we update titles on this.
}
}
}
}
if (o instanceof FIBPanel && view instanceof FIBPanelView) {
if (dataModification instanceof FIBAttributeNotification) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBPanel.Parameters.border || n.getAttribute() == FIBPanel.Parameters.borderColor
|| n.getAttribute() == FIBPanel.Parameters.borderTitle || n.getAttribute() == FIBPanel.Parameters.borderTop
|| n.getAttribute() == FIBPanel.Parameters.borderLeft || n.getAttribute() == FIBPanel.Parameters.borderRight
|| n.getAttribute() == FIBPanel.Parameters.borderBottom || n.getAttribute() == FIBPanel.Parameters.titleFont
|| n.getAttribute() == FIBPanel.Parameters.darkLevel) {
((FIBPanelView) view).updateBorder();
} else if (n.getAttribute() == FIBPanel.Parameters.layout || n.getAttribute() == FIBPanel.Parameters.flowAlignment
|| n.getAttribute() == FIBPanel.Parameters.boxLayoutAxis || n.getAttribute() == FIBPanel.Parameters.vGap
|| n.getAttribute() == FIBPanel.Parameters.hGap || n.getAttribute() == FIBPanel.Parameters.rows
|| n.getAttribute() == FIBPanel.Parameters.cols || n.getAttribute() == FIBPanel.Parameters.protectContent) {
((FIBPanelView) view).updateLayout();
}
}
}
if (o instanceof FIBWidget) {
FIBWidgetView widgetView = (FIBWidgetView) view;
if (dataModification instanceof FIBAttributeNotification) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBWidget.Parameters.manageDynamicModel) {
widgetView.getComponent().updateBindingModel();
} else if (n.getAttribute() == FIBWidget.Parameters.readOnly) {
widgetView.updateEnability();
}
}
}
if (o instanceof FIBMultipleValues) {
if (dataModification instanceof FIBAttributeNotification) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBMultipleValues.Parameters.staticList || n.getAttribute() == FIBMultipleValues.Parameters.list
|| n.getAttribute() == FIBMultipleValues.Parameters.array) {
view.updateDataObject(view.getDataObject());
}
}
}
if (o instanceof FIBNumber) {
if (dataModification instanceof FIBAttributeNotification) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBNumber.Parameters.allowsNull) {
((FIBNumberWidget<?>) view).updateCheckboxVisibility();
} else if (n.getAttribute() == FIBNumber.Parameters.columns) {
((FIBNumberWidget<?>) view).updateColumns();
}
}
}
if (o instanceof FIBFont) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBFont.Parameters.allowsNull) {
((FIBFontWidget) view).updateCheckboxVisibility();
}
}
if (o instanceof FIBColor) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBColor.Parameters.allowsNull) {
((FIBColorWidget) view).updateCheckboxVisibility();
}
}
/*
* if (o instanceof FIBContainer) { if (dataModification instanceof FIBAttributeNotification) { FIBAttributeNotification n =
* (FIBAttributeNotification) dataModification; if (n.getAttribute() == FIBContainer.Parameters.subComponents && view instanceof
* FIBContainerView) { ((FIBContainerView) view).updateLayout(); } } }
*/
if (o instanceof FIBComponent) {
if (dataModification instanceof FIBAttributeNotification) {
FIBAttributeNotification n = (FIBAttributeNotification) dataModification;
if (n.getAttribute() == FIBComponent.Parameters.constraints || n.getAttribute() == FIBComponent.Parameters.width
|| n.getAttribute() == FIBComponent.Parameters.height || n.getAttribute() == FIBComponent.Parameters.minWidth
|| n.getAttribute() == FIBComponent.Parameters.minHeight || n.getAttribute() == FIBComponent.Parameters.maxWidth
|| n.getAttribute() == FIBComponent.Parameters.maxHeight
|| n.getAttribute() == FIBComponent.Parameters.useScrollBar
|| n.getAttribute() == FIBComponent.Parameters.horizontalScrollbarPolicy
|| n.getAttribute() == FIBComponent.Parameters.verticalScrollbarPolicy) {
FIBView parentView = view.getParentView();
FIBEditorController controller = getEditorController();
if (parentView instanceof FIBContainerView) {
((FIBContainerView) parentView).updateLayout();
}
controller.notifyFocusedAndSelectedObject();
} else if (n.getAttribute() == FIBComponent.Parameters.data) {
view.updateDataObject(view.getDataObject());
} else if (n.getAttribute() == FIBComponent.Parameters.font) {
((FIBView) view).updateFont();
} else if (n.getAttribute() == FIBComponent.Parameters.backgroundColor
|| n.getAttribute() == FIBComponent.Parameters.foregroundColor
|| n.getAttribute() == FIBComponent.Parameters.opaque) {
((FIBView) view).updateGraphicalProperties();
((FIBView) view).getJComponent().revalidate();
((FIBView) view).getJComponent().repaint();
}
}
}
}
public static class FIBDropTarget extends DropTarget {
private FIBEditableView editableView;
private PlaceHolder placeHolder = null;
public FIBDropTarget(FIBEditableView editableView) {
super(editableView.getJComponent(), DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE, editableView.getEditorController()
.buildPaletteDropListener(editableView, null), true);
this.editableView = editableView;
logger.fine("Made FIBDropTarget for " + getFIBComponent());
}
public FIBDropTarget(PlaceHolder placeHolder) {
super(placeHolder, DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE, placeHolder.getView().getEditorController()
.buildPaletteDropListener(placeHolder.getView(), placeHolder), true);
this.placeHolder = placeHolder;
this.editableView = placeHolder.getView();
logger.fine("Made FIBDropTarget for " + getFIBComponent());
}
public PlaceHolder getPlaceHolder() {
return placeHolder;
}
public boolean isPlaceHolder() {
return placeHolder != null;
}
public FIBComponent getFIBComponent() {
return editableView.getComponent();
}
public FIBEditorController getFIBEditorController() {
return editableView.getEditorController();
}
}
/**
* DGListener a listener that will start the drag. has access to top level's dsListener and dragSource
*
* @see java.awt.dnd.DragGestureListener
* @see java.awt.dnd.DragSource
* @see java.awt.datatransfer.StringSelection
*/
class MoveDGListener implements DragGestureListener {
/**
* Start the drag if the operation is ok. uses java.awt.datatransfer.StringSelection to transfer the label's data
*
* @param e
* the event object
*/
@Override
public void dragGestureRecognized(DragGestureEvent e) {
logger.fine("dragGestureRecognized");
// if the action is ok we go ahead
// otherwise we punt
if ((e.getDragAction() & dragAction) == 0) {
return;
// get the label's text and put it inside a Transferable
// Transferable transferable = new StringSelection(
// DragLabel.this.getText() );
}
ExistingElementDrag transferable = new ExistingElementDrag(new DraggedFIBComponent(view.getComponent()), e.getDragOrigin());
try {
// initial cursor, transferrable, dsource listener
e.startDrag(FIBEditorPalette.dropKO, transferable, dsListener);
logger.info("Starting existing element drag for " + view.getComponent());
// getDrawingView().captureDraggedNode(PaletteElementView.this, e);
} catch (Exception idoe) {
idoe.printStackTrace();
logger.warning("Unexpected exception " + idoe);
}
}
}
/**
* DSListener a listener that will track the state of the DnD operation
*
* @see java.awt.dnd.DragSourceListener
* @see java.awt.dnd.DragSource
* @see java.awt.datatransfer.StringSelection
*/
public class MoveDSListener implements DragSourceListener {
/**
* @param e
* the event
*/
@Override
public void dragDropEnd(DragSourceDropEvent e) {
System.out.println("dragDropEnd in MoveDSListener");
// getDrawingView().resetCapturedNode();
if (!e.getDropSuccess()) {
if (logger.isLoggable(Level.INFO)) {
logger.info("Dropping was not successful");
}
return;
}
/*
* the dropAction should be what the drop target specified in acceptDrop
*/
// this is the action selected by the drop target
if (e.getDropAction() == DnDConstants.ACTION_MOVE) {
System.out.println("Tiens, que se passe-t-il donc ?");
}
}
/**
* @param e
* the event
*/
@Override
public void dragEnter(DragSourceDragEvent e) {
DragSourceContext context = e.getDragSourceContext();
// System.out.println("dragEnter() with "+context+" component="+e.getSource());
// intersection of the users selected action, and the source and
// target actions
int myaction = e.getDropAction();
if ((myaction & dragAction) != 0) {
context.setCursor(DragSource.DefaultCopyDrop);
} else {
context.setCursor(DragSource.DefaultCopyNoDrop);
}
}
/**
* @param e
* the event
*/
@Override
public void dragOver(DragSourceDragEvent e) {
}
/**
* @param e
* the event
*/
@Override
public void dragExit(DragSourceEvent e) {
}
/**
* for example, press shift during drag to change to a link action
*
* @param e
* the event
*/
@Override
public void dropActionChanged(DragSourceDragEvent e) {
DragSourceContext context = e.getDragSourceContext();
context.setCursor(DragSource.DefaultCopyNoDrop);
}
}
}