Due to the special nature of Collaboration Projects, conventional methods (i.e. hooks) to trigger processes could be ineffective.
In this article we'll discuss other methods you can use to trigger processes from defined events.
EventObserver
EventObservers
are classes that calls its event()
method according to some specific preset events.
Each of these EventObservers
are tied to a set of events and an owner in cm/core/collabG3/CollViewModel.cm.
ProjectViewModel Observers
Similarly to switchWorldHook()
, an Active Project Observer can be set to trigger processes whenever:
- Loading a Collaboration Project.
- Loading from a Collaboration Project to a normal drawing.
Wherever you need the trigger, simply extend from EventObserver
an Active Project Observer.
In this example, suppose there is a dialog that should be automatically closed if a Project is loaded, you can implement it as how cm/core/collabG3/ui/collReleasesCommentDialog.cm does it.
package cm.core.collabG3.ui; ... /** * Collaboration releases comment file dialog. */ package class CollReleasesCommentDialog extends ModalDialog { .... /** * Constructor. */ package constructor(Window parent) { .... projectViewModel.addActiveProjectObserver(this, CollActiveProjectObserver(this)); ....
}
...
} /*************************************************************************** * Observers ***************************************************************************/ /** * Project observer. */ private class CollActiveProjectObserver extends EventObserver { /** * Dialog */ private CollReleasesCommentDialog _dialog; /** * Crete new. */ private constructor(CollReleasesCommentDialog dialog) { super(class#":"#dialog); _dialog = dialog; } /** * On observed event. */ public void event() { if (_dialog.valid) _dialog.close(); } }
Wherever you want the trigger to happen, add an Active Project Observer by:projectViewModel.addActiveProjectObserver(Object owner, EventObserver observer);
projectViewModel
returns the CollProjectViewModel
object in charge of managing all the Projects of a user. Because it has this oversight, it can trigger processes of all EventObserver
added into it.
Looking at the implementation of our EventObserver
, the constructor returns a super
using a unique string to identify this class, while also saving the dialog object in the class.
Then when a collaboration project is loaded, event()
is called, and the dialog closes.
Within CollProjectViewModel
, there is also another observer:
projectViewModel.addProjectObserver(Object owner, EventObserver observer);
This triggers when:
- the Project is updated.
- customers permissions are updated.
CollCollectionViewModel Observers
Like ProjectViewModel
, CollCollectionViewModel
is a class to hold and manage observers, but it is responsible for changes within the Project instead.
To add an EventObserver, simply use:
collectionViewModel.add?????Observer(Object owner, EventObserver observer);
Where a type of observer corresponds to its trigger type and method name:
Method Name | Triggers |
addFilesObserver | File dependencies updated. |
addActiveSectionObserver | Active section is changed. |
addActivePaperSectionObserver | Active paper section is changed. |
addFileSyncObserver | New files are downloaded. Files are pushed to the server. |
addProjectInfoObserver | ProjectInfo is changed |
GroupStatus Observers
This Observer is implemented in the core code to check if a project is offline/online, or if it's connecting. To access this, simply use:
mainCollCollection.isProjectOffline();
ormainCollCollection.isProjectConnecting();
EventViewer
Unlike EventObserver
which has events predefined and managed by CollViewModel
, EventViewer
is a wider solution triggered from a Session
, World
, or Space
's event()
method.
Registering An EventViewer
To register your own EventViewer
, simply:
- Find out which event you want to trigger a process from,
- Then find out if the event belongs in
Session
,World
, orSpace
. - Finally, register your own
EventViewer
onto theSession
,World
, orSpace
.
For example:
private class ExampleExtension extends Extension { /** * Start. Place Init code here. */ public void start(ExtensionEnv env) { initViewers(); super(env); } }
/** * Init viewers. */ package void initViewers() { if (session) session.registerEventViewer(ExampleSessionEventViewer()); }
Now ExampleSessionEventViewer
will have the ability to trigger processes when a Session
event is broadcasted.
This is because a Session instance will hold the EventViewer throughout a user's time using CET. Registering EventViewers under World or Space risks losing the registered EventViewer when the World or Space instance is changed.
Implementing EventViewer
Session EventViewer
Following from the previous example, we can register an example Session EventViewer like:
/** * Keys. */ public const symbol exampleSessionEventViewerId = "exampleSessionEventViewer"; private const str exampleSessionEventViewerName = "exampleSessionEventViewer"; /** * ExampleSessionEventViewer. */ public class ExampleSessionEventViewer extends EventViewer { /** * Constructor */ public constructor() { super(exampleSessionEventViewerId, exampleSessionEventViewerName); } /** * Events. */ public symbol{} events() { return {#putWorld}; } /** * Event. */ public bool event(symbol event, Object z, str->Object args) { ?World world = z; if (!world) return false; if (event == #putWorld) { worldAdded(world); return true; } return false; } /** * Attached to. */ public void attached(Object to) { if (to as Session) { for (world in to.worlds) worldAdded(world); } } /** * World added. */ extend public void worldAdded(World world) { world.registerEventViewer(ExampleWorldEventViewer()); } }
The constructor of an EventViewer
assigns an id and name for this class, do remember to give it a unique id as it is crucial for the EventManager
to keep it in its viewers map.
The events()
method only returns a collection of events you want this EventViewer
to listen to. In this case, we only want to listen to #putWorld
.
Following that, the event()
method triggers the process whenever a World
is loaded.
attached()
is a method called after it is registered, the argument comes with the Session
, World
, or Space
this is registered to.
worldAdded()
is a new method to register a World EventViewer. It is called when this Session EventViewer is registered or when a new World
is loaded.
World EventViewer
Now let's create an example World EventViewer:
public const symbol exampleWorldEventViewerId = "exampleWorldEventViewer"; private const str exampleWorldEventViewerName = "exampleWorldEventViewer"; /** * Example world event viewer. */ public class ExampleWorldEventViewer extends EventViewer { /** * Constructor */ public constructor() { super(exampleWorldEventViewerId, exampleWorldEventViewerName); } /*********************************************************************** * Event. ***********************************************************************/ /** * Events. */ public symbol{} events() { return {#collInitialized, #collFileLoaded, #collFileRemoved, #putSpace, #removeSpace}; } /** * Event. */ public bool event(symbol event, Object z, str->Object args) { if (event == #collInitialized) collInitialized(z, collection.world); else if (event == #collFileLoaded) collFileLoaded(args.get("collection"), z); else if (event == #collFileRemoved) collFileRemoved(args.get("collection"), z, args.get("inLoad")); else if (event == #putSpace) updateAfterAddSpace(z); else if (event == #removeSpace) updateAfterRemoveSpace(z); return false; } /** * Attached to. */ public void attached(Object to) { ?World world = to; if (!world) return; if (CollCollectionG3 collection = world.collCollectionG3()) { if (collection.initialized) { collInitialized(collection, world); } } } /*********************************************************************** * Update ***********************************************************************/ /** * Collaboration initialized. */ extend public void collInitialized(CollCollectionG3 collection, World world) { //Processes to do after CollCollectionG3 is initialized in world. } /** * Collaboration file loaded. */ extend public void collFileLoaded(CollCollectionG3 collection, CollFileG3 file) { //Processes to do after a file is loaded. } /** * Collaboration file removed. */ extend public void collFileRemoved(CollCollectionG3 collection, CollFileG3 file, bool inLoad) { //Processes to do after a file is removed. } /** * Update after adding a space. */ extend public void updateAfterAddSpace(Space space) { space.registerEventViewer(ExampleSpaceEventViewer()); } /** * Update after removing a space. */ extend public void updateAfterRemoveSpace(Space space) { space.removeEventViewer(exampleSpaceEventViewerId); } }
It's almost the same as Session EventViewer, except it has some special events, and registers the Space EventViewer.
Space EventViewer
Hopping onto the example Space EventViewer:
public const symbol exampleSpaceEventViewerId = "exampleSpaceEventViewer"; private const str exampleSpaceEventViewerName = "exampleSpaceEventViewer"; /** * Example Space event viewer. */ package class ExampleSpaceEventViewer extends EventViewer { /** * Constructor. */ public constructor() { super(exampleSpaceEventViewerId, exampleSpaceEventViewerName); } /** * Events. */ public symbol{} events() { return {#putSnapper, #removeSnapper, #changeFromSpace, #changeToSpace, #suspend, #unsuspend}; } /** * Event. */ public bool event(symbol event, Object z, str->Object args) { if (z as ExampleSnapper) { if (event in {#putSnapper, #changeToSpace, #unsuspend}) { updateAfterAddSnapper(z, event); return true; } else if (event in {#removeSnapper, #changeFromSpace, #suspend}) { updateAfterRemoveSnapper(z, event); return true; } return true; } return false; } /** * Attached. */ public void attached(Object to) { super(..); } /** * Update after adding a snapper. */ extend public void updateAfterAddSnapper(ExampleSnapper snapper, symbol event=null) { //Processes to do after a snapper is loaded.
} /** * Update after removing a snapper. */ extend public void updateAfterRemoveSnapper(ExampleSnapper snapper, symbol event=null) { //Processes to do after a snapper is removed. } }
The Event() Method
Inside the event()
method of an EventViewer
, there are three arguments passed when an event is triggered.
/** * Event. */ extend public bool event(symbol event, Object z, str->Object args) { return false; }
Depending on if it's an EventViewer
registered to a Session
, World
, or Space
, the arguments passed here will be different.
Within the context of CollabPro, there are a few notable events to take note of, namely:
Registered To |
Event | Object | Arguments | Description |
World | #collFileLoaded | CollFile | CollCollection | Triggers when a new file is loaded by user or file update. |
World | #collFileRemoved | CollFile | CollCollection | Triggers when a file is removed by user or file update. |
World | #collFileBeforeSave | CollFile | CollCollection | Triggers right before a new file is saved/streamed into the computer. |
Space | #beforeChangeSectionId #afterChangeSectionId |
Snapper | null | Triggers when a Snapper is assigned a new section id. |
Other than these, you can hop on to cm/core/eventViewer.cm to check a list of events.
Comments
0 comments
Please sign in to leave a comment.