-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathBlockLink.java
More file actions
217 lines (194 loc) · 7.75 KB
/
Copy pathBlockLink.java
File metadata and controls
217 lines (194 loc) · 7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the MIT License https://raw.github.com/mit-cml/app-inventor/master/mitlicense.txt
package openblocks.codeblocks;
import openblocks.renderable.RenderableBlock;
import openblocks.workspace.Workspace;
import openblocks.workspace.WorkspaceEvent;
import openblocks.yacodeblocks.FeedbackReporter;
import openblocks.yacodeblocks.WorkspaceControllerHolder;
import openblocks.codeblockutil.SoundManager;
import openblocks.codeblockutil.Sound;
/**
* A class that stores information about a potential block connection.
*
* Each BlockLink instance stores the Block IDs of the "plug" and "socket"
* and two block connectors, one from each, with a possible connection.
*
* In block linking, a "plug" can be either a before or plug connector,
* while a "socket" can either be a after or socket connector. Plugs can only
* connect to other socket connectors, while before connectors can connect to
* after and command socket connectors.
*/
public class BlockLink {
private static Sound clickSound;
private Long plugBlockID;
private Long socketBlockID;
private Long lastPlugBlockID;
private BlockConnector plug;
private BlockConnector socket;
//information regarding the last BlockLink instance
private static Long lastPlugID;
private static Long lastSocketID;
private static BlockConnector lastPlug;
private static BlockConnector lastSocket;
private static BlockLink lastLink;
/**
* Private constructor to (somewhat) limit object creation
* @param block1
* @param block2
* @param socket1
* @param socket2
*/
private BlockLink(Block block1, Block block2, BlockConnector socket1, BlockConnector socket2) {
boolean isPlug1 = (block1.hasPlug() && block1.getPlug() == socket1) ||
(block1.hasBeforeConnector() && block1.getBeforeConnector() == socket1);
boolean isPlug2 = (block2.hasPlug() && block2.getPlug() == socket2) ||
(block2.hasBeforeConnector() && block2.getBeforeConnector() == socket2);
if (!(isPlug1 ^ isPlug2)) {
// bad news... there should be only one plug
assert(false);
} else if (isPlug1){
plug = socket1;
socket = socket2;
plugBlockID = block1.getBlockID();
socketBlockID = block2.getBlockID();
} else {
plug = socket2;
socket = socket1;
plugBlockID = block2.getBlockID();
socketBlockID = block1.getBlockID();
}
lastPlugID = plugBlockID;
lastSocketID = socketBlockID;
lastPlug = plug;
lastSocket = socket;
lastPlugBlockID = Block.NULL;
}
static{
//load the sound for connecting blocks, but only once
try{
if (!WorkspaceControllerHolder.isHeadless()) {
clickSound = SoundManager.loadSound("/openblocks/codeblocks/click.wav");
}
} catch (Exception e) {
e.printStackTrace();
FeedbackReporter.showInfoMessage("Error initializing sounds. Continuing...");
}
}
/**
*
* @return the BlockConnector representing the plug side of the link
*/
public BlockConnector getPlug() {
return plug;
}
/**
*
* @return the BlockConnector representing the socket side of the link
*/
public BlockConnector getSocket() {
return socket;
}
/**
*
* @return the Block ID of the Block containing the plug side of the link
*/
public Long getPlugBlockID() {
return plugBlockID;
}
/**
*
* @return the Block ID of the Block containing the socket side of the link
*/
public Long getSocketBlockID() {
return socketBlockID;
}
public Long getLastBlockID() {
return lastPlugBlockID;
}
/**
* This method actually connects the two blocks stored in this BlockLink object.
*
*/
public void connect() {
/* Make sure to disconnect any connections that are going to be overwritten
* by this new connection. For example, if inserting a block between two
* others, make sure to break that original link.*/
if (socket.hasBlock()) {
// save the ID of the block previously attached to (in) this
// socket. This is used by insertion rules to re-link the replaced
// block to the newly-inserted block.
lastPlugBlockID = socket.getBlockID();
// break the link between the socket block and the block in that socket
Block plugBlock = Block.getBlock(lastPlugBlockID);
BlockConnector plugBlockPlug = BlockLinkChecker.getPlugEquivalent(plugBlock);
if (plugBlockPlug != null && plugBlockPlug.hasBlock()) {
Block socketBlock = Block.getBlock(plugBlockPlug.getBlockID());
BlockLink link = BlockLink.getBlockLink(plugBlock, socketBlock, plugBlockPlug, socket);
link.disconnect();
//don't tell the block about the disconnect like we would normally do, because
// we don't actually want it to have a chance to remove any expandable sockets
// since the inserted block will be filling whatever socket was vacated by this
// broken link.
// NOTIFY WORKSPACE LISTENERS OF DISCONNECTION (not sure if this is great because the
// connection is immediately replaced)
Workspace.getInstance().notifyListeners(new WorkspaceEvent(
RenderableBlock.getRenderableBlock(socketBlock.getBlockID()).getParentWidget(),
link, WorkspaceEvent.BLOCKS_DISCONNECTED));
}
}
if (plug.hasBlock()) {
// in the case of insertion, breaking the link above will mean that
// the plug shouldn't be connected by the time we reach here. This
// exception will only be thrown if the plug is connected even
// after any insertion-esq links were broken above
throw new RuntimeException("trying to link a plug that's already connected somewhere.");
}
// actually form the connection
plug.setConnectorBlockID(socketBlockID);
socket.setConnectorBlockID(plugBlockID);
// Notify renderable blocks of connection so it can redraw with stretching
// and remove complaints.
RenderableBlock socketRB = RenderableBlock.getRenderableBlock(socketBlockID);
RenderableBlock plugRB = RenderableBlock.getRenderableBlock(plugBlockID);
socketRB.blockConnected(socket, plugBlockID);
Block.getBlock(socketBlockID).removeComplaint(
ComplaintDepartment.EMPTY_SOCKET);
Block.getBlock(plugBlockID).removeComplaint(
ComplaintDepartment.UNATTACHED);
if(clickSound != null){
//System.out.println("playing click sound");
clickSound.play();
}
}
public void disconnect() {
plug.setConnectorBlockID(Block.NULL);
socket.setConnectorBlockID(Block.NULL);
}
/**
* Factory method for creating BlockLink objects
* @param block1 one of the Block objects in the potential link
* @param block2 the other Block object
* @param socket1 the BlockConnector from block1
* @param socket2 the BlockConnector from block2
* @return a BlockLink object storing the potential link between block1 and block2
*/
public static BlockLink getBlockLink(Block block1, Block block2, BlockConnector socket1,
BlockConnector socket2) {
// If these arguments are the same as the last call to getBlockLink, return the old object
// instead of creating a new one
if (!((block1.getBlockID().equals(lastPlugID) && block2.getBlockID().equals(lastSocketID) &&
socket1.equals(lastPlug) && socket2.equals(lastSocket)) ||
(block2.getBlockID().equals(lastPlugID) && block1.getBlockID().equals(lastSocketID) &&
socket2.equals(lastPlug) && socket1.equals(lastSocket)))) {
lastLink = new BlockLink(block1, block2, socket1, socket2);
}
return lastLink;
}
@Override
public String toString() {
return "BlockLink(Plug: " + plugBlockID + ", Socket: " + socketBlockID + ")";
}
}