Add basic UI skeleton to add/modify/delete annotation settings

UI currently consists of
1) column for field type which is a drop-box of enums
2) column for field name which is a text box.

No logic is implemented yet.

Test: None
Change-Id: I31e261fe19f53a609889985b6e36642350904f6f
diff --git a/src/tuningfork/tools/plugin/src/main/java/AnnotationTab.java b/src/tuningfork/tools/plugin/src/main/java/AnnotationTab.java
new file mode 100644
index 0000000..efb1b69
--- /dev/null
+++ b/src/tuningfork/tools/plugin/src/main/java/AnnotationTab.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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
+ */
+
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.ui.ToolbarDecorator;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.ui.components.JBScrollPane;
+import com.intellij.ui.table.JBTable;
+import java.awt.Dimension;
+import java.awt.Font;
+import javax.swing.Box;
+import javax.swing.DefaultCellEditor;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.table.TableColumn;
+import org.jdesktop.swingx.VerticalLayout;
+
+class AnnotationTab extends JPanel {
+    private JBScrollPane scrollPane;
+    private JBTable annotationTable;
+    private JPanel decoratorPanel;
+
+    private final JBLabel annotationLabel = new JBLabel("Annotation Settings");
+    private final JBLabel informationLabel =
+        new JBLabel("Annotation is used by tuning fork to mark the histograms being sent.");
+    private final Font mainFont = new Font(Font.SANS_SERIF, Font.BOLD, FONT_BIG);
+    private final Font secondaryLabel = new Font(Font.SANS_SERIF, Font.PLAIN, FONT_SMALL);
+    private static final int PANEL_MIN_WIDTH = 600;
+    private static final int PANEL_MIN_HEIGHT = 500;
+    private static final int TABLE_MIN_WIDTH = 500;
+    private static final int TABLE_MIN_HEIGHT = 230;
+    private static final int FONT_BIG = 18;
+    private static final int FONT_SMALL = 12;
+
+    public AnnotationTab() {
+        initVariables();
+        initComponents();
+    }
+
+    private void initVariables() {
+        scrollPane = new JBScrollPane();
+        annotationTable = new JBTable();
+        decoratorPanel =
+            ToolbarDecorator.createDecorator(annotationTable)
+                .setAddAction(it -> AnnotationTabController.addRowAction(annotationTable))
+                .setRemoveAction(it -> AnnotationTabController.removeRowAction(annotationTable))
+                .createPanel();
+    }
+
+    private void initComponents() {
+        // Initialize layout.
+        this.setLayout(new VerticalLayout());
+        this.setMinimumSize(new Dimension(PANEL_MIN_WIDTH, PANEL_MIN_HEIGHT));
+        this.setPreferredSize(new Dimension(PANEL_MIN_WIDTH, PANEL_MIN_HEIGHT));
+
+        // Add labels.
+        annotationLabel.setFont(mainFont);
+        informationLabel.setFont(secondaryLabel);
+        this.add(annotationLabel);
+        this.add(Box.createVerticalStrut(10));
+        this.add(informationLabel);
+
+        // Initialize toolbar and table.
+        AnnotationTableModel model = new AnnotationTableModel();
+        annotationTable.setModel(model);
+        decoratorPanel.setPreferredSize(new Dimension(TABLE_MIN_WIDTH, TABLE_MIN_HEIGHT));
+        decoratorPanel.setMinimumSize(new Dimension(TABLE_MIN_WIDTH, TABLE_MIN_HEIGHT));
+        annotationTable.setFillsViewportHeight(true);
+        scrollPane.setViewportView(decoratorPanel);
+        annotationTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        annotationTable.getTableHeader().setReorderingAllowed(false);
+        annotationTable.setRowSelectionAllowed(true);
+        annotationTable.setSelectionBackground(null);
+
+        // Initialize field type column.
+        TableColumn typeColumn = annotationTable.getColumnModel().getColumn(0);
+        typeColumn.setCellEditor(getComboBoxModel());
+        typeColumn.setCellRenderer(new TableRenderer.ComboBoxRenderer());
+        typeColumn.setPreferredWidth(150);
+
+        // Initialize field name column.
+        TableColumn nameColumn = annotationTable.getColumnModel().getColumn(1);
+        nameColumn.setCellEditor(getTextFieldModel());
+        nameColumn.setCellRenderer(new TableRenderer.RoundedCornerRenderer());
+        nameColumn.setPreferredWidth(350);
+
+        // Table extra feature such as dynamic size and no grid lines.
+        annotationTable.getModel().addTableModelListener(tableModelEvent -> resizePanelToFit());
+        annotationTable.setIntercellSpacing(new Dimension(0, 0));
+
+        this.add(scrollPane);
+    }
+
+    private void resizePanelToFit() {
+        int oldWidth = scrollPane.getWidth();
+        int newHeight = Math.max(decoratorPanel.getMinimumSize().height + 2,
+            Math.min(AnnotationTab.this.getHeight() - 100,
+                annotationTable.getRowHeight() * annotationTable.getRowCount() + 30));
+        scrollPane.setSize(new Dimension(oldWidth, newHeight));
+        scrollPane.revalidate();
+    }
+
+    private DefaultCellEditor getTextFieldModel() {
+        JTextField textFieldModel = new JTextField();
+        textFieldModel.setBorder(new RoundedCornerBorder());
+        DefaultCellEditor textEditor = new DefaultCellEditor(textFieldModel);
+        textEditor.setClickCountToStart(1);
+        return textEditor;
+    }
+
+    private DefaultCellEditor getComboBoxModel() {
+        ComboBox<String> comboBoxModel = new ComboBox<>();
+        // TODO(mohanad): This will be replaced by enum values.
+        comboBoxModel.addItem("loadingState");
+        comboBoxModel.addItem("Scene");
+        comboBoxModel.addItem("bigBoss");
+        DefaultCellEditor boxEditor = new DefaultCellEditor(comboBoxModel);
+        boxEditor.setClickCountToStart(1);
+        return boxEditor;
+    }
+}
diff --git a/src/tuningfork/tools/plugin/src/main/java/AnnotationTabController.java b/src/tuningfork/tools/plugin/src/main/java/AnnotationTabController.java
new file mode 100644
index 0000000..aa9f77b
--- /dev/null
+++ b/src/tuningfork/tools/plugin/src/main/java/AnnotationTabController.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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
+ */
+
+import javax.swing.JTable;
+
+public class AnnotationTabController {
+    public static void addRowAction(JTable jtable) {
+        AnnotationTableModel model = (AnnotationTableModel) jtable.getModel();
+        // TODO(mohanad): placeholder values used. Will be replaced later with default enum value.
+        model.addRow(new String[] {
+            "",
+            "",
+        });
+    }
+
+    public static void removeRowAction(JTable jtable) {
+        AnnotationTableModel model = (AnnotationTableModel) jtable.getModel();
+        int row = jtable.getSelectedRow();
+        if (jtable.getCellEditor() != null) {
+            jtable.getCellEditor().stopCellEditing();
+        }
+        model.removeRow(row);
+    }
+}
diff --git a/src/tuningfork/tools/plugin/src/main/java/AnnotationTableModel.java b/src/tuningfork/tools/plugin/src/main/java/AnnotationTableModel.java
new file mode 100644
index 0000000..5dae2bc
--- /dev/null
+++ b/src/tuningfork/tools/plugin/src/main/java/AnnotationTableModel.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.table.AbstractTableModel;
+
+public class AnnotationTableModel extends AbstractTableModel {
+    private final String[] columnNames = {"Type", "Name"};
+    private final List<String[]> data;
+
+    public AnnotationTableModel() {
+        data = new ArrayList<>();
+    }
+
+    @Override
+    public int getRowCount() {
+        return data.size();
+    }
+
+    @Override
+    public int getColumnCount() {
+        return columnNames.length;
+    }
+
+    @Override
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        return data.get(rowIndex)[columnIndex];
+    }
+
+    @Override
+    public String getColumnName(int column) {
+        return columnNames[column];
+    }
+
+    public void addRow(String[] row) {
+        data.add(row);
+        fireTableRowsInserted(getRowCount() - 1, getRowCount());
+    }
+
+    @Override
+    public boolean isCellEditable(int row, int column) {
+        return true;
+    }
+
+    @Override
+    public void setValueAt(Object value, int row, int column) {
+        data.get(row)[column] = value.toString();
+        fireTableCellUpdated(row, column);
+    }
+
+    public void removeRow(int row) {
+        data.remove(row);
+        fireTableDataChanged();
+    }
+}
diff --git a/src/tuningfork/tools/plugin/src/main/java/RoundedCornerBorder.java b/src/tuningfork/tools/plugin/src/main/java/RoundedCornerBorder.java
new file mode 100644
index 0000000..cf97167
--- /dev/null
+++ b/src/tuningfork/tools/plugin/src/main/java/RoundedCornerBorder.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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
+ */
+
+import com.intellij.ui.JBColor;
+import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.UIUtil;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import javax.swing.border.AbstractBorder;
+
+public final class RoundedCornerBorder extends AbstractBorder {
+    private final Color ALPHA_ZERO = UIUtil.getWindowColor();
+
+    @Override
+    public void paintBorder(
+        Component component, Graphics graphics, int x, int y, int width, int height) {
+        Graphics2D graphics2D = (Graphics2D) graphics.create();
+        graphics2D.setRenderingHint(
+            RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        Shape border = getBorderShape(x, y, width - 1, height - 1);
+        graphics2D.setPaint(ALPHA_ZERO);
+        Area corner = new Area(new Rectangle2D.Double(x, y, width, height));
+        corner.subtract(new Area(border));
+        graphics2D.fill(corner);
+        graphics2D.setPaint(JBColor.GRAY);
+        graphics2D.draw(border);
+        graphics2D.dispose();
+    }
+
+    public Shape getBorderShape(int x, int y, int width, int height) {
+        int arcWidth = height;
+        int arcHeight = height;
+        return new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight);
+    }
+
+    @Override
+    public Insets getBorderInsets(Component component) {
+        return JBUI.insets(4, 8);
+    }
+
+    @Override
+    public Insets getBorderInsets(Component component, Insets insets) {
+        insets.set(4, 8, 4, 8);
+        return insets;
+    }
+}
diff --git a/src/tuningfork/tools/plugin/src/main/java/TableRenderer.java b/src/tuningfork/tools/plugin/src/main/java/TableRenderer.java
new file mode 100644
index 0000000..1db9a6f
--- /dev/null
+++ b/src/tuningfork/tools/plugin/src/main/java/TableRenderer.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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
+ */
+
+import java.awt.Component;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+
+public class TableRenderer {
+    public static final class RoundedCornerRenderer extends DefaultTableCellRenderer {
+        @Override
+        public Component getTableCellRendererComponent(JTable jTable, Object value,
+            boolean isSelected, boolean hasFocus, int row, int column) {
+            JComponent component = (JComponent) super.getTableCellRendererComponent(
+                jTable, value, isSelected, hasFocus, row, column);
+            component.setBorder(new RoundedCornerBorder());
+            return component;
+        }
+    }
+
+    public static final class ComboBoxRenderer
+        extends JComboBox<String> implements TableCellRenderer {
+        @Override
+        public Component getTableCellRendererComponent(
+            JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+            removeAllItems();
+            addItem(value.toString());
+            return this;
+        }
+    }
+}