Skip to content

Commit ff7c968

Browse files
authored
In common_storage.ts, added function makeUniqueName. Modified makeUploadProjectName to call makeUniqueName. (wpilibsuite#185)
In editor.ts, added methods getCurrentModuleType and getEventHandlerNames. Removed fields methodsCategory and eventsCategory, but still create all custom toolbox categories in the constructor. In mrc_event_handler.ts, renamed function getHasEventHandler to getHasAnyEnabledEventHandlers. Added function getEventHandlerNames. In mrc_event.ts, modified createCustomEventBlock to take the event name as a parameter. In hardware_category.ts, renamed functions that return a category to be named get...Category instead of get...Blocks. Make RobotEventsCategory a custom category with a flyout callback. In event_category, removed field currentModule and method setCurrentModule. Make a unique name for creating a new event. In methods_category, removed field currentModule and method setCurrentModule. Use editor.getCurrentModuleType() instead.
1 parent 35f4fae commit ff7c968

File tree

8 files changed

+122
-87
lines changed

8 files changed

+122
-87
lines changed

src/blocks/mrc_event.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,11 @@ export const pythonFromBlock = function (
238238

239239
// Functions used for creating blocks for the toolbox.
240240

241-
export function createCustomEventBlock(): toolboxItems.Block {
241+
export function createCustomEventBlock(name: string): toolboxItems.Block {
242242
const extraState: EventExtraState = {
243243
params: [],
244244
};
245245
const fields: {[key: string]: any} = {};
246-
fields[FIELD_EVENT_NAME] = 'my_event';
246+
fields[FIELD_EVENT_NAME] = name;
247247
return new toolboxItems.Block(BLOCK_NAME, extraState, fields, null);
248248
}

src/blocks/mrc_event_handler.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,6 @@ export function pythonFromBlock(
226226
const blocklyName = `${sender}_${eventName}`;
227227
const funcName = generator.getProcedureName(blocklyName);
228228

229-
// TODO(lizlooney): if the user adds multiple event handlers for the same event
230-
// name, we need to make the event handler function names unique.
231-
232229
let xfix1 = '';
233230
if (generator.STATEMENT_PREFIX) {
234231
xfix1 += generator.injectId(generator.STATEMENT_PREFIX, block);
@@ -323,8 +320,16 @@ function createRobotEventHandlerBlock(
323320

324321
// Misc
325322

326-
export function getHasEventHandler(workspace: Blockly.Workspace): boolean {
323+
export function getHasAnyEnabledEventHandlers(workspace: Blockly.Workspace): boolean {
327324
return workspace.getBlocksByType(BLOCK_NAME).filter(block => {
328325
return block.isEnabled();
329326
}).length > 0;
330327
}
328+
329+
export function getEventHandlerNames(workspace: Blockly.Workspace, names: string[]): void {
330+
// Here we collect the event names of the event handlers in the given
331+
// workspace, regardless of whether the event handler is enabled.
332+
workspace.getBlocksByType(BLOCK_NAME).forEach(block => {
333+
names.push(block.getFieldValue(FIELD_EVENT_NAME));
334+
});
335+
}

src/editor/editor.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import * as mechanismComponentHolder from '../blocks/mrc_mechanism_component_hol
3131
//import { testAllBlocksInToolbox } from '../toolbox/toolbox_tests';
3232
import { MethodsCategory } from '../toolbox/methods_category';
3333
import { EventsCategory } from '../toolbox/event_category';
34+
import { RobotEventsCategory } from '../toolbox/hardware_category';
3435
import { getToolboxJSON } from '../toolbox/toolbox';
3536

3637
const EMPTY_TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = {
@@ -44,8 +45,6 @@ export class Editor {
4445
private blocklyWorkspace: Blockly.WorkspaceSvg;
4546
private generatorContext: GeneratorContext;
4647
private storage: commonStorage.Storage;
47-
private methodsCategory: MethodsCategory;
48-
private eventsCategory: EventsCategory;
4948
private currentModule: commonStorage.Module | null = null;
5049
private modulePath: string = '';
5150
private robotPath: string = '';
@@ -59,8 +58,10 @@ export class Editor {
5958
this.blocklyWorkspace = blocklyWorkspace;
6059
this.generatorContext = generatorContext;
6160
this.storage = storage;
62-
this.methodsCategory = new MethodsCategory(blocklyWorkspace);
63-
this.eventsCategory = new EventsCategory(blocklyWorkspace);
61+
// Create the custom toolbox categories so they register their flyout callbacks.
62+
new MethodsCategory(blocklyWorkspace);
63+
new EventsCategory(blocklyWorkspace);
64+
new RobotEventsCategory(blocklyWorkspace);
6465
}
6566

6667
private onChangeWhileLoading(event: Blockly.Events.Abstract) {
@@ -107,8 +108,6 @@ export class Editor {
107108
public async loadModuleBlocks(currentModule: commonStorage.Module | null) {
108109
this.generatorContext.setModule(currentModule);
109110
this.currentModule = currentModule;
110-
this.methodsCategory.setCurrentModule(currentModule);
111-
this.eventsCategory.setCurrentModule(currentModule);
112111

113112
if (currentModule) {
114113
this.modulePath = currentModule.modulePath;
@@ -201,6 +200,13 @@ export class Editor {
201200
return this.getModuleContentText() !== this.moduleContentText;
202201
}
203202

203+
public getCurrentModuleType(): string {
204+
if (this.currentModule) {
205+
return this.currentModule.moduleType;
206+
}
207+
return commonStorage.MODULE_TYPE_UNKNOWN;
208+
}
209+
204210
private getModuleContentText(): string {
205211
if (!this.currentModule) {
206212
throw new Error('getModuleContentText: this.currentModule is null.');
@@ -258,6 +264,12 @@ export class Editor {
258264
return events;
259265
}
260266

267+
public getEventHandlerNamesFromWorkspace(): string[] {
268+
const names: string[] = [];
269+
eventHandler.getEventHandlerNames(this.blocklyWorkspace, names);
270+
return names;
271+
}
272+
261273
public async saveBlocks() {
262274
const moduleContentText = this.getModuleContentText();
263275
try {

src/editor/extended_python_generator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export class ExtendedPythonGenerator extends PythonGenerator {
145145

146146
this.ports = Object.create(null);
147147
this.hasHardware = mechanismContainerHolder.getHardwarePorts(this.workspace, this.ports);
148-
this.hasEventHandler = eventHandler.getHasEventHandler(this.workspace);
148+
this.hasEventHandler = eventHandler.getHasAnyEnabledEventHandlers(this.workspace);
149149

150150
const code = super.workspaceToCode(workspace);
151151

src/storage/common_storage.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -629,25 +629,10 @@ export function getClassNameForModule(moduleType: string, moduleName: string) {
629629
* Make a unique project name for an uploaded project.
630630
*/
631631
export function makeUploadProjectName(
632-
uploadFileName: string, existingProjectNames: string[]): string {
632+
uploadFileName: string, existingProjectNames: string[]): string {
633633
const preferredName = uploadFileName.substring(
634634
0, uploadFileName.length - UPLOAD_DOWNLOAD_FILE_EXTENSION.length);
635-
let name = preferredName; // No suffix.
636-
let suffix = 0;
637-
while (true) {
638-
let nameClash = false;
639-
for (const existingProjectName of existingProjectNames) {
640-
if (name == existingProjectName) {
641-
nameClash = true;
642-
break;
643-
}
644-
}
645-
if (!nameClash) {
646-
return name;
647-
}
648-
suffix++;
649-
name = preferredName + suffix;
650-
}
635+
return makeUniqueName(preferredName, existingProjectNames);
651636
}
652637

653638
/**
@@ -704,3 +689,25 @@ export function _processUploadedModule(
704689
const moduleContentText = moduleContent.getModuleContentText();
705690
return [moduleName, moduleType, moduleContentText];
706691
}
692+
693+
/**
694+
* Makes a unique name given a list of existing names
695+
*/
696+
export function makeUniqueName(preferredName: string, existingNames: string[]): string {
697+
let name = preferredName; // No suffix.
698+
let suffix = 0;
699+
while (true) {
700+
let nameClash = false;
701+
for (const existingName of existingNames) {
702+
if (name == existingName) {
703+
nameClash = true;
704+
break;
705+
}
706+
}
707+
if (!nameClash) {
708+
return name;
709+
}
710+
suffix++;
711+
name = preferredName + suffix;
712+
}
713+
}

src/toolbox/event_category.ts

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,32 +38,31 @@ export const getCategory = () => ({
3838
});
3939

4040
export class EventsCategory {
41-
private currentModule: commonStorage.Module | null = null;
42-
4341
constructor(blocklyWorkspace: Blockly.WorkspaceSvg) {
4442
blocklyWorkspace.registerToolboxCategoryCallback(CUSTOM_CATEGORY_EVENTS, this.eventsFlyout.bind(this));
4543
}
4644

47-
public setCurrentModule(currentModule: commonStorage.Module | null) {
48-
this.currentModule = currentModule;
49-
}
50-
5145
public eventsFlyout(workspace: Blockly.WorkspaceSvg) {
5246
const contents: toolboxItems.ContentsType[] = [];
5347

54-
// Add a block that lets the user define a new event.
55-
contents.push(
56-
{
57-
kind: 'label',
58-
text: 'Custom Events',
59-
},
60-
createCustomEventBlock()
61-
);
62-
63-
// Get blocks for firing methods defined in the current workspace.
6448
const editor = Editor.getEditorForBlocklyWorkspace(workspace);
6549
if (editor) {
6650
const eventsFromWorkspace = editor.getEventsFromWorkspace();
51+
const eventNames: string[] = [];
52+
eventsFromWorkspace.forEach(event => {
53+
eventNames.push(event.name);
54+
});
55+
56+
// Add a block that lets the user define a new event.
57+
contents.push(
58+
{
59+
kind: 'label',
60+
text: 'Custom Events',
61+
},
62+
createCustomEventBlock(commonStorage.makeUniqueName('my_event', eventNames))
63+
);
64+
65+
// Get blocks for firing methods defined in the current workspace.
6766
addFireEventBlocks(eventsFromWorkspace, contents);
6867
}
6968

@@ -73,4 +72,4 @@ export class EventsCategory {
7372

7473
return toolboxInfo;
7574
}
76-
}
75+
}

src/toolbox/hardware_category.ts

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,31 @@ export function getHardwareCategory(currentModule: commonStorage.Module): toolbo
3434
kind: 'category',
3535
name: Blockly.Msg['MRC_CATEGORY_HARDWARE'],
3636
contents: [
37-
getRobotMechanismsBlocks(currentModule),
38-
getComponentsBlocks(false),
37+
getRobotMechanismsCategory(currentModule),
38+
getComponentsCategory(false),
3939
]
4040
};
4141
}
4242
if (currentModule.moduleType === commonStorage.MODULE_TYPE_MECHANISM) {
43-
return getComponentsBlocks(true);
43+
return getComponentsCategory(true);
4444
}
4545
if (currentModule.moduleType === commonStorage.MODULE_TYPE_OPMODE) {
4646
return {
4747
kind: 'category',
4848
name: Blockly.Msg['MRC_CATEGORY_ROBOT'],
4949
contents: [
50-
getRobotMechanismsBlocks(currentModule),
51-
getRobotComponentsBlocks(),
52-
getRobotMethodsBlocks(),
53-
getRobotEventsBlocks(),
50+
getRobotMechanismsCategory(currentModule),
51+
getRobotComponentsCategory(),
52+
getRobotMethodsCategory(),
53+
getRobotEventsCategory(),
5454
]
5555
};
5656
}
5757
throw new Error('currentModule.moduleType has unexpected value: ' + currentModule.moduleType)
5858
}
5959

60-
function getRobotMechanismsBlocks(currentModule: commonStorage.Module): toolboxItems.Category {
61-
// getRobotMechanismsBlocks is called when the user is editing the robot or an opmode.
60+
function getRobotMechanismsCategory(currentModule: commonStorage.Module): toolboxItems.Category {
61+
// getRobotMechanismsCategory is called when the user is editing the robot or an opmode.
6262
// If the user is editing the robot, it allows the user to add a mechanism to
6363
// the robot or use an existing mechanism.
6464
// If the user is editing an opmode, it allows the user to use a mechanism that
@@ -211,8 +211,8 @@ function getRobotMechanismsBlocks(currentModule: commonStorage.Module): toolboxI
211211
};
212212
}
213213

214-
function getRobotComponentsBlocks(): toolboxItems.Category {
215-
// getRobotComponentsBlocks is called when the user is editing an opmode.
214+
function getRobotComponentsCategory(): toolboxItems.Category {
215+
// getRobotComponentsCategory is called when the user is editing an opmode.
216216
// It allows the user to use a component that was previously added to the Robot.
217217

218218
const contents: toolboxItems.ContentsType[] = [];
@@ -242,8 +242,8 @@ function getRobotComponentsBlocks(): toolboxItems.Category {
242242
};
243243
}
244244

245-
function getRobotMethodsBlocks(): toolboxItems.Category {
246-
// getRobotMethodsBlocks is called when the user is editing an opmode.
245+
function getRobotMethodsCategory(): toolboxItems.Category {
246+
// getRobotMethodsCategory is called when the user is editing an opmode.
247247
// It allows the user to use methods there previously defined in the Robot.
248248

249249
const contents: toolboxItems.ContentsType[] = [];
@@ -266,8 +266,8 @@ function getRobotMethodsBlocks(): toolboxItems.Category {
266266
};
267267
}
268268

269-
function getComponentsBlocks(hideParams : boolean): toolboxItems.Category {
270-
// getComponentsBlocks is called when the user is editing the robot or a
269+
function getComponentsCategory(hideParams : boolean): toolboxItems.Category {
270+
// getComponentsCategory is called when the user is editing the robot or a
271271
// mechanism. It allows the user to add a component or use an existing component.
272272

273273
const contents: toolboxItems.ContentsType[] = [];
@@ -303,26 +303,41 @@ function getComponentsBlocks(hideParams : boolean): toolboxItems.Category {
303303
};
304304
}
305305

306-
function getRobotEventsBlocks(): toolboxItems.Category {
307-
// getRobotEventsBlocks is called when the user is editing an opmode.
308-
// It allows the user to create event handlers for events previously defined in the Robot.
306+
const CUSTOM_CATEGORY_ROBOT_EVENTS = 'ROBOT_EVENTS';
309307

310-
const contents: toolboxItems.ContentsType[] = [];
308+
// The robot events category is shown when the user is editing an opmode.
309+
// It allows the user to create event handlers for events previously defined in the Robot.
310+
const getRobotEventsCategory = () => ({
311+
kind: 'category',
312+
name: Blockly.Msg['MRC_CATEGORY_EVENTS'],
313+
custom: CUSTOM_CATEGORY_ROBOT_EVENTS,
314+
});
315+
316+
export class RobotEventsCategory {
317+
constructor(blocklyWorkspace: Blockly.WorkspaceSvg) {
318+
blocklyWorkspace.registerToolboxCategoryCallback(CUSTOM_CATEGORY_ROBOT_EVENTS, this.robotEventsFlyout.bind(this));
319+
}
320+
321+
public robotEventsFlyout(workspace: Blockly.WorkspaceSvg) {
322+
const contents: toolboxItems.ContentsType[] = [];
323+
324+
// Get the list of events from the robot and add the blocks for handling events.
311325

312-
// Get the list of events from the robot and add the blocks for calling the
313-
// robot functions.
314-
const workspace = Blockly.getMainWorkspace();
315-
if (workspace) {
316326
const editor = Editor.getEditorForBlocklyWorkspace(workspace);
317327
if (editor) {
318328
const eventsFromRobot = editor.getEventsFromRobot();
319-
addRobotEventHandlerBlocks(eventsFromRobot, contents);
329+
// Remove events if there is already a corresponding handler in the workspace.
330+
const eventHandlerNames = editor.getEventHandlerNamesFromWorkspace();
331+
const eventsToShow = eventsFromRobot.filter(event => {
332+
return !eventHandlerNames.includes(event.name);
333+
});
334+
addRobotEventHandlerBlocks(eventsToShow, contents);
320335
}
321-
}
322336

323-
return {
324-
kind: 'category',
325-
name: Blockly.Msg['MRC_CATEGORY_EVENTS'],
326-
contents,
327-
};
337+
const toolboxInfo = {
338+
contents: contents,
339+
};
340+
341+
return toolboxInfo;
342+
}
328343
}

0 commit comments

Comments
 (0)