Package org.freeplane.view.swing.map.attribute

Source Code of org.freeplane.view.swing.map.attribute.AttributeTable

/*
*  Freeplane - mind map editor
*  Copyright (C) 2008 Dimitry Polivaev
*
*  This file author is Dimitry Polivaev
*
*  This program 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 2 of the License, or
*  (at your option) any later version.
*
*  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.freeplane.view.swing.map.attribute;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.KeyboardFocusManager;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.URI;
import java.util.EventObject;

import javax.swing.AbstractCellEditor;
import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.Icon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import org.freeplane.core.ui.components.TypedListCellRenderer;
import org.freeplane.core.ui.components.UITools;
import org.freeplane.features.attribute.AttributeRegistry;
import org.freeplane.features.attribute.AttributeTableLayoutModel;
import org.freeplane.features.attribute.ColumnWidthChangeEvent;
import org.freeplane.features.attribute.IAttributeTableModel;
import org.freeplane.features.attribute.IColumnWidthChangeListener;
import org.freeplane.features.attribute.NodeAttributeTableModel;
import org.freeplane.features.format.IFormattedObject;
import org.freeplane.features.link.LinkController;
import org.freeplane.features.map.MapController;
import org.freeplane.features.map.NodeModel;
import org.freeplane.features.mode.Controller;
import org.freeplane.features.mode.ModeController;
import org.freeplane.features.nodestyle.NodeStyleController;
import org.freeplane.features.text.TextController;
import org.freeplane.features.text.mindmapmode.EditNodeBase;
import org.freeplane.features.text.mindmapmode.EditNodeBase.EditedComponent;
import org.freeplane.features.text.mindmapmode.EditNodeBase.IEditControl;
import org.freeplane.features.text.mindmapmode.MTextController;
import org.freeplane.features.ui.ViewController;
import org.freeplane.features.url.UrlManager;
import org.freeplane.view.swing.map.MapView;
import org.freeplane.view.swing.map.NodeView;


/**
* @author Dimitry Polivaev
*/
class AttributeTable extends JTable implements IColumnWidthChangeListener {
  private static final String EDITING_STOPPED = AttributeTable.class.getName() + ".editingStopped";
  private static int CLICK_COUNT_TO_START = 2;

