/*
* (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.components.widget;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.FocusManager;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import org.openflexo.foundation.DataModification;
import org.openflexo.foundation.DocType;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.FlexoObservable;
import org.openflexo.foundation.FlexoObserver;
import org.openflexo.foundation.cg.DocTypeAdded;
import org.openflexo.foundation.cg.DocTypeRemoved;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.inspector.AbstractController;
import org.openflexo.inspector.InspectableModification;
import org.openflexo.inspector.InspectableObject;
import org.openflexo.inspector.model.PropertyModel;
import org.openflexo.inspector.widget.WysiwygLightWidget;
import org.openflexo.kvc.KVCObject;
import org.openflexo.logging.FlexoLogger;
import org.openflexo.view.controller.FlexoDocInspectorController;
import org.openflexo.wysiwyg.FlexoWysiwygLight;
import org.openflexo.wysiwyg.FlexoWysiwygUltraLight;
/**
* @author gpolet
*
*/
public class DescriptionInspectorWidget extends CustomInspectorWidget<FlexoModelObject> {
private static final Logger logger = FlexoLogger.getLogger(DescriptionInspectorWidget.class.getPackage().getName());
protected class DescriptionPanel extends JPanel implements FlexoObserver {
private JPanel top;
protected FlexoWysiwygLight wysiwyg;
private JComboBox docTypes;
protected JCheckBox checkBox;
private ActionListener cbListener;
/**
*
*/
public DescriptionPanel() {
super(new BorderLayout());
setOpaque(false);
checkBox = new JCheckBox();
checkBox.setOpaque(false);
boolean showViewSourceButtonInWysiwyg = getController().getConfiguration() != null
&& getController().getConfiguration().showViewSourceButtonInWysiwyg();
if (useUltraLightWysiwyg()) {
wysiwyg = new FlexoWysiwygUltraLight(showViewSourceButtonInWysiwyg) {
@Override
public void notifyTextChanged() {
updateModelFromWidget();
}
};
} else {
// Cannot set css as the modelObject is not set yet
// TODO -> load the CSS
wysiwyg = new FlexoWysiwygLight(null, null, showViewSourceButtonInWysiwyg) {
@Override
public void notifyTextChanged() {
updateModelFromWidget();
}
};
}
wysiwyg.addBorderAroundToolbar();
wysiwyg.setPreferredSize(new Dimension(250, 150));
checkBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateModelFromWidget();
updateWidgetFromModel();
}
});
docTypes = new JComboBox();
docTypes.setRenderer(new DefaultListCellRenderer());
docTypes.addActionListener(cbListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateWidgetFromModel();
}
});
top = new JPanel(new BorderLayout());
top.setOpaque(false);
top.add(checkBox, BorderLayout.WEST);
top.add(docTypes);
top.validate();
top.doLayout();
add(top, BorderLayout.NORTH);
add(wysiwyg, BorderLayout.CENTER);
validate();
doLayout();
}
public void updateModelFromWidget() {
if (isUpdatingWidget || isUpdatingModel || getObject() == null) {
return;
}
isUpdatingModel = true;
try {
if (checkBox.isSelected()) {
for (DocType dt : getObject().getProject().getDocTypes()) {
if (getObject().getSpecificDescriptions().get(dt.getName()) == null) {
getObject().setSpecificDescriptionsForKey("", dt.getName());
}
}
getObject().setSpecificDescriptionsForKey(wysiwyg.getBodyContent(), ((DocType) docTypes.getSelectedItem()).getName());
getObject().setHasSpecificDescriptions(true);
wysiwyg.setEnabled(true);
wysiwyg.setVisible(true);
// docTypes.setEditable(true);
docTypes.setEnabled(true);
} else {
wysiwyg.setEnabled(false);
wysiwyg.setVisible(false);
docTypes.setEnabled(false);
getObject().setHasSpecificDescriptions(false);
}
} finally {
isUpdatingModel = false;
}
}
public void updateWidgetFromModel() {
if (isUpdatingModel || getObject() == null || getObject().getProject() == null) {
return;
}
isUpdatingWidget = true;
try {
checkBox.setSelected(getObject().getHasSpecificDescriptions());
updateDocTypes();
if (checkBox.isSelected()) {
wysiwyg.setEnabled(true);
wysiwyg.setVisible(true);
// docTypes.setEditable(true);
docTypes.setEnabled(true);
DocType dt = (DocType) docTypes.getSelectedItem();
wysiwyg.setActivated(false);
try {
if (getObject().getSpecificDescriptions().get(dt.getName()) != null) {
wysiwyg.setContent(getObject().getSpecificDescriptions().get(dt.getName()));
} else {
boolean b = isUpdatingModel;
try {
isUpdatingModel = true;
getObject().setSpecificDescriptionsForKey("", dt.getName());
} finally {
isUpdatingModel = b;
}
wysiwyg.setContent("");
}
} finally {
wysiwyg.setActivated(true);
}
} else {
wysiwyg.setEnabled(false);
wysiwyg.setVisible(false);
wysiwyg.setContent("");
docTypes.setEnabled(false);
}
updateSplitPane();
revalidate();
doLayout();
} finally {
isUpdatingWidget = false;
}
}
private int lastDividerLocation = -1;
private boolean bothShowing = false;
private void updateSplitPane() {
if (checkBox.isSelected()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (!bothShowing) {
splitPane.setResizeWeight(0.5);// Extra space is given equally to top and bottom component
if (lastDividerLocation == -1) {
splitPane.setDividerLocation(0.5);
} else {
splitPane.setDividerLocation(lastDividerLocation);
}
bothShowing = true;
}
}
});
} else {
if (bothShowing) {
lastDividerLocation = splitPane.getDividerLocation();
splitPane.setResizeWeight(1.0);// Extra space is given to the top component
bothShowing = false;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
snapBottomPanelToMinimalSize();
}
});
}
}
private void snapBottomPanelToMinimalSize() {
if (splitPane.getHeight() > 0) {
splitPane.setDividerLocation(splitPane.getHeight() - DescriptionPanel.this.getPreferredSize().height
- splitPane.getDividerSize());
}
}
private FlexoProject observedProject;
private boolean updatingDocTypes = false;
/**
*
*/
private void updateDocTypes() {
if (updatingDocTypes) {
return;
}
updatingDocTypes = true;
try {
if (observedProject != null) {
observedProject.deleteObserver(this);
observedProject = null;
}
if (getObject() != null) {
DocType dt = (DocType) docTypes.getSelectedItem();
docTypes.removeActionListener(cbListener);
docTypes.setSelectedItem(null);
docTypes.setModel(new DefaultComboBoxModel(new Vector<DocType>(getObject().getProject().getDocTypes())));
if (dt != null && getObject().getProject().getDocTypes().indexOf(dt) > -1) {
docTypes.setSelectedItem(dt);
} else {
docTypes.setSelectedIndex(0);
}
docTypes.addActionListener(cbListener);
updateWidgetFromModel();
getObject().getProject().addObserver(this);
observedProject = getObject().getProject();
}
} finally {
updatingDocTypes = false;
}
}
@Override
public void update(FlexoObservable observable, DataModification dataModification) {
if (dataModification instanceof DocTypeRemoved || dataModification instanceof DocTypeAdded) {
updateDocTypes();
}
}
}
private DescriptionPanel panel;
protected boolean isUpdatingModel = false;
protected boolean isUpdatingWidget = false;
/**
*
*
*/
public FlexoModelObject getObject() {
KVCObject o = (KVCObject) super.getModel();
if (getPropertyModel().name.indexOf('.') > -1) {
String[] s = getPropertyModel().name.split(Pattern.quote("."));
for (int i = 0; i < s.length - 1; i++) {
String string = s[i];
Object returned = o.objectForKey(string);
if (!(returned instanceof KVCObject)) {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Someting is wrong with an inspector. Inspected property path contains object that are not KVCObject "
+ getPropertyModel().name);
}
return null;
} else {
o = (KVCObject) returned;
}
}
}
if (o instanceof FlexoModelObject) {
return (FlexoModelObject) o;
} else if (o != null && logger.isLoggable(Level.SEVERE)) {
logger.severe("Object at the end of property path is not a FlexoModelObject: " + getPropertyModel().name + " this is a " + o
+ " of " + o.getClass().getSimpleName());
}
return null;
}
/**
* Overrides setModel
*
* @see org.openflexo.components.widget.CustomInspectorWidget#setModel(org.openflexo.inspector.InspectableObject)
*/
@Override
public void setModel(InspectableObject value) {
if (FocusManager.getCurrentManager().getFocusOwner() != null && getDynamicComponent() != null
&& SwingUtilities.isDescendingFrom(FocusManager.getCurrentManager().getFocusOwner(), getDynamicComponent())) {
// If we have the focus and we switch the observed object, we first set the last values on the previous object (so that data
// does not get lost)
updateModelFromWidget();
}
super.setModel(value);
if (value != null) {
if (value instanceof FlexoModelObject && ((FlexoModelObject) value).getProject() != null) {
defaultWidget.getDynamicComponent().addSupportForInsertedObjects(
((FlexoModelObject) value).getProject().getImportedImagesDir());
panel.wysiwyg.addSupportForInsertedObjects(((FlexoModelObject) value).getProject().getImportedImagesDir());
}
updateWidgetFromModel();
}
}
@Override
public synchronized void switchObserved(InspectableObject inspectable) {
super.switchObserved(inspectable);
defaultWidget.switchObserved(inspectable);
}
protected JSplitPane splitPane;
private WysiwygLightWidget defaultWidget;
/**
* @param model
*/
public DescriptionInspectorWidget(PropertyModel model, AbstractController controller) {
super(model, controller);
PropertyModel descModel = new PropertyModel();
descModel.parameters.putAll(model.parameters);
descModel._tabModelName = model._tabModelName;
descModel.setTabModel(model.getTabModel());
descModel.label = "description";
descModel.name = "description";
descModel.setValueForParameter("readOnly", "!isDocEditable");
descModel.setValueForParameter("widgetLayout", "1COL");
descModel.setValueForParameter("align", "CENTER");
defaultWidget = new WysiwygLightWidget(descModel, controller, useUltraLightWysiwyg());
panel = new DescriptionPanel();
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, defaultWidget.getDynamicComponent(), panel);
/*splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
System.err.println(splitPane.getResizeWeight()+" "+evt.getOldValue()+" --> "+evt.getNewValue());
Thread.dumpStack();
}
});*/
}
@Override
public boolean widgetHasFocus() {
return super.widgetHasFocus() || panel.wysiwyg.hasFocus() || defaultWidget.hasFocus();
}
public boolean isInMainFrame() {
return getController() instanceof FlexoDocInspectorController;
}
/**
* Overrides getDefaultType
*
* @see org.openflexo.inspector.widget.DenaliWidget#getDefaultType()
*/
@Override
public Class getDefaultType() {
return FlexoModelObject.class;
}
/**
* Overrides getDynamicComponent
*
* @see org.openflexo.inspector.widget.DenaliWidget#getDynamicComponent()
*/
@Override
public JComponent getDynamicComponent() {
return splitPane;
}
/**
* Overrides updateModelFromWidget
*
* @see org.openflexo.inspector.widget.DenaliWidget#updateModelFromWidget()
*/
@Override
public void updateModelFromWidget() {
if (isUpdatingWidget) {
return;
}
panel.updateModelFromWidget();
super.updateModelFromWidget();
}
/**
* Overrides updateWidgetFromModel
*
* @see org.openflexo.inspector.widget.DenaliWidget#updateWidgetFromModel()
*/
@Override
public void updateWidgetFromModel() {
if (isUpdatingModel) {
return;
}
panel.updateWidgetFromModel();
}
@Override
public boolean defaultShouldExpandVertically() {
/*if (getObject()!=null)
return getObject().getHasSpecificDescriptions();*/
return true;
}
@Override
public void update(final InspectableObject inspectable, final InspectableModification modification) {
if (modification != null && modification.propertyName() != null && modification.propertyName().equals("hasSpecificDescriptions")) {
updateWidgetFromModel();
return;
}
super.update(inspectable, modification);
}
protected boolean useUltraLightWysiwyg() {
return getPropertyModel().hasValueForParameter("useUltraLightWysiwyg")
&& getPropertyModel().getBooleanValueForParameter("useUltraLightWysiwyg");
}
}