Skip to content

Commit 37f05c7

Browse files
authored
feat: MOP GUI (#22489)
Signed-off-by: Lazar Petrovic <[email protected]>
1 parent 29d212b commit 37f05c7

File tree

13 files changed

+265
-365
lines changed

13 files changed

+265
-365
lines changed

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/gui/hashgraph/HashgraphPictureOptions.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ public interface HashgraphPictureOptions {
1010
*/
1111
boolean isPictureFrozen();
1212

13-
/**
14-
* @return should the hashgraph be expanded
15-
*/
16-
boolean isExpanded();
17-
1813
/**
1914
* @return should round created be written for every event
2015
*/

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/gui/hashgraph/internal/EventSelector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public void mouseClicked(final MouseEvent me) {
7373

7474
stronglySeen.clear();
7575
for (final EventImpl e : eventsInPicture) {
76-
final int xEvent = metadata.xpos(null, e);
76+
final int xEvent = metadata.xpos(e);
7777
final int yEvent = metadata.ypos(e);
7878
final double distanceSquared = Math.pow(xEvent - xClicked, 2) + Math.pow(yEvent - yClicked, 2);
7979
if (distanceSquared <= rSquared - 20) {

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/gui/hashgraph/internal/HashgraphGuiControls.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ public class HashgraphGuiControls implements HashgraphPictureOptions {
2828
private final Checkbox freezeCheckbox;
2929
/** if checked, color vertices only green (non-consensus) or blue (consensus) */
3030
private final Checkbox simpleColorsCheckbox;
31-
/** if checked, use multiple columns per member to void lines crossing */
32-
private final Checkbox expandCheckbox;
3331

3432
// the following control which labels to print on each vertex
3533

@@ -66,7 +64,6 @@ public HashgraphGuiControls(final ItemListener freezeListener) {
6664
freezeCheckbox = new Checkbox("Freeze: don't change this window");
6765
freezeCheckbox.addItemListener(freezeListener);
6866
simpleColorsCheckbox = new Checkbox("Colors: blue=consensus, green=not");
69-
expandCheckbox = new Checkbox("Expand: wider so lines don't cross");
7067
labelRoundCheckbox = new Checkbox("Labels: Round created");
7168
labelVoteCheckbox = new Checkbox("Labels: Vote");
7269
labelEventHashCheckbox = new Checkbox("Labels: Event Hash (h)");
@@ -106,7 +103,6 @@ public HashgraphGuiControls(final ItemListener freezeListener) {
106103
comps = new Component[] {
107104
freezeCheckbox,
108105
simpleColorsCheckbox,
109-
expandCheckbox,
110106
labelRoundCheckbox,
111107
labelVoteCheckbox,
112108
labelEventHashCheckbox,
@@ -121,16 +117,6 @@ public HashgraphGuiControls(final ItemListener freezeListener) {
121117
};
122118
}
123119

124-
/**
125-
* Set the state of the expanded control
126-
*
127-
* @param expand
128-
* the state to set it to
129-
*/
130-
public void setExpanded(final boolean expand) {
131-
expandCheckbox.setState(expand);
132-
}
133-
134120
/**
135121
* @return a {@link JPanel} with the controls
136122
*/
@@ -220,11 +206,6 @@ public boolean isPictureFrozen() {
220206
return freezeCheckbox.getState();
221207
}
222208

223-
@Override
224-
public boolean isExpanded() {
225-
return expandCheckbox.getState();
226-
}
227-
228209
@Override
229210
public boolean writeRoundCreated() {
230211
return labelRoundCheckbox.getState();

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/gui/hashgraph/internal/HashgraphPicture.java

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import com.hedera.hapi.node.state.roster.Roster;
88
import com.hedera.hapi.node.state.roster.RosterEntry;
99
import com.hedera.hapi.platform.event.GossipEvent;
10-
import com.swirlds.platform.Consensus;
1110
import com.swirlds.platform.gui.hashgraph.HashgraphGuiConstants;
1211
import com.swirlds.platform.gui.hashgraph.HashgraphGuiSource;
1312
import com.swirlds.platform.gui.hashgraph.HashgraphPictureOptions;
@@ -55,8 +54,7 @@ public class HashgraphPicture extends JPanel {
5554
/** used to store an image when the freeze checkbox is checked */
5655
private BufferedImage image = null;
5756

58-
private RosterMetadata nonExpandedMetadata;
59-
private RosterMetadata expandedMetadata;
57+
private RosterMetadata metadata;
6058

6159
/** used to store coordinates for branched events with a given generation for each branching node */
6260
private final Map<Long, Map<Long, GenerationCoordinates>> nodeIdToBranchIndexToCoordinates = new HashMap<>();
@@ -70,9 +68,8 @@ public HashgraphPicture(final HashgraphGuiSource hashgraphSource, final Hashgrap
7068
}
7169

7270
private void createMetadata() {
73-
if ((expandedMetadata == null || nonExpandedMetadata == null) && hashgraphSource.isReady()) {
74-
expandedMetadata = new RosterMetadata(hashgraphSource.getRoster(), true);
75-
nonExpandedMetadata = new RosterMetadata(hashgraphSource.getRoster(), false);
71+
if (metadata == null && hashgraphSource.isReady()) {
72+
metadata = new RosterMetadata(hashgraphSource.getRoster());
7673
}
7774
}
7875

@@ -93,7 +90,6 @@ public void paintComponent(final Graphics g) {
9390
final FontMetrics fm = g.getFontMetrics();
9491
final Roster roster = hashgraphSource.getRoster();
9592
final int numMem = roster.rosterEntries().size();
96-
final RosterMetadata currentMetadata = options.isExpanded() ? expandedMetadata : nonExpandedMetadata;
9793

9894
List<EventImpl> events;
9995
if (options.displayLatestEvents()) {
@@ -115,15 +111,15 @@ public void paintComponent(final Graphics g) {
115111
.toList();
116112

117113
pictureMetadata = new PictureMetadata(
118-
fm, this.getSize(), currentMetadata, events, hashgraphSource, nodeIdToBranchIndexToCoordinates);
114+
fm, this.getSize(), metadata, events, hashgraphSource, nodeIdToBranchIndexToCoordinates);
119115

120116
selector.setMetadata(pictureMetadata);
121117
selector.setEventsInPicture(events);
122118

123119
g.setColor(Color.BLACK);
124120

125-
for (int i = 0; i < currentMetadata.getNumColumns(); i++) {
126-
final String name = currentMetadata.getLabel(i);
121+
for (int i = 0; i < metadata.getNumColumns(); i++) {
122+
final String name = metadata.getLabel(i);
127123

128124
// gap between columns
129125
final int betweenGap = pictureMetadata.getGapBetweenColumns();
@@ -183,8 +179,7 @@ public void paintComponent(final Graphics g) {
183179
* @param borderColor the color of the border
184180
*/
185181
private void drawBorderAroundEvent(final Graphics g, final int d, final EventImpl event, final Color borderColor) {
186-
final int xPos =
187-
pictureMetadata.xpos(event.getOtherParent() != null ? event.getOtherParent() : event, event) - d / 2;
182+
final int xPos = pictureMetadata.xpos(event) - d / 2;
188183
final int yPos = pictureMetadata.ypos(event) - d / 2;
189184
g.setColor(borderColor);
190185
g.fillOval(xPos - 5, yPos - 5, d + 10, d + 10);
@@ -195,50 +190,38 @@ private void drawLinksToParents(final Graphics g, final EventImpl event) {
195190
final Graphics2D g2d = (Graphics2D) g;
196191
Stroke savedStroke = null;
197192
g.setColor(HashgraphGuiUtils.eventColor(event, options));
198-
boolean selectedLines = selector.isSelected(event);
193+
final boolean selectedLines = selector.isSelected(event);
199194
if (selectedLines) {
200195
g.setColor(Color.MAGENTA);
201196
savedStroke = g2d.getStroke();
202197
g2d.setStroke(new BasicStroke(3));
203198
}
204199

205-
final EventImpl e1 = event.getSelfParent();
206-
EventImpl e2 = event.getOtherParent();
207200
final Roster roster = hashgraphSource.getRoster();
208-
if (e2 != null
209-
&& (RosterUtils.getIndex(roster, e2.getCreatorId().id()) == -1
210-
|| RosterUtils.getIndex(roster, e2.getCreatorId().id())
211-
>= roster.rosterEntries().size())) {
212-
// if the creator of the other parent has been removed,
213-
// treat it as if there is no other parent
214-
e2 = null;
215-
}
216-
217-
if (e1 != null && e1.getNGen() >= pictureMetadata.getMinGen()) {
218-
g.drawLine(
219-
pictureMetadata.xpos(e2, event),
220-
pictureMetadata.ypos(event),
221-
pictureMetadata.xpos(e2, e1),
222-
pictureMetadata.ypos(e1));
223-
224-
if (selectedLines) {
225-
final Color currentColor = g.getColor();
226-
drawBorderAroundEvent(g, d, e1, Color.MAGENTA);
227-
drawEventCircle(g, e1, options, d);
228-
g.setColor(currentColor);
201+
for (final EventImpl parent : event.getAllParents()) {
202+
final long id = parent.getCreatorId().id();
203+
if ((RosterUtils.getIndex(roster, id) == -1
204+
|| RosterUtils.getIndex(roster, id)
205+
>= roster.rosterEntries().size())) {
206+
// if the creator of the other parent has been removed,
207+
// treat it as if there is no other parent
208+
continue;
229209
}
230-
}
231-
if (e2 != null && e2.getNGen() >= pictureMetadata.getMinGen()) {
210+
if (parent.getNGen() < pictureMetadata.getMinGen()) {
211+
// parent is out of range, don't draw line to it
212+
continue;
213+
}
214+
232215
g.drawLine(
233-
pictureMetadata.xpos(e2, event),
216+
pictureMetadata.xpos(event),
234217
pictureMetadata.ypos(event),
235-
pictureMetadata.xpos(event, e2),
236-
pictureMetadata.ypos(e2));
218+
pictureMetadata.xpos(parent),
219+
pictureMetadata.ypos(parent));
237220

238221
if (selectedLines) {
239222
final Color currentColor = g.getColor();
240-
drawBorderAroundEvent(g, d, e2, Color.MAGENTA);
241-
drawEventCircle(g, e2, options, d);
223+
drawBorderAroundEvent(g, d, parent, Color.MAGENTA);
224+
drawEventCircle(g, parent, options, d);
242225
g.setColor(currentColor);
243226
}
244227
}
@@ -250,7 +233,6 @@ private void drawLinksToParents(final Graphics g, final EventImpl event) {
250233

251234
private void drawEventCircle(
252235
final Graphics g, final EventImpl event, final HashgraphPictureOptions options, final int d) {
253-
final Consensus consensus = hashgraphSource.getEventStorage().getConsensus();
254236
final FontMetrics fm = g.getFontMetrics();
255237
final int fa = fm.getMaxAscent();
256238
final int fd = fm.getMaxDescent();
@@ -270,7 +252,7 @@ private void drawEventCircle(
270252
color = HashgraphGuiUtils.eventColor(event, options);
271253
}
272254

273-
final int xPos = pictureMetadata.xpos(e2, event) - d / 2;
255+
final int xPos = pictureMetadata.xpos(event) - d / 2;
274256
final int yPos = pictureMetadata.ypos(event) - d / 2;
275257

276258
if (selector.isSelected(event)) {
@@ -335,7 +317,7 @@ private void drawEventCircle(
335317
if (!s.isEmpty()) {
336318
final Rectangle2D rect = fm.getStringBounds(s, g);
337319

338-
final int x = (int) (pictureMetadata.xpos(e2, event) - rect.getWidth() / 2. - fa / 4.);
320+
final int x = (int) (pictureMetadata.xpos(event) - rect.getWidth() / 2. - fa / 4.);
339321
final int y = (int) (pictureMetadata.ypos(event) + rect.getHeight() / 2. - fd / 2);
340322
g.setColor(HashgraphGuiConstants.LABEL_OUTLINE);
341323
g.drawString(s, x - 1, y - 1);

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/gui/hashgraph/internal/PictureMetadata.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ public int getSideGap() {
9696
return (int) (getGapBetweenColumns() * MARGIN_FRACTION);
9797
}
9898

99-
/** find x position on the screen for event e2 which has an other-parent of e1 (or null if none) */
100-
public int xpos(final EventImpl e1, final EventImpl e2) {
99+
/** find x position on the screen for event e */
100+
public int xpos(final EventImpl e) {
101101
// the gap between left side of screen and leftmost column
102102
// is marginFraction times the gap between columns (and similarly for right side)
103103
final double marginFraction = 0.5;
@@ -106,14 +106,14 @@ public int xpos(final EventImpl e1, final EventImpl e2) {
106106
// gap between leftmost column and left edge (and similar on right)
107107
final int sideGap = (int) (betweenGap * marginFraction);
108108

109-
// find the column for e2 next to the column for e1
110-
int xPos = sideGap + rosterMetadata.mems2col(e1, e2) * betweenGap;
109+
// find the column for e
110+
int xPos = sideGap + rosterMetadata.mems2col(e) * betweenGap;
111111

112-
final GossipEvent e2GossipEvent = e2.getBaseEvent().getGossipEvent();
112+
final GossipEvent e2GossipEvent = e.getBaseEvent().getGossipEvent();
113113

114114
// check if we have a branched event
115115
if (hashgraphSource.getEventStorage().getBranchedEventsMetadata().containsKey(e2GossipEvent)) {
116-
return calculateXPosForBranchedEvent(e2, xPos);
116+
return calculateXPosForBranchedEvent(e, xPos);
117117
}
118118

119119
return xPos;

platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/gui/hashgraph/internal/RosterMetadata.java

Lines changed: 7 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.hedera.hapi.node.state.roster.Roster;
55
import com.swirlds.platform.internal.EventImpl;
66
import edu.umd.cs.findbugs.annotations.NonNull;
7-
import edu.umd.cs.findbugs.annotations.Nullable;
87
import java.util.Objects;
98
import org.hiero.consensus.roster.RosterUtils;
109

@@ -19,20 +18,7 @@ public class RosterMetadata {
1918
/** the labels of all the members */
2019
private final String[] memberLabels;
2120

22-
// the following allow each member to have multiple columns so lines don't cross
23-
/** number of columns (more than number of members if preventCrossings) */
24-
private final int numColumns;
25-
/** mems2col[a][b] = which member-b column is adjacent to some member-a column */
26-
private final int[][] mems2col;
27-
/** col2mems[c][0] = the member for column c, col2mems[c][1] = second member or -1 if none */
28-
private final int[][] col2mems;
29-
30-
/**
31-
* In order to draw this "expanded" hashgraph (where each member has multiple columns and lines don't
32-
* cross), we need several data tables. So fill in four arrays: numMembers, mems2col, col2mems, and
33-
* names, if they haven't already been filled in, or if the number of members has changed.
34-
*/
35-
public RosterMetadata(@NonNull final Roster roster, final boolean expand) {
21+
public RosterMetadata(@NonNull final Roster roster) {
3622
this.roster = Objects.requireNonNull(roster, "roster must not be null");
3723
final int m = roster.rosterEntries().size();
3824
numMembers = m;
@@ -43,54 +29,6 @@ public RosterMetadata(@NonNull final Roster roster, final boolean expand) {
4329
roster.rosterEntries().get(i).nodeId(),
4430
roster.rosterEntries().get(i).weight());
4531
}
46-
47-
// fix corner cases missed by the formulas here
48-
if (numMembers == 1) {
49-
numColumns = 1;
50-
col2mems = new int[][] {{0, -1}};
51-
mems2col = new int[][] {{0}};
52-
return;
53-
} else if (numMembers == 2) {
54-
numColumns = 2;
55-
col2mems = new int[][] {{0, -1}, {1, -1}};
56-
mems2col = new int[][] {{0, 1}, {0, 0}};
57-
return;
58-
}
59-
60-
if (!expand) { // if unchecked so only one column per member, then the arrays are trivial
61-
numColumns = m;
62-
mems2col = new int[m][m];
63-
col2mems = new int[numColumns][2];
64-
for (int i = 0; i < m; i++) {
65-
col2mems[i][0] = i;
66-
col2mems[i][1] = -1;
67-
for (int j = 0; j < m; j++) {
68-
mems2col[i][j] = j;
69-
}
70-
}
71-
return;
72-
}
73-
74-
numColumns = m * (m - 1) / 2 + 1;
75-
mems2col = new int[m][m];
76-
col2mems = new int[numColumns][2];
77-
78-
for (int x = 0; x < m * (m - 1) / 2 + 1; x++) {
79-
final int d1 = ((m % 2) == 1) ? 0 : 2 * ((x - 1) / (m - 1)); // amount to add to x to skip
80-
// columns
81-
col2mems[x][0] =
82-
HashgraphGuiUtils.col2mem(m, d1 + x); // find even m answer by asking for m+1 with skipped cols
83-
col2mems[x][1] = (((m % 2) == 1) || ((x % (m - 1)) > 0) || (x == 0) || (x == m * (m - 1) / 2))
84-
? -1
85-
: HashgraphGuiUtils.col2mem(m, d1 + x + 2);
86-
final int d = ((m % 2) == 1) ? 0 : 2 * (x / (m - 1)); // amount to add to x to skip columns
87-
final int a = HashgraphGuiUtils.col2mem(m, d + x);
88-
final int b = HashgraphGuiUtils.col2mem(m, d + x + 1);
89-
if (x < m * (m - 1) / 2) { // on the last iteration, x+1 is invalid, so don't record it
90-
mems2col[b][a] = x;
91-
mems2col[a][b] = x + 1;
92-
}
93-
}
9432
}
9533

9634
/**
@@ -104,24 +42,15 @@ public int getNumMembers() {
10442
* @return the number of columns to draw
10543
*/
10644
public int getNumColumns() {
107-
return numColumns;
45+
return numMembers;
10846
}
10947

11048
/**
111-
* find the column for e2 next to the column for e1
49+
* find the column for e
11250
*/
113-
public int mems2col(@Nullable final EventImpl e1, @NonNull final EventImpl e2) {
114-
Objects.requireNonNull(e2, "e2 must not be null");
115-
// To support Noncontiguous NodeId in the roster,
116-
// the mems2col array is now based on indexes of NodeIds in the roster.
117-
final int e2Index = RosterUtils.getIndex(roster, e2.getCreatorId().id());
118-
if (e1 != null) {
119-
final int e1Index = RosterUtils.getIndex(roster, e1.getCreatorId().id());
120-
return mems2col[e1Index][e2Index];
121-
}
122-
// there is no e1, so pick one of the e2 columns arbitrarily (next to 0 or 1). If there is only 1
123-
// member, avoid the array out of bounds exception
124-
return mems2col[e2Index == 0 ? getNumColumns() == 1 ? 0 : 1 : 0][e2Index];
51+
public int mems2col(@NonNull final EventImpl e) {
52+
Objects.requireNonNull(e, "e must not be null");
53+
return RosterUtils.getIndex(roster, e.getCreatorId().id());
12554
}
12655

12756
/**
@@ -130,10 +59,6 @@ public int mems2col(@Nullable final EventImpl e1, @NonNull final EventImpl e2) {
13059
* @return the label of the member with the provided index
13160
*/
13261
public String getLabel(final int i) {
133-
if (col2mems[i][1] == -1) {
134-
return "" + memberLabels[col2mems[i][0]];
135-
} else {
136-
return "" + memberLabels[col2mems[i][0]] + "|" + memberLabels[col2mems[i][1]];
137-
}
62+
return memberLabels[i];
13863
}
13964
}

0 commit comments

Comments
 (0)