ab1c484fbc2bcd4d63c768c53d673b9ae682ef91
[sonitus.git] / src / main / java / net / pterodactylus / sonitus / gui / PipelinePanel.java
1 /*
2  * Sonitus - PipelinePanel.java - Copyright © 2013 David Roden
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 package net.pterodactylus.sonitus.gui;
19
20 import static javax.swing.BorderFactory.createEtchedBorder;
21
22 import java.awt.GridBagConstraints;
23 import java.awt.GridBagLayout;
24 import java.awt.Insets;
25 import java.util.Collection;
26 import java.util.List;
27 import javax.swing.JLabel;
28 import javax.swing.JPanel;
29
30 import net.pterodactylus.sonitus.data.Controlled;
31 import net.pterodactylus.sonitus.data.Filter;
32 import net.pterodactylus.sonitus.data.Pipeline;
33 import net.pterodactylus.sonitus.data.Sink;
34 import net.pterodactylus.sonitus.data.Source;
35
36 import com.google.common.collect.Lists;
37
38 /**
39  * {@link JPanel} that displays all components of a {@link Pipeline}.
40  *
41  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
42  */
43 public class PipelinePanel extends JPanel {
44
45         /** The pipeline being displayed. */
46         private final Pipeline pipeline;
47
48         /**
49          * Creates a new pipeline panel displaying the given pipeline.
50          *
51          * @param pipeline
52          *              The pipeline to display
53          */
54         public PipelinePanel(Pipeline pipeline) {
55                 super(new GridBagLayout());
56                 this.pipeline = pipeline;
57                 updatePanel();
58         }
59
60         //
61         // PRIVATE METHODS
62         //
63
64         /** Update the panel. Needs to be called when the pipeline is changed. */
65         private void updatePanel() {
66                 /* clear everything. */
67                 removeAll();
68
69                 /* count all sinks. */
70                 int sinkCount = 0;
71                 List<Source> sources = Lists.newArrayList(pipeline.source());
72                 while (!sources.isEmpty()) {
73                         Collection<Sink> sinks = pipeline.sinks(sources.remove(0));
74                         for (Sink sink : sinks) {
75                                 /* only count real sinks, everything else is filter. */
76                                 if (sink instanceof Filter) {
77                                         sources.add((Filter) sink);
78                                 } else {
79                                         sinkCount++;
80                                 }
81                         }
82                 }
83
84                 /* get number of maximum horizontal grid cells. */
85                 int gridCellCount = 1;
86                 for (int n = 2; n <= sinkCount; ++n) {
87                         gridCellCount *= n;
88                 }
89
90                 /* paint all components recursively. */
91                 addControlled(pipeline.source(), 0, 0, gridCellCount);
92         }
93
94         /**
95          * Displays the given component.
96          *
97          * @param controlled
98          *              The component to add this panel.
99          * @param level
100          *              The level at which to show the component (the source is level {@code 0})
101          * @param position
102          *              The position at which to display the component
103          * @param width
104          *              The width of the component in grid cells
105          */
106         private void addControlled(Controlled controlled, int level, int position, int width) {
107                 /* create a GUI component that displays the component. */
108                 JLabel sourceLabel = new JLabel(controlled.name());
109                 sourceLabel.setBorder(createEtchedBorder());
110
111                 /* show component. */
112                 add(sourceLabel, new GridBagConstraints(position, level, width, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
113
114                 /* if the component does not have connected sinks, exit here. */
115                 if (!(controlled instanceof Source)) {
116                         return;
117                 }
118
119                 /* iterate over the component’s sinks. */
120                 Collection<Sink> sinks = pipeline.sinks((Source) controlled);
121                 int sinkWidth = width / sinks.size();
122                 int sinkIndex = 0;
123                 for (Sink connectedSink : sinks) {
124                         /* distribute all sinks evenly below this source. */
125                         addControlled(connectedSink, level + 1, position + sinkIndex * sinkWidth, sinkWidth);
126                         sinkIndex++;
127                 }
128         }
129
130 }