/*
 * Copyright 2000-2010 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.util.ui;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.table.TableView;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.table.TableCellEditor;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventObject;

public abstract class ChangesTrackingTableView<T> extends TableView<T> {

  private Disposable myEditorListenerDisposable;

  protected abstract void onCellValueChanged(int row, int column, Object value);

  protected abstract void onEditingStopped();

  @Override
  public TableCellEditor getCellEditor(int row, int column) {
    final TableCellEditor editor = super.getCellEditor(row, column);
    if (column == 0 && editor instanceof DefaultCellEditor) {
      //((DefaultCellEditor)editor).setClickCountToStart(1);
    }
    return editor;
  }

  @Override
  public boolean editCellAt(final int row, final int column, EventObject e) {
    if (super.editCellAt(row, column, e)) {
      assert myEditorListenerDisposable == null;
      myEditorListenerDisposable = new Disposable() {
        @Override
        public void dispose() {
        }
      };
      addChangeListener(getEditorComponent(), new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent e) {
          onCellValueChanged(row, column, getValue(getEditorComponent()));
        }
      }, myEditorListenerDisposable);
      return true;
    }
    return false;
  }

  @Override
  public void removeEditor() {
    if (myEditorListenerDisposable != null) {
      Disposer.dispose(myEditorListenerDisposable);
      myEditorListenerDisposable = null;
    }

    onEditingStopped();
    super.removeEditor();
  }

  public static Object getValue(Component component) {
    if (component instanceof CellEditorComponentWithBrowseButton) {
      final JTextField textField = (JTextField)((CellEditorComponentWithBrowseButton)component).getChildComponent();
      return textField.getText();
    }
    else if (component instanceof JTextField) {
      return ((JTextField)component).getText();
    }
    else if (component instanceof JComboBox) {
      return ((JComboBox)component).getSelectedItem();
    }
    else if (component instanceof JCheckBox) {
      return Boolean.valueOf(((JCheckBox)component).isSelected());
    }
    throw new UnsupportedOperationException("editor control of type " + component.getClass().getName() + " is not supported");
  }

  private static void addChangeListener(final Component component, final ChangeListener listener, Disposable parentDisposable) {
    if (component instanceof CellEditorComponentWithBrowseButton) {
      addChangeListener(((CellEditorComponentWithBrowseButton)component).getChildComponent(), listener, parentDisposable);
    }
    else if (component instanceof JTextField) {
      final DocumentAdapter documentListener = new DocumentAdapter() {
        @Override
        protected void textChanged(DocumentEvent e) {
          listener.stateChanged(new ChangeEvent(component));
        }
      };
      final Document document = ((JTextField)component).getDocument();
      document.addDocumentListener(documentListener);
      Disposer.register(parentDisposable, new Disposable() {
        @Override
        public void dispose() {
          document.removeDocumentListener(documentListener);
        }
      });
    }
    else if (component instanceof JComboBox) {
      final ActionListener comboListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          listener.stateChanged(new ChangeEvent(component));
        }
      };
      ((JComboBox)component).addActionListener(comboListener);
      Disposer.register(parentDisposable, new Disposable() {
        @Override
        public void dispose() {
          ((JComboBox)component).removeActionListener(comboListener);
        }
      });
    }
    else if (component instanceof JCheckBox) {
      final ActionListener checkBoxListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          listener.stateChanged(new ChangeEvent(component));
        }
      };
      ((JCheckBox)component).addActionListener(checkBoxListener);
      Disposer.register(parentDisposable, new Disposable() {
        @Override
        public void dispose() {
          ((JCheckBox)component).removeActionListener(checkBoxListener);
        }
      });
    }
    else if (component instanceof JCheckBox) {
      final ActionListener checkBoxListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          listener.stateChanged(new ChangeEvent(component));
        }
      };
      ((JCheckBox)component).addActionListener(checkBoxListener);
      Disposer.register(parentDisposable, new Disposable() {
        @Override
        public void dispose() {
          ((JCheckBox)component).removeActionListener(checkBoxListener);
        }
      });
    }
    else {
      throw new UnsupportedOperationException("editor control of type " + component.getClass().getName() + " is not supported");
    }
  }

}

@@ -5279,551 +5279,8 @@
   %7D%0A
-    else if (component instanceof JCheckBox) %7B%0A      final ActionListener checkBoxListener = new ActionListener() %7B%0A        @Override%0A        public void actionPerformed(ActionEvent e) %7B%0A          listener.stateChanged(new ChangeEvent(component));%0A        %7D%0A      %7D;%0A      ((JCheckBox)component).addActionListener(checkBoxListener);%0A      Disposer.register(parentDisposable, new Disposable() %7B%0A        @Override%0A        public void dispose() %7B%0A          ((JCheckBox)component).removeActionListener(checkBoxListener);%0A        %7D%0A      %7D);%0A    %7D%0A
     

remove duplicate code appeared on merge