2 * Sonitus - PipelinePanel.java - Copyright © 2013 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sonitus.gui;
20 import static javax.swing.BorderFactory.createEtchedBorder;
22 import java.awt.GridBagConstraints;
23 import java.awt.GridBagLayout;
24 import java.awt.Insets;
25 import java.awt.event.MouseAdapter;
26 import java.awt.event.MouseEvent;
27 import java.util.Collection;
28 import java.util.EventListener;
29 import java.util.List;
30 import javax.swing.JLabel;
31 import javax.swing.JPanel;
32 import javax.swing.event.EventListenerList;
34 import net.pterodactylus.sonitus.data.ControlledComponent;
35 import net.pterodactylus.sonitus.data.Filter;
36 import net.pterodactylus.sonitus.data.Pipeline;
37 import net.pterodactylus.sonitus.data.Sink;
38 import net.pterodactylus.sonitus.data.Source;
40 import com.google.common.collect.Lists;
43 * {@link JPanel} that displays all components of a {@link Pipeline}.
45 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
47 public class PipelinePanel extends JPanel {
49 /** The pipeline being displayed. */
50 private final Pipeline pipeline;
52 /** The component hover listeners. */
53 private final EventListenerList componentHoverListeners = new EventListenerList();
56 * Creates a new pipeline panel displaying the given pipeline.
59 * The pipeline to display
61 public PipelinePanel(Pipeline pipeline) {
62 super(new GridBagLayout());
63 this.pipeline = pipeline;
68 // LISTENER MANAGEMENT
72 * Adds the given component hover listener to this panel.
74 * @param componentHoverListener
75 * The component hover listener to add
77 public void addComponentHoverListener(ComponentHoverListener componentHoverListener) {
78 componentHoverListeners.add(ComponentHoverListener.class, componentHoverListener);
85 /** Update the panel. Needs to be called when the pipeline is changed. */
86 private void updatePanel() {
87 /* clear everything. */
90 /* count all sinks. */
92 List<Source> sources = Lists.newArrayList(pipeline.source());
93 while (!sources.isEmpty()) {
94 Collection<Sink> sinks = pipeline.sinks(sources.remove(0));
95 for (Sink sink : sinks) {
96 /* only count real sinks, everything else is filter. */
97 if (sink instanceof Filter) {
98 sources.add((Filter) sink);
105 /* get number of maximum horizontal grid cells. */
106 int gridCellCount = 1;
107 for (int n = 2; n <= sinkCount; ++n) {
111 /* paint all components recursively. */
112 addControlled(pipeline.source(), 0, 0, gridCellCount);
116 * Displays the given component.
118 * @param controlledComponent
119 * The component to add this panel.
121 * The level at which to show the component (the source is level {@code 0})
123 * The position at which to display the component
125 * The width of the component in grid cells
127 private void addControlled(final ControlledComponent controlledComponent, int level, int position, int width) {
128 /* create a GUI component that displays the component. */
129 JLabel sourceLabel = new JLabel(controlledComponent.name());
130 sourceLabel.setBorder(createEtchedBorder());
131 sourceLabel.addMouseListener(new MouseAdapter() {
134 public void mouseEntered(MouseEvent mouseEvent) {
135 for (ComponentHoverListener componentHoverListener : componentHoverListeners.getListeners(ComponentHoverListener.class)) {
136 componentHoverListener.componentEntered(controlledComponent);
141 /* show component. */
142 add(sourceLabel, new GridBagConstraints(position, level, width, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
144 /* if the component does not have connected sinks, exit here. */
145 if (!(controlledComponent instanceof Source)) {
149 /* iterate over the component’s sinks. */
150 Collection<Sink> sinks = pipeline.sinks((Source) controlledComponent);
151 int sinkWidth = width / sinks.size();
153 for (Sink connectedSink : sinks) {
154 /* distribute all sinks evenly below this source. */
155 addControlled(connectedSink, level + 1, position + sinkIndex * sinkWidth, sinkWidth);
161 * Interface for objects that want to be notified if the user moves the mouse
162 * cursor over a controlled component.
164 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
166 public static interface ComponentHoverListener extends EventListener {
169 * Notifies the listener that the mouse is now over the given controlled
172 * @param controlledComponent
173 * The controlled component now under the mouse
175 void componentEntered(ControlledComponent controlledComponent);