/*
* (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.tabularbrowser;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import org.openflexo.components.browser.BrowserElement;
import org.openflexo.components.browser.ProjectBrowser;
import org.openflexo.foundation.DataModification;
import org.openflexo.foundation.FlexoEditor;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.FlexoObservable;
import org.openflexo.foundation.GraphicalFlexoObserver;
import org.openflexo.inspector.InspectableObject;
import org.openflexo.selection.ContextualMenuManager;
import org.openflexo.selection.DefaultContextualMenuManager;
import org.openflexo.selection.SelectionManager;
import org.openflexo.selection.SelectionSynchronizedComponent;
import org.openflexo.view.controller.FlexoController;
/**
* Tabular and browsable view representing an TabularBrowserModel
*
* @author sguerin
*
*/
public class TabularBrowserView extends JPanel implements TableModelListener, ListSelectionListener, GraphicalFlexoObserver,
SelectionSynchronizedComponent {
protected static final Logger logger = Logger.getLogger(TabularBrowserView.class.getPackage().getName());
protected FlexoController _controller;
protected JTreeTable _treeTable;
protected TabularBrowserModel _model;
private JScrollPane scrollPane;
private TabularBrowserFooter _footer;
private boolean _synchronizeWithSelectionManager = false;
public TabularBrowserView(FlexoController controller, TabularBrowserModel model, int visibleRowCount) {
this(controller, model);
setVisibleRowCount(visibleRowCount);
}
public TabularBrowserView(FlexoController controller, TabularBrowserModel model) {
super();
_model = model;
_controller = controller;
_treeTable = new JTreeTable(model);
// _treeTable.setPreferredSize(new Dimension(model.getTotalPreferredWidth(),100));
if (model.getRowHeight() > 0) {
_treeTable.setRowHeight(model.getRowHeight());
}
_treeTable.setShowVerticalLines(true);
_treeTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
getSelectionModel().addListSelectionListener(this);
scrollPane = new JScrollPane(_treeTable);
setLayout(new BorderLayout());
// _treeTable.getTableHeader().setPreferredSize(new Dimension(model.getTotalPreferredWidth(),100));
add(_treeTable.getTableHeader(), BorderLayout.NORTH);
add(scrollPane, BorderLayout.CENTER);
// add(new JPanel(),BorderLayout.SOUTH);
if (getBrowser().handlesControlPanel()) {
_footer = new TabularBrowserFooter(this);
add(_footer, BorderLayout.SOUTH);
}
_treeTable.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (getContextualMenuManager() != null) {
getContextualMenuManager().processMousePressed(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (getContextualMenuManager() != null) {
getContextualMenuManager().processMouseReleased(e);
}
}
});
_treeTable.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
if (getContextualMenuManager() != null) {
getContextualMenuManager().processMouseMoved(e);
}
}
});
validate();
}
public void delete() {
if (getSelectionModel() != null) {
getSelectionModel().removeListSelectionListener(this);
}
if (_model != null) {
_model.delete();
_model = null;
}
}
public FlexoController getController() {
return _controller;
}
public FlexoEditor getEditor() {
if (getController() != null) {
return getController().getEditor();
}
return null;
}
/**
* !!!!!!!!!! IMPORTANT !!!!!!!!
*
* This hack is a workaround to prevent arrival on a NPE while such a component is added to the container hierarchy in a context i still
* don't understand, but certainly due to adding of JTextArea when using TextColumn. Seems that this is not so important, but....
*
* Overrides @see java.awt.Component#addNotify()
*
* @see java.awt.Component#addNotify()
*/
@Override
public void addNotify() {
logger.fine("BEGIN addNotify() NPE catcher");
try {
super.addNotify();
} catch (NullPointerException e) {
logger.fine("NPE caught!");
for (int i = 0; i < getComponentCount(); i++) {
logger.fine("addNotify() for " + getComponent(i));
getComponent(i).addNotify();
}
}
logger.fine("END addNotify() NPE catcher");
}
public ProjectBrowser getBrowser() {
return getTreeTable().getProjectBrowser();
}
public BrowserElement getSelectedElement() {
return (BrowserElement) getTreeTable().getTree().getLastSelectedPathComponent();
}
public FlexoModelObject getSelectedObject() {
if (getSelectedElement() != null) {
return getSelectedElement().getObject();
}
return null;
}
public JTreeTable getTreeTable() {
return _treeTable;
}
private DefaultContextualMenuManager defaultContextualMenuManager;
protected ContextualMenuManager getContextualMenuManager() {
if (getSelectionManager() != null && _synchronizeWithSelectionManager) {
return getSelectionManager().getContextualMenuManager();
}
if (defaultContextualMenuManager == null) {
defaultContextualMenuManager = new DefaultContextualMenuManager(getController());
}
return defaultContextualMenuManager;
}
public ListSelectionModel getSelectionModel() {
return _treeTable.getTreeTableSelectionModel();
}
public TabularBrowserModel getModel() {
return _model;
}
public void focusOn(FlexoModelObject object) {
setSelectedObject(object);
}
public void setVisibleRowCount(int rows) {
int height = 0;
for (int row = 0; row < rows; row++) {
height += _treeTable.getRowHeight(row);
}
_treeTable.setPreferredScrollableViewportSize(new Dimension(_treeTable.getPreferredScrollableViewportSize().width, height));
}
public boolean isSelected(FlexoModelObject object) {
return _treeTable.isSelected(object);
}
public Vector<FlexoModelObject> getObjects() {
return getSelectedObjects();
}
public Vector<FlexoModelObject> getSelectedObjects() {
return _treeTable.getSelectedObjects();
}
private boolean _isSelected = false;
public boolean isSelected() {
return _isSelected;
}
public void setIsSelected(boolean b) {
_isSelected = b;
}
public FlexoModelObject getRootObject() {
return _model.getRootObject();
}
/**
* Implements
*
* @see org.openflexo.view.InspectableObjectView#getInspectedObject()
* @see org.openflexo.view.InspectableObjectView#getInspectedObject()
*/
public InspectableObject getInspectedObject() {
if (getRootObject() instanceof InspectableObject) {
return (InspectableObject) getRootObject();
}
return null;
}
/**
* Implements
*
* @see org.openflexo.view.MultipleInspectableObjectView#getInspectedObjects()
* @see org.openflexo.view.MultipleInspectableObjectView#getInspectedObjects()
*/
public Vector getInspectedObjects() {
return getObjects();
}
/**
* Overrides
*
* @see org.openflexo.foundation.FlexoObserver#update(org.openflexo.foundation.FlexoObservable,
* org.openflexo.foundation.DataModification)
* @see org.openflexo.foundation.FlexoObserver#update(org.openflexo.foundation.FlexoObservable,
* org.openflexo.foundation.DataModification)
*/
@Override
public void update(FlexoObservable o, DataModification dataModification) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("update received in TabularBrowserView for " + o + " dataModification=" + dataModification);
}
}
/**
* Overrides
*
* @see javax.swing.event.TableModelListener#tableChanged(javax.swing.event.TableModelEvent)
* @see javax.swing.event.TableModelListener#tableChanged(javax.swing.event.TableModelEvent)
*/
@Override
public void tableChanged(TableModelEvent e) {
}
public FlexoModelObject getObject() {
return getRootObject();
}
public boolean isSelected(Vector<? extends FlexoModelObject> objectList) {
return getSelectedObjects().containsAll(objectList);
}
public boolean isSynchronizedWithSelectionManager() {
return _synchronizeWithSelectionManager;
}
public void setSynchronizeWithSelectionManager(boolean synchronizeWithSelectionManager) {
_synchronizeWithSelectionManager = synchronizeWithSelectionManager;
if (synchronizeWithSelectionManager) {
if (getSelectionManager() != null) {
_treeTable.getTreeTableModel().setSelectionManager(getSelectionManager());
getSelectionManager().addToSelectionListeners(this);
}
updateSelection();
}
}
@Override
public SelectionManager getSelectionManager() {
if (_controller != null) {
return _controller.getSelectionManager();
} else {
return null;
}
}
@Override
public Vector<FlexoModelObject> getSelection() {
if (getSelectionManager() != null) {
return getSelectionManager().getSelection();
}
return null;
}
@Override
public void resetSelection() {
if (getSelectionManager() != null) {
getSelectionManager().resetSelection();
} else {
fireResetSelection();
}
}
@Override
public void addToSelected(FlexoModelObject object) {
if (mayRepresents(object)) {
if (getSelectionManager() != null) {
getSelectionManager().addToSelected(object);
} else {
fireObjectSelected(object);
}
}
}
@Override
public void removeFromSelected(FlexoModelObject object) {
if (mayRepresents(object)) {
if (getSelectionManager() != null) {
getSelectionManager().removeFromSelected(object);
} else {
fireObjectDeselected(object);
}
}
}
@Override
public void addToSelected(Vector<? extends FlexoModelObject> objects) {
if (getSelectionManager() != null) {
getSelectionManager().addToSelected(objects);
} else {
fireBeginMultipleSelection();
for (FlexoModelObject next : objects) {
fireObjectSelected(next);
}
fireEndMultipleSelection();
}
}
@Override
public void removeFromSelected(Vector<? extends FlexoModelObject> objects) {
if (getSelectionManager() != null) {
getSelectionManager().removeFromSelected(objects);
} else {
fireBeginMultipleSelection();
for (FlexoModelObject next : objects) {
fireObjectDeselected(next);
}
fireEndMultipleSelection();
}
}
@Override
public void setSelectedObjects(Vector<? extends FlexoModelObject> objects) {
if (getSelectionManager() != null) {
getSelectionManager().setSelectedObjects(objects);
} else {
resetSelection();
addToSelected(objects);
}
}
public void setSelectedObject(FlexoModelObject object) {
if (getSelectionManager() != null) {
getSelectionManager().setSelectedObject(object);
} else {
resetSelection();
addToSelected(object);
}
}
@Override
public boolean mayRepresents(FlexoModelObject anObject) {
return _treeTable.mayRepresents(anObject);
}
@Override
public FlexoModelObject getFocusedObject() {
if (getSelectionManager() != null) {
return getSelectionManager().getFocusedObject();
}
return null;
}
@Override
public void fireObjectSelected(FlexoModelObject object) {
if (mayRepresents(object)) {
getSelectionModel().removeListSelectionListener(this);
_treeTable.fireObjectSelected(object);
getSelectionModel().addListSelectionListener(this);
} else {
fireResetSelection();
}
if (getBrowser().handlesControlPanel()) {
_footer.handleSelectionChanged();
}
}
@Override
public void fireObjectDeselected(FlexoModelObject object) {
if (mayRepresents(object)) {
getSelectionModel().removeListSelectionListener(this);
_treeTable.fireObjectDeselected(object);
getSelectionModel().addListSelectionListener(this);
}
if (getBrowser().handlesControlPanel()) {
_footer.handleSelectionChanged();
}
}
@Override
public void fireResetSelection() {
getSelectionModel().removeListSelectionListener(this);
_treeTable.fireResetSelection();
getSelectionModel().addListSelectionListener(this);
if (getBrowser().handlesControlPanel()) {
_footer.handleSelectionCleared();
}
}
@Override
public void fireBeginMultipleSelection() {
_treeTable.fireBeginMultipleSelection();
}
@Override
public void fireEndMultipleSelection() {
_treeTable.fireEndMultipleSelection();
}
/**
* Update selection
*/
public void updateSelection() {
if (getSelectionManager() != null) {
getSelectionManager().fireUpdateSelection(this);
}
if (getBrowser().handlesControlPanel()) {
_footer.handleSelectionChanged();
}
}
@Override
public void valueChanged(ListSelectionEvent e) {
// Ignore extra messages.
if (e.getValueIsAdjusting()) {
return;
}
if (getSelectionManager() != null && _synchronizeWithSelectionManager) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("valueChanged() ListSelectionEvent=" + e + " ListSelectionModel=" + getSelectionModel().toString());
}
/* At least one of this item has change */
int beginIndex = e.getFirstIndex();
int endIndex = e.getLastIndex();
Vector<FlexoModelObject> toBeRemovedFromSelection = new Vector<FlexoModelObject>();
Vector<FlexoModelObject> toBeAddedToSelection = new Vector<FlexoModelObject>();
for (int i = beginIndex; i <= endIndex; i++) {
FlexoModelObject object = _treeTable.getObjectAt(i);
if (getSelectionModel().isSelectedIndex(i) != getSelectionManager().selectionContains(object)) {
// logger.info("Selection status for object "+object+" at index "+i+" has changed");
if (getSelectionModel().isSelectedIndex(i)) {
// Change for addition
toBeAddedToSelection.add(object);
} else {
// Change for removing
toBeRemovedFromSelection.add(object);
}
}
}
for (FlexoModelObject next : toBeAddedToSelection) {
getSelectionManager().addToSelected(next);
}
for (FlexoModelObject next : toBeRemovedFromSelection) {
getSelectionManager().removeFromSelected(next);
}
}
if (getBrowser().handlesControlPanel()) {
_footer.handleSelectionChanged();
}
}
}