Skip to content

Annotations with context and priority

Compare
Choose a tag to compare
@dionisiydk dionisiydk released this 11 Dec 16:37
· 55 commits to master since this release
5c6a1f5

Contextual annotations

Now annotations can be defined with context where they can be used.
Imaging that you want annotate command classes with shortcuts for specific widgets:

MyCommand class>>widget1ShortcutAnnotation
   <classAnnotation>
   ShortcutAnnotation using: $r meta for: MyWidgetClass1

MyCommand class>> widget2ShortcutAnnotation
   <classAnnotation>
   ShortcutAnnotation using: $t meta for: MyWidgetClass2

Then you can query all shortcuts which should be active for concrete widget:

ShortcutAnnotation activeAnnotationsInContext: aMyWidgetInstance

Declaring context using classes is simplest case. Underhood class is converted to AnnotationContext instance using #asAnnotationContext message. Then during annotations lookup it simply asks #isKindOf: for given context instances.
For advanced scenarios you can implement more complex annotation context and define specific DSL to use them for annotations and queries.

Any annotation class can redefine meaning of active annotation with extra conditions. For example it can delegate decision to annotated class itself:

ShortcutAnnotation >>isActiveInContext: aMyWidgetInstance
	^(super isActiveInContext: aMyWidgetInstance)
			and: [annotatedClass canBeUsedInWidget: aMyWidgetInstance]

But for some scenarios you may need to query annotations according to original "active" definition despite of extra conditions. For such cases the "visibility" of annotation is introduced: the annotation is visible if it is declared for given context:

ClassAnnotation>>isVisibleInContext: aContext
	^activeContext describes: aContext

So the visible annotation is not necessary active. But active annotation is always visible in given context:

ClassAnnotation>>isActiveInContext: aContext
	^self isVisibleInContext: aContext

Imaging that you want annotate commands with context menu information (where they should be accessible). In that case disabled menu items can represent commands which are visible for application but not active in given context (because selected items is not appropriate for them).

To query visible annotations where are few methods:

ContextMenuAnnotation visibleInstancesInContext: anUserContext
ContextMenuAnnotation visibleInstancesInContext: anUserContext do: aBlock

Annotation priority

For particular scenarios it can be important to define order in which annotations are processed.
For context menu example this order can be used to sort menu items.
For shortcut example it allows override existing shortcuts of application.

So concept of annotation priority was introduced for this reason. Any annotation can define it. Annotation with greater priority value is processed first by enumeration methods:

  • registeredInstancesDo:
  • activeInstancesInContext:do:
  • visibleInstancesInContext:do:

Priority is holden as instance variable. So you can specify it in declaration method:

MyCommand class>>shortcutAnnotation
   <classAnnotation>
   (ShortcutAnnotation using: $r meta for: MyWidgetClass) 
       priority: 1000

Of course for your annotation you can add methods which are suitable for your domain.

In some cases you would need override order in which annotations should be sorted. For example, you can say that command with greater priority should be at the end of menu.
For such cases you can override class side method #createContainerForRegistry:

MySpecificAnnotation class>>createContainerForRegistry
     ^SortedCollection sortBlock: #priority ascending

Forbidden annotation

Annotation can forbid annotating of particular classes. For example it can forbid abstract classes.

MySpecificAnnotation>>isForbidden
      ^annotatedClass isAbstract

Such annotations will not be added to the registry and forbidden classes will not include them