| /* |
| * Copyright 2000-2012 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.uiDesigner.designSurface; |
| |
| import com.intellij.openapi.actionSystem.DefaultActionGroup; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.uiDesigner.SelectionWatcher; |
| import com.intellij.uiDesigner.radComponents.RadComponent; |
| import com.intellij.util.ui.PlatformColors; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * Decoration layer is over COMPONENT_LAYER (layer where all components are located). |
| * It contains all necessary decorators. Decorators are: |
| * - special mini-buttons to perform editing of grids (add/remove of columns) |
| * |
| * @author Anton Katilin |
| * @author Vladimir Kondratyev |
| */ |
| final class ActiveDecorationLayer extends JComponent implements FeedbackLayer { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.designSurface.ActiveDecorationLayer"); |
| |
| private final GuiEditor myEditor; |
| private final JToolTip myToolTip; |
| |
| private final Map<RadComponent, ListenerNavigateButton> myNavigateButtons = new HashMap<RadComponent, ListenerNavigateButton>(); |
| |
| private final FeedbackPainterPanel myFeedbackPainterPanel = new FeedbackPainterPanel(); |
| private final RectangleFeedbackPainter myRectangleFeedbackPainter = new RectangleFeedbackPainter(); |
| |
| public ActiveDecorationLayer(@NotNull final GuiEditor editor) { |
| myEditor = editor; |
| myToolTip = new JToolTip(); |
| } |
| |
| public void installSelectionWatcher() { |
| new MyNavigateButtonSelectionWatcher(myEditor); |
| } |
| |
| public void paint(final Graphics g){ |
| layoutListenerNavigateButtons(); |
| |
| // Paint active decorators |
| paintChildren(g); |
| } |
| |
| private void layoutListenerNavigateButtons() { |
| for(Map.Entry<RadComponent, ListenerNavigateButton> e: myNavigateButtons.entrySet()) { |
| RadComponent c = e.getKey(); |
| ListenerNavigateButton btn = e.getValue(); |
| if (btn.isVisible()) { |
| Rectangle rc = SwingUtilities.convertRectangle(c.getDelegee().getParent(), c.getBounds(), this); |
| btn.setLocation(rc.x, rc.y+rc.height); |
| } |
| } |
| } |
| |
| public void putFeedback(Component relativeTo, final Rectangle rc, final String tooltipText) { |
| putFeedback(relativeTo, rc, myRectangleFeedbackPainter, tooltipText); |
| } |
| |
| public void putFeedback(Component relativeTo, Rectangle rc, final FeedbackPainter feedbackPainter, final String tooltipText) { |
| rc = SwingUtilities.convertRectangle(relativeTo, rc, this); |
| myFeedbackPainterPanel.setBounds(rc); |
| myFeedbackPainterPanel.setPainter(feedbackPainter != null ? feedbackPainter : myRectangleFeedbackPainter); |
| Point pntMouse = myEditor.getGlassLayer().getLastMousePosition(); |
| putToolTip(this, new Point(pntMouse.x+20, pntMouse.y+30), tooltipText); |
| if (myFeedbackPainterPanel.getParent() != this) { |
| add(myFeedbackPainterPanel); |
| repaint(); |
| } |
| } |
| |
| private void putToolTip(Component relativeTo, Point pnt, @Nullable String text) { |
| if (text == null) { |
| if (myToolTip.getParent() == this) { |
| remove(myToolTip); |
| repaint(); |
| } |
| } |
| else { |
| String oldText = myToolTip.getTipText(); |
| myToolTip.setTipText(text); |
| |
| pnt = SwingUtilities.convertPoint(relativeTo, pnt, this); |
| Dimension prefSize = myToolTip.getPreferredSize(); |
| pnt.x = Math.min(pnt.x, getBounds().width - prefSize.width); |
| pnt.y = Math.min(pnt.y, getBounds().height - prefSize.height); |
| myToolTip.setBounds(pnt.x, pnt.y, prefSize.width, prefSize.height); |
| if (myToolTip.getParent() != this) { |
| add(myToolTip); |
| repaint(); |
| } |
| else if (!text.equals(oldText)) { |
| myToolTip.repaint(); |
| } |
| } |
| } |
| |
| public void removeFeedback() { |
| boolean needRepaint = false; |
| if (myFeedbackPainterPanel.getParent() == this) { |
| remove(myFeedbackPainterPanel); |
| needRepaint = true; |
| } |
| if (myToolTip.getParent() == this) { |
| remove(myToolTip); |
| needRepaint = true; |
| } |
| if (needRepaint) repaint(); |
| } |
| |
| private static class RectangleFeedbackPainter implements FeedbackPainter { |
| |
| public void paintFeedback(Graphics2D g2d, Rectangle rc) { |
| g2d.setColor(PlatformColors.BLUE); |
| g2d.setStroke(new BasicStroke(2.5f)); |
| // give space for stroke to be painted |
| g2d.drawRect(rc.x+1, rc.y+1, rc.x+rc.width-2, rc.y+rc.height-2); |
| } |
| } |
| |
| private static class FeedbackPainterPanel extends JPanel { |
| private FeedbackPainter myFeedbackPainter; |
| |
| public FeedbackPainterPanel() { |
| setOpaque(false); |
| } |
| |
| protected void paintComponent(Graphics g) { |
| super.paintComponent(g); |
| Graphics2D g2d = (Graphics2D) g; |
| final Stroke savedStroke = g2d.getStroke(); |
| final Color savedColor = g2d.getColor(); |
| try { |
| myFeedbackPainter.paintFeedback(g2d, new Rectangle(0, 0, getWidth(), getHeight())); |
| } |
| finally { |
| g2d.setStroke(savedStroke); |
| g2d.setColor(savedColor); |
| } |
| } |
| |
| public void setPainter(final FeedbackPainter feedbackPainter) { |
| myFeedbackPainter = feedbackPainter; |
| } |
| } |
| |
| private class MyNavigateButtonSelectionWatcher extends SelectionWatcher { |
| public MyNavigateButtonSelectionWatcher(final GuiEditor editor) { |
| super(editor); |
| } |
| |
| protected void selectionChanged(RadComponent component, boolean selected) { |
| ListenerNavigateButton btn = myNavigateButtons.get(component); |
| if (selected) { |
| DefaultActionGroup group = component.getBinding() != null ? ListenerNavigateButton.prepareActionGroup(component) : null; |
| if (group != null && group.getChildrenCount() > 0) { |
| if (btn == null) { |
| btn = new ListenerNavigateButton(component); |
| myNavigateButtons.put(component, btn); |
| } |
| add(btn); |
| btn.setVisible(true); |
| } |
| else { |
| if (btn != null) { |
| btn.setVisible(false); |
| } |
| } |
| } |
| else { |
| if (btn != null) { |
| btn.setVisible(false); |
| } |
| } |
| } |
| } |
| } |