@@ -26,9 +26,18 @@ import { Order } from 'blockly/python';
2626import {
2727 createModuleOrClassVariableSetterBlock ,
2828 createInstanceVariableSetterBlock } from '../blocks/mrc_set_python_variable' ;
29- import { getAllowedTypesForSetCheck , getOutputCheck } from './utils/python' ;
30- import { VariableGettersAndSetters } from './utils/python_json_types' ;
29+ import {
30+ getAllowedTypesForSetCheck ,
31+ getClassData ,
32+ getModuleData ,
33+ getOutputCheck } from './utils/python' ;
34+ import {
35+ ClassData ,
36+ ModuleData ,
37+ organizeVarDataByType ,
38+ VariableGettersAndSetters } from './utils/python_json_types' ;
3139import * as variable from './utils/variable' ;
40+ import { Editor } from '../editor/editor' ;
3241import { ExtendedPythonGenerator } from '../editor/extended_python_generator' ;
3342import { createFieldDropdown } from '../fields/FieldDropdown' ;
3443import { createFieldNonEditableText } from '../fields/FieldNonEditableText' ;
@@ -50,6 +59,8 @@ export enum VariableKind {
5059const FIELD_MODULE_OR_CLASS_NAME = 'MODULE_OR_CLASS' ;
5160const FIELD_VARIABLE_NAME = 'VAR' ;
5261
62+ const WARNING_ID_VARIABLE_CHANGED = 'variable changed' ;
63+
5364// Variables and functions used for populating the drop down field for the variable names.
5465
5566const PythonVariableGetterNames = Object . create ( null ) ;
@@ -258,7 +269,112 @@ const GET_PYTHON_VARIABLE = {
258269 . setAlign ( Blockly . inputs . Align . RIGHT )
259270 . appendField ( this . mrcSelfLabel ) ;
260271 }
261- }
272+ } ,
273+
274+ /**
275+ * mrcOnLoad is called for each GetPythonVariableBlock when the blocks are loaded in the blockly
276+ * workspace.
277+ */
278+ mrcOnLoad : function ( this : GetPythonVariableBlock , _editor : Editor ) : void {
279+ this . checkBlock ( ) ;
280+ } ,
281+ checkBlock : function ( this : GetPythonVariableBlock ) : void {
282+ const warnings : string [ ] = [ ] ;
283+
284+ switch ( this . mrcVarKind ) {
285+ case VariableKind . MODULE :
286+ this . checkModuleVariable ( warnings ) ;
287+ break ;
288+ case VariableKind . CLASS :
289+ this . checkClassVariable ( warnings ) ;
290+ break ;
291+ case VariableKind . INSTANCE :
292+ this . checkInstanceVariable ( warnings ) ;
293+ break ;
294+ }
295+
296+ if ( warnings . length ) {
297+ // Add a warnings to the block.
298+ const warningText = warnings . join ( '\n\n' ) ;
299+ this . setWarningText ( warningText , WARNING_ID_VARIABLE_CHANGED ) ;
300+ const icon = this . getIcon ( Blockly . icons . IconType . WARNING ) ;
301+ if ( icon ) {
302+ icon . setBubbleVisible ( true ) ;
303+ }
304+ if ( this . rendered ) {
305+ ( this as unknown as Blockly . BlockSvg ) . bringToFront ( ) ;
306+ }
307+ } else {
308+ // Clear the existing warning on the block.
309+ this . setWarningText ( null , WARNING_ID_VARIABLE_CHANGED ) ;
310+ }
311+ } ,
312+ checkModuleVariable : function ( this : GetPythonVariableBlock , warnings : string [ ] ) : void {
313+ // If this block is getting a module variable, check whether the module and variable still
314+ // exist. If the module or variable doesn't exist, put a visible warning on this block.
315+ const moduleName = this . getFieldValue ( FIELD_MODULE_OR_CLASS_NAME ) ;
316+ const moduleData = getModuleData ( moduleName ) ;
317+ if ( moduleData ) {
318+ let foundVariable = false ;
319+ const blockVarName = this . getFieldValue ( FIELD_VARIABLE_NAME ) ;
320+ for ( const varData of moduleData . moduleVariables ) {
321+ if ( blockVarName === varData . name &&
322+ this . mrcVarType === varData . type ) {
323+ foundVariable = true ;
324+ break ;
325+ }
326+ }
327+ if ( ! foundVariable ) {
328+ warnings . push ( Blockly . Msg . WARNING_GET_MODULE_VARIABLE_MISSING_VARIABLE ) ;
329+ }
330+ } else {
331+ warnings . push ( Blockly . Msg . WARNING_GET_MODULE_VARIABLE_MISSING_MODULE ) ;
332+ }
333+ } ,
334+ checkClassVariable : function ( this : GetPythonVariableBlock , warnings : string [ ] ) : void {
335+ // If this block is getting a class variable, check whether the class and variable still
336+ // exist. If the class or variable doesn't exist, put a visible warning on this block.
337+ const className = this . getFieldValue ( FIELD_MODULE_OR_CLASS_NAME ) ;
338+ const classData = getClassData ( className ) ;
339+ if ( classData ) {
340+ let foundVariable = false ;
341+ const blockVarName = this . getFieldValue ( FIELD_VARIABLE_NAME ) ;
342+ for ( const varData of classData . classVariables ) {
343+ if ( blockVarName === varData . name &&
344+ this . mrcVarType === varData . type ) {
345+ foundVariable = true ;
346+ break ;
347+ }
348+ }
349+ if ( ! foundVariable ) {
350+ warnings . push ( Blockly . Msg . WARNING_GET_CLASS_VARIABLE_MISSING_VARIABLE ) ;
351+ }
352+ } else {
353+ warnings . push ( Blockly . Msg . WARNING_GET_CLASS_VARIABLE_MISSING_CLASS ) ;
354+ }
355+ } ,
356+ checkInstanceVariable : function ( this : GetPythonVariableBlock , warnings : string [ ] ) : void {
357+ // If this block is getting an instance variable, check whether the class and variable still
358+ // exist. If the class or variable doesn't exist, put a visible warning on this block.
359+ const className = this . getFieldValue ( FIELD_MODULE_OR_CLASS_NAME ) ;
360+ const classData = getClassData ( className ) ;
361+ if ( classData ) {
362+ let foundVariable = false ;
363+ const blockVarName = this . getFieldValue ( FIELD_VARIABLE_NAME ) ;
364+ for ( const varData of classData . instanceVariables ) {
365+ if ( blockVarName === varData . name &&
366+ this . mrcVarType === varData . type ) {
367+ foundVariable = true ;
368+ break ;
369+ }
370+ }
371+ if ( ! foundVariable ) {
372+ warnings . push ( Blockly . Msg . WARNING_GET_INSTANCE_VARIABLE_MISSING_VARIABLE ) ;
373+ }
374+ } else {
375+ warnings . push ( Blockly . Msg . WARNING_GET_INSTANCE_VARIABLE_MISSING_CLASS ) ;
376+ }
377+ } ,
262378} ;
263379
264380export const setup = function ( ) {
@@ -303,20 +419,25 @@ export const pythonFromBlock = function(
303419// Functions used for creating blocks for the toolbox.
304420
305421export function addModuleVariableBlocks (
306- moduleName : string ,
307- varsByType : { [ key : string ] : VariableGettersAndSetters } ,
422+ moduleData : ModuleData ,
308423 contents : toolboxItems . ContentsType [ ] ) {
309- addModuleOrClassVariableBlocks (
310- VariableKind . MODULE , moduleName , moduleName , varsByType , contents ) ;
424+ if ( moduleData . moduleVariables . length ) {
425+ const varsByType : { [ key : string ] : VariableGettersAndSetters } =
426+ organizeVarDataByType ( moduleData . moduleVariables ) ;
427+ addModuleOrClassVariableBlocks (
428+ VariableKind . MODULE , moduleData . moduleName , moduleData . moduleName , varsByType , contents ) ;
429+ }
311430}
312431
313432export function addClassVariableBlocks (
314- importModule : string ,
315- className : string ,
316- varsByType : { [ key : string ] : VariableGettersAndSetters } ,
433+ classData : ClassData ,
317434 contents : toolboxItems . ContentsType [ ] ) {
318- addModuleOrClassVariableBlocks (
319- VariableKind . CLASS , importModule , className , varsByType , contents ) ;
435+ if ( classData . classVariables . length ) {
436+ const varsByType : { [ key : string ] : VariableGettersAndSetters } =
437+ organizeVarDataByType ( classData . classVariables ) ;
438+ addModuleOrClassVariableBlocks (
439+ VariableKind . CLASS , classData . moduleName , classData . className , varsByType , contents ) ;
440+ }
320441}
321442
322443function addModuleOrClassVariableBlocks (
@@ -334,7 +455,7 @@ function addModuleOrClassVariableBlocks(
334455 contents . push ( getterBlock ) ;
335456 if ( variableGettersAndSetters . varNamesForSetter . includes ( varName ) ) {
336457 const setterBlock = createModuleOrClassVariableSetterBlock (
337- VariableKind . CLASS , importModule , moduleOrClassName , varType , varName ) ;
458+ varKind , importModule , moduleOrClassName , varType , varName ) ;
338459 contents . push ( setterBlock ) ;
339460 }
340461 }
@@ -360,18 +481,21 @@ function createModuleOrClassVariableGetterBlock(
360481}
361482
362483export function addInstanceVariableBlocks (
363- className : string ,
364- varsByType : { [ key : string ] : VariableGettersAndSetters } ,
484+ classData : ClassData ,
365485 contents : toolboxItems . ContentsType [ ] ) {
366- for ( const varType in varsByType ) {
367- const variableGettersAndSetters = varsByType [ varType ] ;
368- for ( let i = 0 ; i < variableGettersAndSetters . varNamesForGetter . length ; i ++ ) {
369- const varName = variableGettersAndSetters . varNamesForGetter [ i ] ;
370- const getterBlock = createInstanceVariableGetterBlock ( className , varType , varName ) ;
371- contents . push ( getterBlock ) ;
372- if ( variableGettersAndSetters . varNamesForSetter . includes ( varName ) ) {
373- const setterBlock = createInstanceVariableSetterBlock ( className , varType , varName ) ;
374- contents . push ( setterBlock ) ;
486+ if ( classData . instanceVariables . length ) {
487+ const varsByType : { [ key : string ] : VariableGettersAndSetters } =
488+ organizeVarDataByType ( classData . instanceVariables ) ;
489+ for ( const varType in varsByType ) {
490+ const variableGettersAndSetters = varsByType [ varType ] ;
491+ for ( let i = 0 ; i < variableGettersAndSetters . varNamesForGetter . length ; i ++ ) {
492+ const varName = variableGettersAndSetters . varNamesForGetter [ i ] ;
493+ const getterBlock = createInstanceVariableGetterBlock ( classData . className , varType , varName ) ;
494+ contents . push ( getterBlock ) ;
495+ if ( variableGettersAndSetters . varNamesForSetter . includes ( varName ) ) {
496+ const setterBlock = createInstanceVariableSetterBlock ( classData . className , varType , varName ) ;
497+ contents . push ( setterBlock ) ;
498+ }
375499 }
376500 }
377501 }
0 commit comments