/* * Copyright 2000-2014 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.application.options.codeStyle.arrangement.util; import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.Toggleable; import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; import com.intellij.psi.codeStyle.arrangement.std.ArrangementUiComponent; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SimpleColoredComponent; import com.intellij.util.ui.GridBag; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.util.Set; /** * @author Denis Zhdanov * @since 10/31/12 5:00 PM */ public class ArrangementListRowDecorator extends JPanel implements ArrangementUiComponent { @NotNull private final JLabel mySortLabel = new JLabel(AllIcons.ObjectBrowser.Sorted); @NotNull private final ArrangementRuleIndexControl myRowIndexControl; @NotNull private final ArrangementUiComponent myDelegate; @NotNull private final ArrangementMatchingRulesControl myControl; @NotNull private final MyActionButton myEditButton; @Nullable private Rectangle myScreenBounds; private boolean myBeingEdited; private boolean myUnderMouse; public ArrangementListRowDecorator(@NotNull ArrangementUiComponent delegate, @NotNull ArrangementMatchingRulesControl control) { myDelegate = delegate; myControl = control; mySortLabel.setVisible(false); AnAction action = ActionManager.getInstance().getAction("Arrangement.Rule.Edit"); Presentation presentation = action.getTemplatePresentation().clone(); Icon editIcon = presentation.getIcon(); Dimension buttonSize = new Dimension(editIcon.getIconWidth(), editIcon.getIconHeight()); myEditButton = new MyActionButton(action, presentation, ArrangementConstants.MATCHING_RULES_CONTROL_PLACE, buttonSize); myEditButton.setVisible(false); FontMetrics metrics = getFontMetrics(getFont()); int maxWidth = 0; for (int i = 0; i <= 99; i++) { maxWidth = Math.max(metrics.stringWidth(String.valueOf(i)), maxWidth); } int height = metrics.getHeight() - metrics.getDescent() - metrics.getLeading(); int diameter = Math.max(maxWidth, height) * 5 / 3; myRowIndexControl = new ArrangementRuleIndexControl(diameter, height); setOpaque(true); init(); } public void setError(@Nullable String message) { myRowIndexControl.setError(StringUtil.isNotEmpty(message)); setToolTipText(message); } private void init() { setLayout(new GridBagLayout()); GridBag constraints = new GridBag().anchor(GridBagConstraints.CENTER) .insets(0, ArrangementConstants.HORIZONTAL_PADDING, 0, ArrangementConstants.HORIZONTAL_GAP * 2); add(myRowIndexControl, constraints); add(new InsetsPanel(mySortLabel), new GridBag().anchor(GridBagConstraints.CENTER).insets(0, 0, 0, ArrangementConstants.HORIZONTAL_GAP)); add(myDelegate.getUiComponent(), new GridBag().weightx(1).anchor(GridBagConstraints.WEST)); add(myEditButton, new GridBag().anchor(GridBagConstraints.EAST)); setBorder(IdeBorderFactory.createEmptyBorder(ArrangementConstants.VERTICAL_GAP)); } @Override protected void paintComponent(Graphics g) { Point point = UIUtil.getLocationOnScreen(this); if (point != null) { Rectangle bounds = getBounds(); myScreenBounds = new Rectangle(point.x, point.y, bounds.width, bounds.height); } FontMetrics metrics = g.getFontMetrics(); int baseLine = SimpleColoredComponent.getTextBaseLine(metrics, metrics.getHeight()); myRowIndexControl.setBaseLine( baseLine + ArrangementConstants.VERTICAL_GAP + myDelegate.getUiComponent().getBounds().y - myRowIndexControl.getBounds().y ); super.paintComponent(g); } public void setRowIndex(int row) { myRowIndexControl.setIndex(row); } public void setUnderMouse(boolean underMouse) { myUnderMouse = underMouse; if (myUnderMouse) { setBackground(UIUtil.getDecoratedRowColor()); } else { setBackground(UIUtil.getListBackground()); } } public void setBeingEdited(boolean beingEdited) { if (myBeingEdited && !beingEdited) { myEditButton.getPresentation().putClientProperty(Toggleable.SELECTED_PROPERTY, false); } if (!beingEdited && !myUnderMouse) { myEditButton.setVisible(false); } if (beingEdited && !myBeingEdited) { myEditButton.setVisible(true); myEditButton.getPresentation().putClientProperty(Toggleable.SELECTED_PROPERTY, true); } myBeingEdited = beingEdited; } @NotNull @Override public ArrangementMatchCondition getMatchCondition() { return myDelegate.getMatchCondition(); } @NotNull @Override public JComponent getUiComponent() { return this; } @Nullable @Override public Rectangle getScreenBounds() { return myScreenBounds; } @Override public void setSelected(boolean selected) { myDelegate.setSelected(selected); } @Override public void setData(@NotNull Object data) { myDelegate.setData(data); } public void setShowSortIcon(boolean show) { mySortLabel.setVisible(show); } @Override public Rectangle onMouseEntered(@NotNull MouseEvent e) { setBackground(UIUtil.getDecoratedRowColor()); myEditButton.setVisible(myControl.getSelectedModelRows().size() <= 1); return myDelegate.onMouseEntered(e); } @Nullable @Override public Rectangle onMouseMove(@NotNull MouseEvent event) { myEditButton.setVisible(myControl.getSelectedModelRows().size() <= 1); Rectangle bounds = getButtonScreenBounds(); if (!myBeingEdited && bounds != null) { boolean selected = bounds.contains(event.getLocationOnScreen()); boolean wasSelected = myEditButton.getPresentation().getClientProperty(Toggleable.SELECTED_PROPERTY) == Boolean.TRUE; myEditButton.getPresentation().putClientProperty(Toggleable.SELECTED_PROPERTY, selected); if (selected ^ wasSelected) { return myScreenBounds; } } return myDelegate.onMouseMove(event); } @Override public void onMouseRelease(@NotNull MouseEvent event) { myEditButton.setVisible(myControl.getSelectedModelRows().size() <= 1); Rectangle bounds = getButtonScreenBounds(); if (bounds != null && bounds.contains(event.getLocationOnScreen())) { if (myBeingEdited) { myControl.hideEditor(); myBeingEdited = false; } else { int row = myControl.getRowByRenderer(this); if (row >= 0) { myControl.showEditor(row); myControl.scrollRowToVisible(row); myBeingEdited = true; } } event.consume(); return; } myDelegate.onMouseRelease(event); } @Nullable @Override public Rectangle onMouseExited() { setBackground(UIUtil.getListBackground()); if (!myBeingEdited) { myEditButton.setVisible(false); } return myDelegate.onMouseExited(); } @Nullable private Rectangle getButtonScreenBounds() { if (myScreenBounds == null) { return null; } Rectangle bounds = myEditButton.getBounds(); return new Rectangle(bounds.x + myScreenBounds.x, bounds.y + myScreenBounds.y, bounds.width, bounds.height); } @Nullable @Override public ArrangementSettingsToken getToken() { return myDelegate.getToken(); } @NotNull @Override public Set<ArrangementSettingsToken> getAvailableTokens() { return myDelegate.getAvailableTokens(); } @Override public void chooseToken(@NotNull ArrangementSettingsToken data) throws IllegalArgumentException, UnsupportedOperationException { myDelegate.chooseToken(data); } @Override public boolean isSelected() { return myDelegate.isSelected(); } @Override public void reset() { myDelegate.reset(); } @Override public int getBaselineToUse(int width, int height) { return myDelegate.getBaselineToUse(width, height); } @Override public void setListener(@NotNull Listener listener) { myDelegate.setListener(listener); } @Override public void handleMouseClickOnSelected() { myDelegate.handleMouseClickOnSelected(); } @Override public boolean alwaysCanBeActive() { return false; } @Override public String toString() { return "list row decorator for " + myDelegate.toString(); } private static class MyActionButton extends ActionButton { MyActionButton(AnAction action, Presentation presentation, String place, @NotNull Dimension minimumSize) { super(action, presentation, place, minimumSize); } @NotNull public Presentation getPresentation() { return myPresentation; } } }