Thunderbird:Activity Manager/Developer
NOTE: The content on this page has been moved to MDC: Activity Manager, Activity Manager Interfaces and Activity Manager Examples
Contents
- 1 Activity Manager Concepts and Interfaces
- 1.1 Overview
- 1.2 Interfaces
- 1.3 Default Components
- 1.4 Error Handling
- 1.5 Extending the Activity System
- 1.6 Scenarios
- 1.6.1 Showing an user-defined activity on the activity manager window
- 1.6.2 Showing an user-defined activity with cancel capability (JS)
- 1.6.3 Showing an user-defined activity with undo capability (C++)
- 1.6.4 Adding an activity with custom context type
- 1.6.5 Adding a fully customized activity
- 1.6.6 Changing the activity bindings
- 1.7 Relevant Links
- 1.8 Relevant Bugs
Activity Manager Concepts and Interfaces
Overview
Interfaces
See nsIActivityManager.idl and nsIActivity.idl files for more documentation
- nsIActivityMgrListener: The implementer of this interface gets notified when an activity is added/removed to/from the activity list managed by Activity Manager. Activity developers do not need to implement this interface in order to introduce new activities to the system.
- nsIActivityManager: It is implemented by the default Activity Manager component, used by the Activity Manager consumers. Activity developers do not need to implement this interface in order to introduce new activities to the system.
- nsIActivityContextDisplayHelper: It is implemented and registered by the Activity developer to customize the context display text.
- nsIActivity: Base interface for both nsIActivityProcess, nsIActivityWarning and nsIActivityEvent. Exposes common attributes and methods. Activity developers do not need to implement this interface in order to introduce new activities to the system.
- nsIActivityProcess: Process activity types should implement this interface. For the majority of the cases, default process component (@mozilla.org/activity-process;1) should suffice. In cases where additional functionality needed by the process, Activity developers can implement their own version of Process activity and extend the system.
- nsIActivityEvent: Event activity types should implement this interface. For the majority of the cases, default event component (@mozilla.org/activity-event;1) should suffice. In cases where additional functionality needed by the event, Activity developers can implement their own version of Event activity and extend the system.
- nsIActivityWarning: Warning activity types should implement this interface. For the majority of the cases, default warning component (@mozilla.org/activity-warning;1) should suffice. In cases where additional functionality needed by the warning, Activity developers can implement their own version of Warning activity and extend the system.
- nsIActivityListener: The implementer of this interface gets notified when the subscribed activity changes state, progress and more.
- nsIActivityPauseHandler: If provided with the activity, it allows the user to pause/resume the activity during its progress. Process types only. Activity developers might implement a component realizing this interface and associate with the activity in question. When done, default binding (XBL) representing the activity in the Activity Manager window will automatically show a pause/resume button attached to the activity.
- nsIActivityRetryHandler: If provided with the activity, it allows the user to retry the failed activity. Process types only. Activity developers might implement a component realizing this interface and associate with the activity in question. When done, default binding (XBL) representing the activity in the Activity Manager window will automatically show a retry button attached to the activity.
- nsIActivityCancelHandler: If provided with the activity, it allows the user to cancel the activity. Process types only. Activity developers might implement a component realizing this interface and associate with the activity in question. When done, default binding (XBL) representing the activity in the Activity Manager window will automatically show a cancel button attached to the activity.
- nsIActivityUndoHandler: If provided with the activity, it allows the user to undo the operation subject of the event. Persisted Events might not be undone. This feature hopefully will be supported in the future when we have a better undo mechanism in place. Obviously Event types only. Activity developers might implement a component realizing this interface and associate with the activity in question. When done, default binding (XBL) representing the activity in the Activity Manager window will automatically show a undo button attached to the activity.
- nsIActivityRecoveryHandler: If provided with the activity, it allows the user to activste the operation to recover from the sitation causing the warning. Warning types only. Activity developers might implement a component realizing this interface and associate with the activity in question. When done, default binding (XBL) representing the activity in the Activity Manager window will automatically show a pause/resume button attached to the activity.
Default Components
- @mozilla.org/activity-manager;1: Implements the nsIActivityManager. Provides the facilities to manage activities introduced by the backend, extensions, and the user.
- @mozilla.org/activity-process;1: The default implementation of a Process activity. It knows how to deal with different process states. In majority of the cases it is enough to instantiate this component to add a new Process activity to the Activity Management system - see samples below.
- @mozilla.org/activity-event;1: The default implementation of an Event activity. In majority of the cases it is enough to instantiate this component to add a new Event activity to the Activity Management system - see samples below.
- @mozilla.org/activity-warning;1: The default implementation of a Warning activity. In majority of the cases it is enough to instantiate this component to add a new Warning activity to the Activity Management system - see samples below.
Error Handling
TBD
Extending the Activity System
- If the default implementation of nsIActivityProcess, nsIActivityWarning and nsIActivityEvent are not sufficient for the activity initiator, Activity developers can provide their own components to extend the capabilities. Default implementations can be found in nsActivity.js file.
- If Activity developers would like to extend the default UI representation of the activity types, they can provide their own XBL elements for their own activity types. All custom activity XBL elements should inherit from "activity-base" binding. For XBL sample please see activity.xml and activity.css files.
Scenarios
Showing an user-defined activity on the activity manager window
The following sample will show a process and an event for junk processing on the activity manager window.
// Step 1: Adding a Process into the activity manager const nsIAP = Ci.nsIActivityProcess; const nsIAE = Ci.nsIActivityEvent; const nsIAM = Ci.nsIActivityManager; let gActivityManager = Cc["@mozilla.org/activity-manager;1"].getService(nsIAM); let process = Cc["@mozilla.org/activity-process;1"].createInstance(nsIAP); // Assuming folder is an instance of nsIMsgFolder interface // Localization is omitted, initiator is not provided process.init("Processing folder: " + folder.prettiestName, null); // Note that we don't define a custom icon, default process icon // will be used process.contextType = "account"; // group this activity by account process.contextObj = folder.server; // account in question gActivityManager.addActivity(process); // Step 2: Showing some progress let percent = 50; process.setProgress(percent, "Junk processing 25 of 50 messages", 25, 50); // Step 3: Removing the process and adding an Event using Process' attributes process.state = Components.interfaces.nsIActivityProcess.STATE_COMPLETED; gActivityManager.removeActivity(process.id); let event = Cc["@mozilla.org/activity-event;1"].createInstance(nsIAE); // Localization is omitted, initiator is omitted event.init(folder.prettiestName + " is processed", null, "No junk found", process.startTime, // start time Date.now()); // completion time event.contextType = process.contextType; // optional event.contextObj = process.contextObj; // optional gActivityManager.addActivity(event);
Showing an user-defined activity with cancel capability (JS)
This sample will improve the previous one by providing an nsIActivityCancelHandler to allow the user cancel the process.
// Step 1: Create a nsIActivityCancelHandler implementation function CancelJunkProcess() { // user stuff here.. } CancelJunkProcess.prototype = { cancel: function(aActivity) { let initiator = aActivity.initiator; if (initiator) { let folder = aActivity.getSubjects({})[0]; .... // assuming that the initiator has some way to cancel // the junk processing for given folder if (initiator.cancelFolderOp(folder)) { aActivity.state = Components.interfaces.nsIActivityProcess.STATE_CANCELED; gActivityManager.removeActivity(aActivity.id); return Cr.NS_SUCCESS; } } return Cr.NS_FAILURE; } } // Step 2: Modify the previous sample to add initiator, subject // and associate a nsIActivityCancelHandler component ... // assuming that gJunkProcessor is the entity initiating the junk processing // activity, and it has cancelFolderOp method that cancels the operations on folders process.init("Processing folder: " + folder.prettiestName, gJunkProcessor); // folder is being filtered/processed process.addSubject(folder); process.cancelHandler = new CancelJunkProcess(); ...
Since nsIActivityCancelHandler is provided with the activity, UI will show a cancel button besides the activity. You can extrapolate this sample to nsIActivityRetryHandler and nsIActivityPauseHandler as well.
Showing an user-defined activity with undo capability (C++)
..... #include "nsIActivity.h" #include "nsIActivityManager.h" .....
////////////////////////////////////////////////////////////////////////////// //// Undo handler implementation class myCopyEventUndo : public nsIActivityUndoHandler { public: NS_DECL_ISUPPORTS NS_DECL_NSIACTIVITYUNDOHANDLER myCopyEventUndo() {} private: ~myCopyEventUndo() {} }; NS_IMPL_ISUPPORTS1(myCopyEventUndo, nsIActivityUndoHandler)
NS_IMETHODIMP myCopyEventUndo::Undo(nsIActivityEvent *event, nsresult *result) { nsresult rv; // get the subjects of this copy event PRUint32 length; nsIVariant **subjectList; rv = event->GetSubjects(&length, &subjectList); if(NS_FAILED(rv)) return rv; // first subject in the list is the source folder in this particular case nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(subjectList[0]); // get the initiator nsIVariant *initiator; event->GetInitiator(&initiator); if (initiator) { nsISupports* ptr; rv = object->GetAsISupports(&ptr); if(NS_FAILED(rv)) return rv; nsCOMPtr<nsIMsgCopyService> copyService = do_QueryInterface(ptr); if (copyService) copyService->Undo(folder); } return (*result = NS_OK); }
///////////////////////////////////////////////////////////////////////////// //// Creating an undoable copy event nsCOMPtr<nsIActivityUndoHandler> undoHandler = new myCopyEventUndo(); nsCOMPtr<nsIActivityEvent> copyEvent(do_CreateInstance("@mozilla.org/activity-event;1")); // The initiator of this particular event is CopyService. We want to // associate it with the event since we are going to use it in the // undo handler. // Same for the source folder, it is required for undo operation, but // since it is the subject of this activity (event), it goes into the // subject list. // wrap copyservice in a nsvariant component nsCOMPtr<nsIWritableVariant> initiator = do_CreateInstance(NS_VARIANT_CONTRACTID); initiator->SetAsISupports(reinterpret_cast<nsISupports*>(copyService)); // subject of the delete operation is the imap folder // wrap it in a nsvariant component nsCOMPtr<nsIWritableVariant> srcFolder = do_CreateInstance(NS_VARIANT_CONTRACTID); srcFolder->SetAsISupports(reinterpret_cast<nsISupports*>(imapFolder)); copyEvent->AddSubject(srcFolder); copyEvent->Init(NS_LITERAL_STRING("Message copy event"), initiator, NS_LITERAL_STRING("Completed successfully"), PR_Now() / PR_USEC_PER_MSEC, // start time PR_Now() / PR_USEC_PER_MSEC); // completion time // Do not forget to increase the ref counter if needed copyEvent->SetUndoHandler(undoHandler);
//////////////////////////////////////////////////////////////// //// Adding the event into Activity Manager nsCOMPtr<nsIActivityManager> activityMgr(do_GetService("@mozilla.org/activity-manager;1")); PRUint32 id; activityMgr->AddActivity(copyEvent, &id);
Adding an activity with custom context type
This sample shows how to provide a custom context type for the junk processing. As a result, all junk processing activities (assuming that we process accounts in parallel) processing the messages coming from the same sender will be grouped together.
//optional: define some convenience constants const nsActProcess = Components.Constructor("@mozilla.org/activity-process;1", "nsIActivityProcess", "init"); const nsActEvent = Components.Constructor("@mozilla.org/activity-event;1", "nsIActivityEvent", "init"); // Step 1: Implement nsIActivityContextDisplayHelper to show a // customized display text for our context type function SenderContextDisplayHelper() { // user stuff here.. } SenderContextDisplayHelper.prototype = { getContextDisplayText: function(contextType, contextObj) { // in this particular example we know that contextType is "Sender" // since we also pass the contextType along with the contextObject // in some cases, one helper can be registered for a group of context types // we know that the context object is the author of the message // Localization is omitted return "Messages coming from " + contextObj.surname + ", " + contextObj.firstname; } } // Step 2: Register the helper for this context type gActivityManager.registerContextDisplayHelper("Sender", new SenderContextDisplayHelper()); // Step 3: Create the process ... let process = new nsActProcess("Processing folder: " + folder.prettiestName, gJunkProcessor); process.cancelHandler = new CancelJunkProcess(); // folder is being filtered/processed process.addSubject(folder); process.contextType = "Sender"; // assuming msg is an instance of nsIMsgHdr process.contextObj = msg.author; ...
Adding a fully customized activity
In complex scenarios, it might be inevitable for extensions to implement their own version nsIActivityProcess, nsIActivityWarning and nsIActivityEvent interfaces. In such case, nsActivity.js can be used as a model.
Changing the activity bindings
TBD
Relevant Links
- https://wiki.mozilla.org/Thunderbird:Activity_Manager
- https://wiki.mozilla.org/Thunderbird:Activity_Manager/Window
- https://wiki.mozilla.org/Thunderbird:Interactive_Status_Bar
- http://clarkbw.net/designs/interactive-status-bar/activity%20manager.svg