Package org.sylfra.idea.plugins.revu.ui.forms.issue

Source Code of org.sylfra.idea.plugins.revu.ui.forms.issue.IssueNotesForm$NoteInfoPanel

package org.sylfra.idea.plugins.revu.ui.forms.issue;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.TableUtil;
import com.intellij.ui.table.TableView;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.sylfra.idea.plugins.revu.RevuBundle;
import org.sylfra.idea.plugins.revu.model.*;
import org.sylfra.idea.plugins.revu.utils.RevuUtils;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EventObject;
import java.util.List;

/**
* @author <a href="mailto:syllant@gmail.com">Sylvain FRANCOIS</a>
* @version $Id$
*/
public class IssueNotesForm extends AbstractIssueForm
{
  private JPanel contentPane;
  private JButton bnAdd;
  private TableView<IssueNote> notesTable;
  private JLabel lbCount;
  private NotesTableModel notesTableModel;
  private List<UpdatableEntityListListener<IssueNote>> updatableEntityListListeners;

  public IssueNotesForm(@NotNull Project project)
  {
    super(project);
    updatableEntityListListeners = new ArrayList<UpdatableEntityListListener<IssueNote>>();
    installListeners();
  }

  private void createUIComponents()
  {
    notesTableModel = new NotesTableModel();
    notesTable = new TableView<IssueNote>(notesTableModel)
    {
      @Override
      public boolean editCellAt(int row, int column, EventObject e)
      {
        return super.editCellAt(row, column, e);
      }
    };
    notesTable.setModel(notesTableModel);
    notesTable.setShowVerticalLines(false);
    notesTable.setGridColor(Color.LIGHT_GRAY);
    notesTable.setTableHeader(null);
  }