  private static final class TableHeaderRendererImpl implements TableCellRenderer {
    final private TableCellRenderer delegate;
    TableHeaderRendererImpl(TableCellRenderer renderer){
      this.delegate = renderer;
    }
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
        int row, int column) {
      final Component c = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
      final int height = (int) (((AttributeTable)table).getZoom() * 6);
      final Dimension preferredSize = new Dimension(1, height);
      c.setPreferredSize(preferredSize);
      return c;
    }
  }
  @SuppressWarnings("serial")
  private static final class TableHeader extends JTableHeader {
    private TableHeader(TableColumnModel cm) {
      super(cm);
    }
    @Override
    protected TableCellRenderer createDefaultRenderer() {
      return new TableHeaderRendererImpl(super.createDefaultRenderer());
    }
  }

  static private class HeaderMouseListener extends MouseAdapter {
    @Override
    public void mouseReleased(final MouseEvent e) {
      final JTableHeader header = (JTableHeader) e.getSource();
      final AttributeTable table = (AttributeTable) header.getTable();
      final float zoom = table.attributeView.getMapView().getZoom();
      final AttributeTableModelDecoratorAdapter model = (AttributeTableModelDecoratorAdapter) table
      .getModel();
      for (int col = 0; col < table.getColumnCount(); col++) {
        final int modelColumnWidth = model.getColumnWidth(col);
        final int currentColumnWidth = (int) (table.getColumnModel().getColumn(col).getWidth() / zoom);
        if (modelColumnWidth != currentColumnWidth) {
          model.setColumnWidth(col, currentColumnWidth);
        }
      }
    }
  }

  static private class MyFocusListener implements FocusListener {
    private AttributeTable focusedTable;

    /*
     * (non-Javadoc)
     * @see
     * java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
     */
    public void focusGained(final FocusEvent event) {
      final Component source = (Component) event.getSource();
      event.getOppositeComponent();
      if (source instanceof AttributeTable) {
        focusedTable = (AttributeTable) source;
      }
      else {
        focusedTable = (AttributeTable) SwingUtilities.getAncestorOfClass(AttributeTable.class, source);
      }
      if(focusedTable != null){
          focusedTable.setSelectedCellTypeInfo();
      }
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          if (focusedTable != null) {
            final Component newNodeViewInFocus = SwingUtilities.getAncestorOfClass(NodeView.class,
                focusedTable);
            if (newNodeViewInFocus != null) {
              final NodeView viewer = (NodeView) newNodeViewInFocus;
              if (viewer != viewer.getMap().getSelected()) {
                viewer.getMap().selectAsTheOnlyOneSelected(viewer, false);
              }
            }
          }
        }
      });
    }

    /*
     * (non-Javadoc)
     * @see
     * java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
     */
    public void focusLost(final FocusEvent event) {
      if (event.isTemporary()) {
        return;
      }
      final Component oppositeComponent = event.getOppositeComponent();
      if (oppositeComponent == null) {
        return;
      }
      final Component newTable;
      if (oppositeComponent instanceof AttributeTable) {
        newTable = oppositeComponent;
      }
      else {
        newTable = SwingUtilities.getAncestorOfClass(AttributeTable.class, oppositeComponent);
      }
      if (focusedTable == null) {
        return;
      }
      if (focusedTable != newTable) {
        if (focusedTable.isEditing()) {
          focusedTable.clearSelection();
          focusedTable.getCellEditor().stopCellEditing();
        }
        if (!focusedTable.attributeView.isPopupShown()) {
          final AttributeView attributeView = focusedTable.getAttributeView();
          final String currentAttributeViewType = AttributeRegistry.getRegistry(
              attributeView.getNode().getMap()).getAttributeViewType();
          if (attributeView.getViewType() != currentAttributeViewType) {
            attributeView.stateChanged(null);
          }
        }
        focusedTable = null;
        return;
      }
    }
  }

  static private MouseListener componentListener = new HeaderMouseListener();
  static private ComboBoxModel defaultComboBoxModel = null;
  static private AttributeTableCellRenderer dtcr = new AttributeTableCellRenderer();
  private static final int EXTRA_HEIGHT = 4;
  static private MyFocusListener focusListener = new MyFocusListener();
  static private CursorUpdater cursorUpdater = new CursorUpdater();
  private static final int MAX_HEIGTH = 300;
  private static final int MAX_WIDTH = 300;
  private static final long serialVersionUID = 1L;
  private static final float TABLE_ROW_HEIGHT = 4;

  static ComboBoxModel getDefaultComboBoxModel() {
    if (AttributeTable.defaultComboBoxModel == null) {
      AttributeTable.defaultComboBoxModel = new DefaultComboBoxModel();
    }
    return AttributeTable.defaultComboBoxModel;
  }

  final private AttributeView attributeView;
  private int highRowIndex = 0;
  private static DefaultCellEditor dce;

  AttributeTable(final AttributeView attributeView) {
    super();
    this.attributeView = attributeView;
    addFocusListener(AttributeTable.focusListener);
    addMouseListener(AttributeTable.cursorUpdater);
    addMouseMotionListener(AttributeTable.cursorUpdater);
    if (attributeView.getMapView().getModeController().canEdit()) {
      tableHeader.addMouseListener(AttributeTable.componentListener);
    }
    else {
      tableHeader.setResizingAllowed(false);
    }
    setModel(attributeView.getCurrentAttributeTableModel());
    updateFontSize(this, 1F);
    updateColumnWidths();
    setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    getTableHeader().setReorderingAllowed(false);
    setRowSelectionAllowed(false);
    putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
    updateRowHeights();
    updateColumnWidths();
  }

  @Override
  protected JTableHeader createDefaultTableHeader() {
    return new TableHeader(columnModel);
  }

  private void changeSelectedRowHeight(final int rowIndex) {
    if (highRowIndex != rowIndex) {
      if (highRowIndex < getRowCount()) {
        final int h = getRowHeight(highRowIndex);
        setRowHeight(highRowIndex, h - AttributeTable.EXTRA_HEIGHT);
      }
      final int h = getRowHeight(rowIndex);
      setRowHeight(rowIndex, h + AttributeTable.EXTRA_HEIGHT);
      highRowIndex = rowIndex;
      assert highRowIndex >= 0;
    }
  }

  @Override
  public void changeSelection(int rowIndex, int columnIndex, final boolean toggle, final boolean extend) {
    final int rowCount = getRowCount();
    if (rowCount == 0) {
      return;
    }
    if (rowIndex >= rowCount) {
      rowIndex = 0;
      columnIndex = 0;
    }
    changeSelectedRowHeight(rowIndex);
    super.changeSelection(rowIndex, columnIndex, toggle, extend);
  }

  public void columnWidthChanged(final ColumnWidthChangeEvent event) {
    final float zoom = getZoom();
    final int col = event.getColumnNumber();
    final AttributeTableLayoutModel layoutModel = (AttributeTableLayoutModel) event.getSource();
    final int width = layoutModel.getColumnWidth(col);
    getColumnModel().getColumn(col).setPreferredWidth((int) (width * zoom));
    final MapView map = attributeView.getMapView();
    final NodeModel node = attributeView.getNode();
    map.getModeController().getMapController().nodeChanged(node);
  }

  /**
   * @return Returns the currentModel.
   */
  public AttributeTableModelDecoratorAdapter getAttributeTableModel() {
    return (AttributeTableModelDecoratorAdapter) getModel();
  }

  public AttributeView getAttributeView() {
    return attributeView;
  }
 
 

  @Override
    public boolean editCellAt(int row, int column, EventObject e) {
    if(isEditing() && getCellEditor() instanceof DialogTableCellEditor){
      return false;
    }
    if(column == 1 && e instanceof MouseEvent){
      final MouseEvent me = (MouseEvent) e;
      final Object value = getValueAt(row, column);
      if(value instanceof URI){
        final URI uri = (URI) value;
        final Icon linkIcon = getLinkIcon(uri);
        final int xmax = linkIcon != null ? linkIcon.getIconWidth() : 0;
        final int x = me.getX() - getColumnModel().getColumn(0).getWidth();
        if(x < xmax){
          LinkController.getController().loadURL(attributeView.getNode(), new ActionEvent(me.getSource(), me.getID(), null), uri);
          return false;
        }
             }
    }
    putClientProperty("AttributeTable.EditEvent", e);
    try{
      if(super.editCellAt(row, column, e)){
        final TableCellEditor cellEditor = getCellEditor();
        if(isEditing() && cellEditor instanceof DialogTableCellEditor){
          ((JComponent)editorComp).paintImmediately(0, 0, editorComp.getWidth(), editorComp.getHeight());
          ((DialogTableCellEditor)cellEditor).startEditing();
          return false;
        }
        return true;
      }
      return false;
    }
    finally{
      putClientProperty("AttributeTable.EditEvent", null);
    }
    }

  Icon getLinkIcon(final URI uri) {
    NodeModel nodeModel = ((IAttributeTableModel)getModel()).getNode();
      final Icon linkIcon = LinkController.getLinkIcon(uri, nodeModel);
      return linkIcon;
    }
 
  @SuppressWarnings("serial")
    private class DialogTableCellEditor extends AbstractCellEditor implements TableCellEditor{
   
    final private IEditControl editControl;
    private Object value;
    private EditNodeBase editBase;
    public DialogTableCellEditor() {
      super();
      editControl = new IEditControl() {
        public void split(String newText, int position) {
        }
       
        public void ok(String newText) {
          value = newText;
          stopCellEditing();
        }
       
        public void cancel() {
          stopCellEditing();
        }

        public boolean canSplit() {
                  return false;
                }

        public EditedComponent getEditType() {
                  return EditedComponent.TEXT;
                }
      };
        }

    public IEditControl getEditControl() {
          return editControl;
        }

    public void setEditBase(EditNodeBase editBase) {
          this.editBase = editBase;
        }
   
    public Object getCellEditorValue() {
          return value;
        }

    public void startEditing(){
      if(editBase == null){
        return;
      }
      final JFrame frame = (JFrame) JOptionPane.getFrameForComponent(AttributeTable.this);
      editBase.show(frame);
    }

    public boolean isCellEditable(EventObject anEvent) {
      if (anEvent instanceof MouseEvent) {
        return ((MouseEvent)anEvent).getClickCount() >= CLICK_COUNT_TO_START;
      }
      return true;
    }
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
          return new AttributeTableCellRenderer().getTableCellRendererComponent(table, value, true, true, row, column);
        }
  };

  @Override
  public TableCellEditor getCellEditor(final int row, final int col) {
    return getCellEditor(row, col, (EventObject) getClientProperty("AttributeTable.EditEvent"));
  }

  @SuppressWarnings("serial")
    public TableCellEditor getCellEditor(final int row, final int col, EventObject e) {
    if (dce != null) {
      dce.stopCellEditing();
    }
    if(col == 1){
      final MTextController textController = (MTextController) TextController.getController();
      if(e instanceof KeyEvent){
        final KeyEvent kev = (KeyEvent) e;
        textController.getEventQueue().setFirstEvent(kev);
      }
      final IAttributeTableModel model = (IAttributeTableModel) getModel();
      final String text = getValueForEdit(row, col);
      final DialogTableCellEditor dialogTableCellEditor = new DialogTableCellEditor();
      EditNodeBase base = textController.getEditNodeBase(model.getNode(), text, dialogTableCellEditor.getEditControl(), false);
      if(base != null){
        dialogTableCellEditor.setEditBase(base);
        return dialogTableCellEditor;
      }
    }
    final JComboBox comboBox;
    if (dce == null) {
      comboBox = new JComboBox();
      comboBox.addFocusListener(AttributeTable.focusListener);
      comboBox.getEditor().getEditorComponent().addFocusListener(AttributeTable.focusListener);
      comboBox.setRenderer(new TypedListCellRenderer());
      dce = new DefaultCellEditor(comboBox) {
            public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int col) {
                return super.getTableCellEditorComponent(table, ((AttributeTable)table).getValueForEdit(row, col), isSelected, row, col);
            }
      };
      dce.setClickCountToStart(CLICK_COUNT_TO_START);
    }
    return dce;
  }

    private String getValueForEdit(final int row, final int col) {
        final Object value = getValueAt(row, col);
        return (value instanceof IFormattedObject ? ((IFormattedObject) value).getObject() : value).toString();
    }


  @Override
  public TableCellRenderer getCellRenderer(final int row, final int column) {
    return AttributeTable.dtcr;
  }

  private float getFontSize() {
    return UITools.FONT_SCALE_FACTOR * AttributeRegistry.getRegistry(attributeView.getNode().getMap()).getFontSize();
  }

  @Override
  public Dimension getPreferredScrollableViewportSize() {
    if (!isValid()) {
      validate();
    }
    final Dimension dimension = super.getPreferredSize();
    NodeView nodeView = (NodeView) SwingUtilities.getAncestorOfClass(NodeView.class, this);
    if(nodeView != null){
      final MapView map = nodeView.getMap();
      final ModeController modeController = map.getModeController();
      final NodeStyleController nsc = NodeStyleController.getController(modeController);
      dimension.width = Math.min(map.getZoomed(nsc.getMaxWidth(nodeView.getModel())), dimension.width);
      dimension.height = Math.min(map.getZoomed(AttributeTable.MAX_HEIGTH) - getTableHeaderHeight(), dimension.height);
    }
    else{
      dimension.width = Math.min(MAX_WIDTH, dimension.width);
      dimension.height = Math.min(MAX_HEIGTH, dimension.height);
    }
    return dimension;
  }

  int getTableHeaderHeight() {
    final JTableHeader tableHeader = getTableHeader();
    return tableHeader != null ? tableHeader.getPreferredSize().height : 0;
  }

  float getZoom() {
        final MapView mapView = attributeView.getMapView();
      if(SwingUtilities.isDescendingFrom(this, mapView)) {
            return mapView.getZoom();
        }
      return 1f;
  }

  /**
   */
  public void insertRow(final int row) {
    if (getModel() instanceof ExtendedAttributeTableModelDecorator) {
      final ExtendedAttributeTableModelDecorator model = (ExtendedAttributeTableModelDecorator) getModel();
      if (isEditing() && getCellEditor() != null && !getCellEditor().stopCellEditing()) {
        return;
      }
      model.insertRow(row);
      changeSelection(row, 0, false, false);
      if (editCellAt(row, 0)) {
        getEditorComponent().requestFocusInWindow();
      }
    }
  }

  @Override
  public boolean isVisible() {
    return super.isVisible() && attributeView.areAttributesVisible();
  }

  /**
   */
  public void moveRowDown(final int row) {
    if (getModel() instanceof ExtendedAttributeTableModelDecorator && row < getRowCount() - 1) {
      final ExtendedAttributeTableModelDecorator model = (ExtendedAttributeTableModelDecorator) getModel();
      model.moveRowDown(row);
      changeSelection(row + 1, getSelectedColumn(), false, false);
    }
  }

  /**
   */
  public void moveRowUp(final int row) {
    if (getModel() instanceof ExtendedAttributeTableModelDecorator && row > 0) {
      final ExtendedAttributeTableModelDecorator model = (ExtendedAttributeTableModelDecorator) getModel();
      model.moveRowUp(row);
      changeSelection(row - 1, getSelectedColumn(), false, false);
    }
  }

  @Override
  public Component prepareEditor(final TableCellEditor tce, final int row, final int col) {
    if(tce instanceof DialogTableCellEditor){
      return super.prepareEditor(tce, row, col);
    }
    final JComboBox comboBox = (JComboBox) ((DefaultCellEditor) tce).getComponent();
    final NodeModel node = getAttributeTableModel().getNode();
    final AttributeRegistry attributes = AttributeRegistry.getRegistry(node.getMap());
    final ComboBoxModel model;
    switch (col) {
      case 0:
        model = attributes.getComboBoxModel();
        comboBox.setEditable(!attributes.isRestricted());
        break;
      case 1:
        final String attrName = getAttributeTableModel().getValueAt(row, 0).toString();
        model = attributes.getDefaultComboBoxModel(attrName);
        comboBox.setEditable(!attributes.isRestricted(attrName));
        break;
      default:
        model = AttributeTable.getDefaultComboBoxModel();
    }
    final Object[] items = new Object[model.getSize()];
    for (int i = 0; i < items.length; i++) {
      items[i] = model.getElementAt(i);
    }
    final DefaultComboBoxModel currentModel = new DefaultComboBoxModel(items);
    comboBox.setModel(currentModel);
    updateFontSize(comboBox, getZoom());
    return super.prepareEditor(tce, row, col);
  }

  @Override
    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
      Object value = getValueAt(row, column);
       
            boolean isSelected = false;
            boolean hasFocus = false;
       
            // Only indicate the selection and focused cell if not printing
            MapView map = (MapView) SwingUtilities.getAncestorOfClass(MapView.class, this);
            if (map == null || ! map.isPrinting()) {
                isSelected = isCellSelected(row, column);
       
                boolean rowIsLead =
                    (selectionModel.getLeadSelectionIndex() == row);
                boolean colIsLead =
                    (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
       
                final Window windowAncestor = SwingUtilities.getWindowAncestor(this);
        hasFocus = (rowIsLead && colIsLead) && windowAncestor != null && equals(windowAncestor.getMostRecentFocusOwner());
            }
       
        return renderer.getTableCellRendererComponent(this, value,
                                                      isSelected, hasFocus,
                                                      row, column);
    }

  @Override
  protected boolean processKeyBinding(final KeyStroke ks, final KeyEvent e, final int condition, final boolean pressed) {
    if (ks.getKeyCode() == KeyEvent.VK_TAB && e.getModifiers() == 0 && pressed && getSelectedColumn() == 1
            && getSelectedRow() == getRowCount() - 1 && getModel() instanceof ExtendedAttributeTableModelDecorator) {
      insertRow(getRowCount());
      return true;
    }
    if (ks.getKeyCode() == KeyEvent.VK_ESCAPE && e.getModifiers() == 0 && pressed) {
      attributeView.getNodeView().requestFocusInWindow();
      return true;
    }
    boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
    if (!retValue && condition == JComponent.WHEN_FOCUSED && isFocusOwner() && ks.getKeyCode() != KeyEvent.VK_TAB
            && e != null && e.getID() == KeyEvent.KEY_PRESSED && !e.isActionKey()
            && e.getKeyChar() != KeyEvent.CHAR_UNDEFINED
            && 0 == (e.getModifiers() & (InputEvent.CTRL_MASK | InputEvent.ALT_MASK))) {
      final int leadRow = getSelectionModel().getLeadSelectionIndex();
      final int leadColumn = getColumnModel().getSelectionModel().getLeadSelectionIndex();
      if (leadRow != -1 && leadColumn != -1 && !isEditing()) {
        if (!editCellAt(leadRow, leadColumn, e)) {
          return false;
        }
      }
      final Component editorComponent = getEditorComponent();
      if (editorComponent instanceof JComboBox) {
        final JComboBox comboBox = (JComboBox) editorComponent;
        if (comboBox.isEditable()) {
          final ComboBoxEditor editor = comboBox.getEditor();
          editor.selectAll();
          KeyEvent keyEv;
          keyEv = new KeyEvent(editor.getEditorComponent(), KeyEvent.KEY_TYPED, e.getWhen(),
              e.getModifiers(), KeyEvent.VK_UNDEFINED, e.getKeyChar(), KeyEvent.KEY_LOCATION_UNKNOWN);
          retValue = SwingUtilities.processKeyBindings(keyEv);
        }
        else {
          editorComponent.requestFocusInWindow();
          retValue = true;
        }
      }
    }
    if (ks.getKeyCode() == KeyEvent.VK_SPACE) {
      return true;
    }
    return retValue;
  }

  @Override
  public void removeEditor() {
    final Component editorComponent = getEditorComponent();
    final Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
    boolean requestFocus = editorComponent != null && focusOwner != null &&
    (focusOwner == editorComponent || SwingUtilities.isDescendingFrom(focusOwner, editorComponent));
    getAttributeTableModel().editingCanceled();
    final boolean focusCycleRoot = isFocusCycleRoot();
    setFocusCycleRoot(true);
    super.removeEditor();
    setFocusCycleRoot(focusCycleRoot);
    if(requestFocus)
      requestFocusInWindow();
  }

  /**
   */
  public void removeRow(final int row) {
    if (getModel() instanceof ExtendedAttributeTableModelDecorator) {
      final ExtendedAttributeTableModelDecorator model = (ExtendedAttributeTableModelDecorator) getModel();
      model.removeRow(row);
      final int rowCount = getRowCount();
      if (row <= rowCount - 1) {
        changeSelection(row, getSelectedColumn(), false, false);
      }
      else if (rowCount >= 1) {
        changeSelection(row - 1, getSelectedColumn(), false, false);
      }
    }
  }

  @Override
  public void setModel(final TableModel dataModel) {
    super.setModel(dataModel);
  }

  /**
   *
   */
  public void setOptimalColumnWidths() {
    Component comp = null;
    int cellWidth = 0;
    int maxCellWidth = 2 * (int) (Math.ceil(getFontSize() + AttributeTable.TABLE_ROW_HEIGHT));
    for (int col = 0; col < 2; col++) {
      for (int row = 0; row < getRowCount(); row++) {
        comp = AttributeTable.dtcr.getTableCellRendererComponent(this, getValueAt(row, col), false, false, row,
            col);
        cellWidth = comp.getPreferredSize().width;
        maxCellWidth = Math.max(cellWidth, maxCellWidth);
      }
      getAttributeTableModel().setColumnWidth(col, maxCellWidth + 1);
    }
  }

  @Override
  public void tableChanged(final TableModelEvent e) {
    if(isEditing() && null == getClientProperty(EDITING_STOPPED) ){
      removeEditor();
    }
    int selectedRow = getSelectedRow();
    super.tableChanged(e);
    if (getParent() == null) {
      return;
    }
      switch(e.getType())
      {
        case TableModelEvent.DELETE:
          if(selectedRow != -1 ){
            if(e.getFirstRow() <= selectedRow){
              if( e.getLastRow() >= selectedRow && e.getFirstRow() != 0) {
                changeSelection(e.getFirstRow() - 1, 0, false, false);
              }
              else if(e.getLastRow() < selectedRow){
                int rowIndex = selectedRow - (e.getLastRow() - e.getFirstRow() + 1);
                if(rowIndex < 0){
                  rowIndex = 0;
                }
                if(rowIndex < getRowCount()){
                  changeSelection(rowIndex , getSelectedColumn(), false, false);
                }
              }
            }
          }
          break;
        case TableModelEvent.INSERT:
          changeSelection(e.getFirstRow() , getSelectedColumn(), false, false);
          break;
        default:
          if(selectedRow > getRowCount() && getRowCount() > 0){
            changeSelection(getRowCount() - 1 , getSelectedColumn(), false, false);
          }
      }
    getParent().getParent().invalidate();
    final NodeModel node = attributeView.getNode();
    MapController mapController = attributeView.getMapView().getModeController().getMapController();
    mapController.nodeChanged(node, NodeAttributeTableModel.class, null, null);
  }

  void updateAttributeTable() {
    updateFontSize(this, 1F);
    updateRowHeights();
    updateColumnWidths();
  }

  private void updateColumnWidths() {
    final float zoom = getZoom();
    for (int i = 0; i < 2; i++) {
      final int width = (int) (getAttributeTableModel().getColumnWidth(i) * zoom);
      getColumnModel().getColumn(i).setPreferredWidth(width);
    }
  }

  private void updateFontSize(final Component c, final float zoom) {
    Font font = c.getFont();
    if (font != null) {
      final float oldFontSize = font.getSize2D();
      final float newFontSize = getFontSize() * zoom;
      if (Float.compare(oldFontSize, newFontSize) != 0) {
        font = font.deriveFont(newFontSize);
        c.setFont(font);
      }
    }
  }

  private void updateRowHeights() {
    if(! isDisplayable()){
      addHierarchyListener(new HierarchyListener() {
        public void hierarchyChanged(HierarchyEvent e) {
          if(isDisplayable()){
            updateRowHeights();
            removeHierarchyListener(this);
          }
        }
      });
      return;
    }
    final int rowCount = getRowCount();
    if (rowCount == 0) {
      return;
    }
    final int constHeight = getTableHeaderHeight() + AttributeTable.EXTRA_HEIGHT;
    final float zoom = getZoom();
    final float fontSize = (float) getFont().getMaxCharBounds(((Graphics2D)getGraphics()).getFontRenderContext()).getHeight();
    final float tableRowHeight = fontSize + zoom * AttributeTable.TABLE_ROW_HEIGHT;
    int newHeight = (int) ((tableRowHeight * rowCount + (zoom - 1) * constHeight) / rowCount);
    if (newHeight < 1) {
      newHeight = 1;
    }
    final int highRowsNumber = (int) ((tableRowHeight - newHeight) * rowCount);
    for (int i = 0; i < highRowsNumber; i++) {
      setRowHeight(i, 1 + newHeight + (i == highRowIndex ? AttributeTable.EXTRA_HEIGHT : 0));
    }
    for (int i = highRowsNumber; i < rowCount; i++) {
      setRowHeight(i, newHeight + (i == highRowIndex ? AttributeTable.EXTRA_HEIGHT : 0));
    }
  }

  public void viewRemoved(NodeView nodeView) {
    getModel().removeTableModelListener(this);
  }

  @Override
    public void editingStopped(ChangeEvent e) {
    try{
      putClientProperty(EDITING_STOPPED, Boolean.TRUE);
           // Take in the new value
          TableCellEditor editor = getCellEditor();
          if (editor != null) {
              Object value = editor.getCellEditorValue();
        if (value != null) {
          final MTextController textController = (MTextController) TextController.getController();
          final Object oldValue = getValueAt(editingRow, editingColumn);
          final String pattern  = oldValue instanceof IFormattedObject
                  ? ((IFormattedObject) oldValue).getPattern() : null;
          setValueAt(textController.guessObjectOrURI(value, pattern), editingRow, editingColumn);
        }
              removeEditor();
          }
    }
    finally{
      putClientProperty(EDITING_STOPPED, null);
    }
    }

  @Override
    public void setValueAt(Object aValue, int row, int column) {
      super.setValueAt(column == 0 ? aValue.toString() : aValue, row, column);
      setSelectedCellTypeInfo();
    }

  @Override
    public void valueChanged(ListSelectionEvent e) {
      super.valueChanged(e);
      setSelectedCellTypeInfo();
    }
 
 

  @Override
    public void columnSelectionChanged(ListSelectionEvent e) {
      super.columnSelectionChanged(e);
      setSelectedCellTypeInfo();
    }

  private void setSelectedCellTypeInfo() {
    final int r = getSelectedRow();
    final int c = getSelectedColumn();
    if(r >= 0 && c >= 0){
      final Object value = getValueAt(r, c);
      final ViewController viewController = Controller.getCurrentController().getViewController();
      viewController.addObjectTypeInfo(value);
    }
    }
}
TOP

Related Classes of org.freeplane.view.swing.map.attribute.AttributeTable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.