com.android.tools.idea.structure.services.ServicePanelBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.android.tools.idea.structure.services.ServicePanelBuilder.java

Source

/*
 * Copyright (C) 2015 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.
 */
package com.android.tools.idea.structure.services;

import com.android.tools.adtui.TabularLayout;
import com.android.tools.idea.ui.properties.BindingsManager;
import com.android.tools.idea.ui.properties.InvalidationListener;
import com.android.tools.idea.ui.properties.ObservableValue;
import com.android.tools.idea.ui.properties.collections.ObservableList;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.HyperlinkLabel;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.util.List;

/**
 * Builder that builds up the panel which is defined in service.xml. Use {@link #getPanel()} to get
 * the underlying Swing panel.
 */
public final class ServicePanelBuilder {

    @NotNull
    private final JPanel myRootPanel;
    @NotNull
    private final BindingsManager myBindings = new BindingsManager();
    @NotNull
    private final Stack<UiGrid> myGrids = new Stack<UiGrid>();

    public ServicePanelBuilder() {
        myRootPanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false));
        // Pass BindingsManager to the panel so it stays alive after this builder goes away.
        myRootPanel.putClientProperty("bindings", myBindings);
    }

    public JPanel getPanel() {
        assert myGrids.isEmpty() : "startGrid called without matching endGrid";
        return myRootPanel;
    }

    /**
     * Return the active bindings manager for this panel, useful so we can register new bindings
     * externally.
     */
    @NotNull
    public BindingsManager getBindings() {
        return myBindings;
    }

    /**
     * Begin a grid, which groups added components into a table-like layout until {@link #endGrid()}
     * is called. You can nest grids.
     */
    public JPanel startGrid(@NotNull String colDefinitions) {
        UiGrid uiGrid = new UiGrid(colDefinitions);
        myGrids.push(uiGrid);
        return uiGrid.getPanel();
    }

    public void endGrid() {
        assert !myGrids.isEmpty() : "endGrid called without matching startGrid";
        addComponent(myGrids.pop().getPanel());
    }

    /**
     * Set the row index of the next added component. It is an error to call this while we are not
     * constructing a grid.
     */
    public void setRow(int row) {
        assert !myGrids.isEmpty() : "setRow called without calling startGrid";
        myGrids.peek().setCurrRow(row);
    }

    /**
     * Set the row index of the next added component. It is an error to call this while we are not
     * constructing a grid.
     */
    public void setCol(int col) {
        assert !myGrids.isEmpty() : "setCol called without calling startGrid";
        myGrids.peek().setCurrCol(col);
    }

    public JButton addButton() {
        JButton button = new JButton();
        addComponent(button);
        return button;
    }

    public JCheckBox addCheckbox() {
        JCheckBox checkbox = new JCheckBox();
        addComponent(checkbox);
        return checkbox;
    }

    public JLabel addLabel() {
        JLabel label = new JLabel();
        addComponent(label);
        return label;
    }

    public HyperlinkLabel addLink(@NotNull String text, @NotNull final URI uri) {
        HyperlinkLabel linkLabel = new HyperlinkLabel(text);
        linkLabel.addHyperlinkListener(new HyperlinkListener() {
            @Override
            public void hyperlinkUpdate(HyperlinkEvent e) {
                try {
                    Desktop.getDesktop().browse(uri);
                } catch (IOException e1) {
                    // Don't care
                }
            }
        });
        addComponent(linkLabel);
        return linkLabel;
    }

    public JTextField addField() {
        JTextField field = new JTextField();
        addComponent(field);
        return field;
    }

    public JComboBox addComboBox(@NotNull final ObservableList<String> backingList) {
        final CollectionComboBoxModel<String> model = new CollectionComboBoxModel<String>(backingList) {
            @NotNull
            @Override
            public List<String> getItems() {
                return backingList;
            }
        };

        final ComboBox comboBox = new ComboBox(model);

        InvalidationListener onListModified = new InvalidationListener() {
            @Override
            public void onInvalidated(@NotNull ObservableValue<?> sender) {
                model.update();
                if (backingList.size() > 0 && comboBox.getSelectedIndex() < 0) {
                    comboBox.setSelectedIndex(0);
                }
            }
        };

        addComponent(comboBox);
        backingList.addWeakListener(onListModified);
        // Keep weak listener alive as long as the combobox is alive
        comboBox.putClientProperty("onListModified", onListModified);
        return comboBox;
    }

    private void addComponent(@NotNull JComponent component) {
        if (!myGrids.isEmpty()) {
            myGrids.peek().addComponent(component);
        } else {
            myRootPanel.add(component);
        }
    }

    /**
     * Tracks the state of the row of parameters currently being built.
     */
    private static class UiGrid {
        @NotNull
        private final JPanel myPanel;
        private final int myNumCols;
        private int myCurrCol;
        private int myCurrRow;

        public UiGrid(@NotNull String colDefinitions) {
            TabularLayout layout = new TabularLayout(colDefinitions).setVGap(10);
            myNumCols = layout.getNumColumns();
            myPanel = new JPanel(layout);
        }

        @NotNull
        public JPanel getPanel() {
            return myPanel;
        }

        public void setCurrCol(int col) {
            if (col >= myNumCols) {
                throw new IllegalArgumentException(
                        String.format("Can't set col = %1$d on a grid with only %2$d columns", col, myNumCols));
            }
            myCurrCol = col;
        }

        public void setCurrRow(int row) {
            myCurrRow = row;
        }

        public void addComponent(@NotNull JComponent component) {
            myPanel.add(component, new TabularLayout.Constraint(myCurrRow, myCurrCol));
            myCurrRow = 0;
            myCurrCol = 0;
        }
    }
}