  private void installListeners()
  {
    bnAdd.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        Review review = getEnclosingReview(null);
        if (review != null)
        {
          IssueNote note = new IssueNote();
          note.setHistory(RevuUtils.buildHistory(review));
          note.setContent(RevuBundle.message("issueForm.notes.defaultContent.text"));

          addNote(note);
        }
      }
    });

    // Make the cell editor for first col active to avoid force user having to click once for enter in editing mode,
    // and once for delete/modify action
    notesTable.addMouseMotionListener(new MouseAdapter()
    {
      @Override
      public void mouseMoved(MouseEvent e)
      {
        int column = notesTable.columnAtPoint(e.getPoint());
        if (column == 0)
        {
          if (notesTable.isEditing())
          {
            return;
          }
          int row = notesTable.rowAtPoint(e.getPoint());
          notesTable.editCellAt(row, column);
        }
      }
    });

    notesTableModel.addTableModelListener(new TableModelListener()
    {
      public void tableChanged(TableModelEvent e)
      {
        lbCount.setText(RevuBundle.message("issueForm.notes.count.text", notesTableModel.getRowCount()));
      }
    });
  }

  private void addNote(IssueNote note)
  {
    // Bad code but this seems to be how ListTableModel is usually used...
    final List<IssueNote> notes = new ArrayList<IssueNote>(notesTableModel.getItems());
    notes.add(note);
    notesTableModel.setItems(notes);

    for (UpdatableEntityListListener<IssueNote> updatableEntityListListener : updatableEntityListListeners)
    {
      updatableEntityListListener.entityAdded(notesTableModel.getItems(), note);
    }

    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        int row = notes.size() - 1;
        notesTable.getSelectionModel().setSelectionInterval(row, row);
        TableUtil.scrollSelectionToVisible(notesTable);

        if (notesTable.editCellAt(row, 1))
        {
          final JTextComponent textEditor = (JTextComponent)
            ((JScrollPane) notesTable.getEditorComponent()).getViewport().getView();
          textEditor.requestFocusInWindow();
          textEditor.selectAll();
        }
      }
    });
  }

  private void removeNote(IssueNote note)
  {
    // Bad code but this seems to be how ListTableModel is usually used...
    List<IssueNote> notes = new ArrayList<IssueNote>(notesTableModel.getItems());
    notes.remove(note);
    notesTableModel.setItems(notes);

    for (UpdatableEntityListListener<IssueNote> updatableEntityListListener : updatableEntityListListeners)
    {
      updatableEntityListListener.entityDeleted(notesTableModel.getItems(), note);
    }
  }

  private boolean isLastNote(IssueNote note)
  {
    List<IssueNote> notes = notesTableModel.getItems();
    return (notes.indexOf(note) == notes.size() - 1);
  }

  private int indexOfNote(IssueNote note)
  {
    return notesTableModel.getItems().indexOf(note);
  }

  public JComponent getPreferredFocusedComponent()
  {
    return bnAdd;
  }

  @NotNull
  public JPanel getContentPane()
  {
    return contentPane;
  }

  public boolean isModified(@NotNull Issue data)
  {
    notesTable.stopEditing();
    return !data.getNotes().equals(notesTableModel.getItems());
  }

  protected void internalUpdateWriteAccess(Issue data, @Nullable User user)
  {
    RevuUtils.setWriteAccess(((user != null)
      && ((currentIssue == null) || (IssueStatus.CLOSED != currentIssue.getStatus()))), bnAdd);
  }

  protected void internalValidateInput(@Nullable Issue data)
  {
  }

  protected void internalUpdateUI(@Nullable Issue data, boolean requestFocus)
  {
    super.internalUpdateUI(data, requestFocus);

    List<IssueNote> notes;
    if (data == null)
    {
      notes = Collections.emptyList();
    }
    else
    {
      notes = cloneNotes(data.getNotes());
    }

    notesTableModel.setItems(notes);
  }

  private List<IssueNote> cloneNotes(List<IssueNote> issueNotes)
  {
    List<IssueNote> clone = new ArrayList<IssueNote>(issueNotes.size());
    for (IssueNote note : issueNotes)
    {
      clone.add(note.clone());
    }

    return clone;
  }

  protected void internalUpdateData(@NotNull Issue data)
  {
    notesTable.stopEditing();
    data.setNotes(cloneNotes(notesTableModel.getItems()));
  }

  private boolean isEditable(@NotNull IssueNote note)
  {
    Review enclosingReview = getEnclosingReview(null);
    if (enclosingReview == null)
    {
      return false;
    }

    User user = RevuUtils.getCurrentUser(enclosingReview);
    return ((currentIssue != null) && (user != null) && (IssueStatus.CLOSED != currentIssue.getStatus())
      && ((note.getHistory().getCreatedBy().equals(user)) || (user.hasRole(User.Role.ADMIN))));
  }

  public void addUpdatableEntityListListener(UpdatableEntityListListener<IssueNote> listener)
  {
    updatableEntityListListeners.add(listener);
  }

  private class NotesTableModel extends ListTableModel<IssueNote>
  {
    private NotesTableModel()
    {
      super(
        new ColumnInfo<IssueNote, Object>("1")
        {
          private NoteInfoPanel noteInfoPanel = new NoteInfoPanel();

          @Override
          public int getWidth(JTable table)
          {
            // @TODO dynamic ?
            return 150;
          }

          public Object valueOf(IssueNote note)
          {
            return note;
          }

          @Override
          public boolean isCellEditable(IssueNote note)
          {
            return isEditable(note);
          }

          @Override
          public TableCellEditor getEditor(IssueNote o)
          {
            return new NoteInfoEditor();
          }

          @Override
          public TableCellRenderer getRenderer(final IssueNote note)
          {
            return new TableCellRenderer()
            {
              public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus,
                int row, int column)
              {
                noteInfoPanel.updateNote(note);
                return noteInfoPanel;
              }
            };
          }
        },
        new ColumnInfo<IssueNote, String>("2")
        {
          public String valueOf(IssueNote note)
          {
            return note.getContent();
          }

          @Override
          public void setValue(IssueNote note, String value)
          {
            note.setContent(value);
          }

          @Override
          public boolean isCellEditable(IssueNote note)
          {
            return isEditable(note);
          }

          @Override
          public TableCellRenderer getRenderer(IssueNote note)
          {
            final JTextArea textArea = new JTextArea();
            textArea.setWrapStyleWord(true);
            textArea.setLineWrap(true);
            textArea.setBackground(UIUtil.getPanelBackground());

            return new TableCellRenderer()
            {
              public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus,
                int row, int column)
              {
                textArea.setText((String) value);

                int minHeight = table.getCellRenderer(row, 0)
                  .getTableCellRendererComponent(table, table.getModel().getValueAt(row, 0), isSelected, hasFocus, row,
                    0).getMinimumSize().height;
                table.setRowHeight(row, Math.max(minHeight, (int) textArea.getPreferredSize().getHeight()));
                return textArea;
              }
            };
          }

          @Override
          public TableCellEditor getEditor(IssueNote o)
          {
            return new NoteContentEditor();
          }
        }
      );

    }
  }

  public class NoteContentEditor extends DefaultCellEditor
  {
    public NoteContentEditor()
    {
      super(new JTextField());
      final JTextArea textArea = new JTextArea();
      textArea.setWrapStyleWord(true);
      textArea.setLineWrap(true);
      JScrollPane scrollPane = new JScrollPane(textArea);
      scrollPane.setBorder(null);
      editorComponent = scrollPane;

      delegate = new EditorDelegate()
      {
        @Override
        public void setValue(Object value)
        {
          textArea.setText((String) value);
        }

        @Override
        public Object getCellEditorValue()
        {
          return textArea.getText();
        }

        @Override
        public boolean startCellEditing(EventObject anEvent)
        {
          textArea.setCaretPosition(textArea.getText().length());
          return super.startCellEditing(anEvent);
        }
      };
    }
  }

  public class NoteInfoEditor extends DefaultCellEditor
  {
    public NoteInfoEditor()
    {
      super(new JTextField());
      final NoteInfoPanel noteInfoPanel = new NoteInfoPanel();
      editorComponent = noteInfoPanel;

      delegate = new EditorDelegate()
      {
        @Override
        public void setValue(Object value)
        {
          noteInfoPanel.updateNote((IssueNote) value);
        }
      };
    }

    @Override
    public boolean isCellEditable(EventObject anEvent)
    {
      return true;
    }
  }

  private class NoteInfoPanel extends JPanel
  {
    private final DateFormat DATE_FORMATTER = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);

    private JLabel lbUser;
    private JLabel lbDate;
    private JLabel lbDelete;
    private JLabel lbModify;
    private IssueNote currentNote;

    private NoteInfoPanel()
    {
      super(new GridBagLayout());
      lbUser = new JLabel();
      lbUser.setFont(lbUser.getFont().deriveFont(Font.BOLD));

      lbDate = new JLabel();

      lbDelete = new JLabel(RevuBundle.message("issueForm.notes.delete.text"));
      lbDelete.setHorizontalAlignment(SwingConstants.CENTER);
      lbDelete.setVerticalAlignment(SwingConstants.TOP);
      lbDelete.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      lbDelete.addMouseListener(new MouseAdapter()
      {
        @Override
        public void mouseClicked(MouseEvent e)
        {
          int result = Messages.showOkCancelDialog(NoteInfoPanel.this,
            RevuBundle.message("issueForm.notes.delete.confirm.text"),
            RevuBundle.message("issueForm.notes.delete.confirm.title"),
            Messages.getQuestionIcon());
          if (result == DialogWrapper.OK_EXIT_CODE)
          {
            removeNote(currentNote);
          }
        }
      });

      lbModify = new JLabel(RevuBundle.message("issueForm.notes.modify.text"));
      lbModify.setHorizontalAlignment(SwingConstants.CENTER);
      lbModify.setVerticalAlignment(SwingConstants.TOP);
      lbModify.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      lbModify.addMouseListener(new MouseAdapter()
      {
        @Override
        public void mouseClicked(MouseEvent e)
        {
          if (notesTable.editCellAt(indexOfNote(currentNote), 1))
          {
            final JTextComponent textEditor = (JTextComponent)
              ((JScrollPane) notesTable.getEditorComponent()).getViewport().getView();
            textEditor.requestFocusInWindow();
          }
        }
      });
      configureUI();
    }

    private void configureUI()
    {
      GridBagConstraints c = new GridBagConstraints();
      c.gridx = 0;
      c.gridy = 0;
      c.gridwidth = 2;
      c.anchor = GridBagConstraints.NORTHWEST;
      c.fill = GridBagConstraints.HORIZONTAL;
      c.weightx = 1.0;
      c.weighty = 0.0;
      add(lbUser, c);

      c.gridy++;
      c.insets = new Insets(0, 0, 5, 0);
      add(lbDate, c);

      c.gridy++;
      c.gridwidth = 1;
      c.weighty = 1.0;
      c.weightx = 0.5;
      c.fill = GridBagConstraints.BOTH;
      c.insets = new Insets(5, 0, 5, 0);
      add(lbModify, c);

      c.gridx++;
      add(lbDelete, c);
    }

    private void updateNote(IssueNote note)
    {
      currentNote = note;

      lbUser.setText(note.getHistory().getCreatedBy().getDisplayName());
      lbDate.setText(DATE_FORMATTER.format(note.getHistory().getCreatedOn()));

      User user = RevuUtils.getCurrentUser(getEnclosingReview(null));
      boolean mayUpdate = (user != null)
        && (((note.getHistory().getCreatedBy().getLogin().equals(user.getLogin())) && (isLastNote(note)))
        || (user.hasRole(User.Role.ADMIN)));
      lbModify.setVisible(mayUpdate);
      lbDelete.setVisible(mayUpdate);
    }
  }
}
TOP

Related Classes of org.sylfra.idea.plugins.revu.ui.forms.issue.IssueNotesForm$NoteInfoPanel

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.