| /* |
| * 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.updater.configure; |
| |
| import com.intellij.ui.ColoredTreeCellRenderer; |
| import com.intellij.util.ui.ThreeStateCheckBox; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import javax.swing.tree.DefaultMutableTreeNode; |
| import javax.swing.tree.TreeCellRenderer; |
| import java.awt.*; |
| |
| /** |
| * A tree node with a checkbox that can have three states. |
| */ |
| abstract class UpdaterTreeNode extends DefaultMutableTreeNode implements Comparable<UpdaterTreeNode>, SdkUpdaterConfigPanel.MultiStateRow { |
| /** |
| * @return The initial state of this node (representing the current state of the SDK). |
| */ |
| abstract public NodeStateHolder.SelectedState getInitialState(); |
| |
| /** |
| * @return The current selected state of this node. |
| */ |
| abstract public NodeStateHolder.SelectedState getCurrentState(); |
| |
| /** |
| * Set the state of the node to the given state. For parent nodes this will also set the state of the children. |
| * @param state |
| */ |
| abstract protected void setState(NodeStateHolder.SelectedState state); |
| |
| /** |
| * Set the state of this node back to its initial state. |
| */ |
| public final void resetState() { |
| setState(getInitialState()); |
| } |
| |
| /** |
| * Indicates whether this node, when represented by a summary node, should be installed when the |
| * summary node is marked as to be installed. |
| * @return True if this node should be selected when the corresponding summary node is selected. |
| */ |
| public boolean includeInSummary() { |
| return false; |
| } |
| |
| /** |
| * Indicates whether this node should be used to retrieve data for a summary node (e.g. currently installed revision). |
| * @return |
| */ |
| public boolean isPrimary() { |
| return false; |
| } |
| |
| /** |
| * Set the selected state of this node to the next one in sequence. This is what happens when a user clicks a checkbox. |
| */ |
| @Override |
| public final void cycleState() { |
| if (getCurrentState() == null) { |
| return; |
| } |
| if (getCurrentState() == NodeStateHolder.SelectedState.NOT_INSTALLED) { |
| if (canHaveMixedState()) { |
| setState(NodeStateHolder.SelectedState.MIXED); |
| } |
| else { |
| setState(NodeStateHolder.SelectedState.INSTALLED); |
| } |
| } |
| else if (getCurrentState() == NodeStateHolder.SelectedState.INSTALLED) { |
| setState(NodeStateHolder.SelectedState.NOT_INSTALLED); |
| } |
| else { |
| setState(NodeStateHolder.SelectedState.INSTALLED); |
| } |
| } |
| |
| /** |
| * Whether this node can have an intermediate state (neither selected nor deselected). This corresponds to e.g. a package being installed |
| * but needing an update, or only some of the children of this node being selected. |
| */ |
| protected boolean canHaveMixedState() { |
| return false; |
| } |
| |
| /** |
| * Status to show in the table. |
| */ |
| public String getStatusString() { |
| return ""; |
| } |
| |
| @Override |
| public int compareTo(UpdaterTreeNode o) { |
| return toString().compareTo(o.toString()); |
| } |
| |
| public static class Renderer extends JPanel implements TreeCellRenderer { |
| private final ColoredTreeCellRenderer myTextRenderer; |
| public final ThreeStateCheckBox myCheckbox; |
| |
| public Renderer() { |
| super(new BorderLayout()); |
| myCheckbox = new ThreeStateCheckBox(); |
| myTextRenderer = new ColoredTreeCellRenderer() { |
| @Override |
| public void customizeCellRenderer(@NotNull JTree tree, |
| Object value, |
| boolean selected, |
| boolean expanded, |
| boolean leaf, |
| int row, |
| boolean hasFocus) { |
| } |
| }; |
| myTextRenderer.setOpaque(true); |
| add(myCheckbox, BorderLayout.WEST); |
| add(myTextRenderer, BorderLayout.CENTER); |
| } |
| |
| @Override |
| public final Component getTreeCellRendererComponent(JTree tree, |
| Object value, |
| boolean selected, |
| boolean expanded, |
| boolean leaf, |
| int row, |
| boolean hasFocus) { |
| if (!(value instanceof UpdaterTreeNode)) { |
| return null; |
| } |
| UpdaterTreeNode node = (UpdaterTreeNode)value; |
| invalidate(); |
| myCheckbox.setVisible(true); |
| if (node.getCurrentState() == NodeStateHolder.SelectedState.MIXED) { |
| myCheckbox.setState(ThreeStateCheckBox.State.DONT_CARE); |
| } |
| else { |
| myCheckbox.setSelected(node.getCurrentState() == NodeStateHolder.SelectedState.INSTALLED); |
| } |
| myCheckbox.setOpaque(false); |
| myCheckbox.setBackground(null); |
| setBackground(null); |
| myTextRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); |
| |
| if (UIUtil.isUnderGTKLookAndFeel()) { |
| final Color background = selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(); |
| UIUtil.changeBackGround(this, background); |
| } |
| else if (UIUtil.isUnderNimbusLookAndFeel()) { |
| UIUtil.changeBackGround(this, UIUtil.TRANSPARENT_COLOR); |
| } |
| node.customizeRenderer(this, tree, selected, expanded, leaf, row, hasFocus); |
| revalidate(); |
| |
| return this; |
| } |
| |
| public ColoredTreeCellRenderer getTextRenderer() { |
| return myTextRenderer; |
| } |
| } |
| |
| public void customizeRenderer(Renderer renderer, |
| JTree tree, |
| boolean selected, |
| boolean expanded, |
| boolean leaf, |
| int row, |
| boolean hasFocus) { |
| } |
| } |