Chronos Plugins 5.4.0
This documentation covers the plugin interfaces definitions and an example implementation.
Loading...
Searching...
No Matches
MockUseDeviceTasks.cs
Go to the documentation of this file.
1using System;
2using System.ComponentModel;
3using System.Drawing.Design;
4using System.Linq;
5using System.Windows.Forms.Design;
6using System.Xml.Serialization;
9using Ctc.Palplus.Integration.Driver.Entities;
12using MockPlugin.Properties;
14
15// ReSharper disable UnusedMember.Global
16// ReSharper disable MemberCanBePrivate.Global
17// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
18// ReSharper disable ClassNeverInstantiated.Global
19// ReSharper disable UnusedAutoPropertyAccessor.Global
20
21namespace MockPlugin.Tasks
22{
26 public abstract class CoffeeMachineBaseTask : IConsumer
27 {
29
34 protected void CheckForCoffeeMachine(IDevice yourDevice)
35 {
36 mDevice = yourDevice as MockDevice;
37 if (mDevice == null && yourDevice != null)
38 {
39 throw new ArgumentException(
40 $"Device type {yourDevice.DisplayedTypeName} is not usable for a {GetType().Name}.");
41 }
42 if (yourDevice == null)
43 {
44 throw new ArgumentException("This kind of task needs an autosampler.");
45 }
46 }
47
48 public void SetDevice(IDevice yourDevice)
49 {
50 CheckForCoffeeMachine(yourDevice);
51 }
52
53 public virtual void PreValidate()
54 {
55 }
56
57 public virtual void PostValidate()
58 {
59 }
60
61 public abstract void Execute();
62 public abstract string GetTaskAction();
63
65 }
66
71 {
72 public CoffeeCategory(int ranking) : base(ranking)
73 {
74 }
75
79 public override string Name => LocalizeMockPlugin.CoffeeCategory_Name_Coffee;
80 }
81
90 [ScheduleDiagramColor("Sienna")]
92 {
96 public override void Execute()
97 {
100 }
101
102 public override void PostValidate()
103 {
105 }
106
111 {
112 Consumables.ModifyLevel(CoffeeConsumableManager.GetLocationIdentifier(mDevice, MockConsumablesForCoffeeMakerDevice.Coffee.Name), new Quantity(-7, Units.Gram));
113 }
114
119 public override string GetTaskAction()
120 {
121 return LocalizeMockPlugin.BrewCoffee_GetTaskAction_Send_a_message_to_my_device;
122 }
123
127 public string Message { get; set; } = LocalizeMockPlugin.BrewCoffee_mMessage_Do_you_want_sugar_;
128 }
129
139 [CoffeeCategory(2)]
141 {
145 [TypeConverter(typeof(CreamTypeConverter))]
146 public enum CreamType
147 {
148 Normal,
149 LowFat,
150 Vegan
151 }
152
156 [Editor(typeof(CompositionEditor), typeof(UITypeEditor))]
157 public class CompositionData
158 {
159 [XmlIgnore]
160 public MockDevice DevInEditor { get; set; }
161
163 {
164 get;
165 set;
166 }
167
168 public bool MuchIce { get; set; }
169
170 public bool DeCaffeinated { get; set; }
171
172 public uint Volume { get; set; }
173
178 {
179 Cream = CreamType.LowFat;
180 MuchIce = false;
181 DeCaffeinated = false;
182 Volume = 250;
183 }
184
189 public override string ToString()
190 {
191 return String.Format(LocalizeMockPlugin.CompositionData_ToString_Cream___0___MuchIce___1___Decaffeinated___2___Size___3__mL,
193 }
194 }
195
196 #region Component model UI type editor
197
201 public class CompositionEditor : UITypeEditor
202 {
208 public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
209 {
210 // we want a real dialog, not just a drop down box
211 return UITypeEditorEditStyle.Modal;
212 }
213
221 public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
222 {
223 var editProvider = (IWindowsFormsEditorService)provider?.GetService(typeof(IWindowsFormsEditorService));
224 // create the editor form
225 var compData = (CompositionData)value;
226 // we could get a reference to the task here: var theTask = context.Instance as BrewFrappuccino;
227 using (var myEditor = new FrappuccinoCompositionEditor(compData))
228 {
229 // our editor will only modify the parameters if it has been closed by clicking OK
230 editProvider?.ShowDialog(myEditor);
231 }
232 return value;
233 }
234 }
235
236 #endregion Component model UI type editor
237
239
245 {
246 get
247 {
248 if (mComposition != null && mComposition.DevInEditor == null)
249 {
250 mComposition.DevInEditor = mDevInEditor;
251 }
252 return mComposition;
253 }
254 set
255 {
256 mComposition = value;
257 if (mComposition != null)
258 {
259 mComposition.DevInEditor = mDevInEditor;
260 }
261 RaiseVolumeChanged();
262 }
263 }
264
265 public override string GetTaskAction()
266 {
267 return LocalizeMockPlugin.BrewFrappuccino_GetTaskAction_Brew_a_frappuccino__composition__ + Composition;
268 }
269
270
271 [DefaultUnit(Units.MilliLiter)]
272 public uint Volume
273 {
274 get => mComposition.Volume;
275 set
276 {
277 if(mComposition.Volume == value) return;
278 mComposition.Volume = value;
279 RaiseVolumeChanged();
280 }
281 }
282 internal void RaiseVolumeChanged()
283 {
284 PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(Volume)));
285 }
286 [DefaultUnit("mL")]
287 public uint CupSize
288 {
289 get;
290 set;
291 }
292
294 {
296 CupSize = 250;
297 }
298
302 public override void Execute()
303 {
306 }
307
308 public override void PostValidate()
309 {
311 }
312
317 private void RegisterConsumption(CompositionData composition)
318 {
319 var sizeFactor = composition.Volume / 125.0;
320 Consumables.ModifyLevel(CoffeeConsumableManager.GetLocationIdentifier(mDevice,MockConsumablesForCoffeeMakerDevice.Coffee.Name),new Quantity(-7*sizeFactor, Units.Gram));
321 string creamName;
322 switch (composition.Cream)
323 {
324 case CreamType.LowFat:
325 // intentionally picked name of a component that is not tracked. Results just in a log entry, not visible on tracker's page.
326 creamName = "Low Fat Milk";
327 break;
328 case CreamType.Normal:
329 creamName = MockConsumablesForCoffeeMakerDevice.Milk.Name;
330 break;
331 case CreamType.Vegan:
332 creamName = MockConsumablesForCoffeeMakerDevice.VeganCream.Name;
333 break;
334 default:
335 creamName = "";
336 break;
337 }
338 Consumables.ModifyLevel(CoffeeConsumableManager.GetLocationIdentifier(mDevice, creamName),new Quantity(-10*sizeFactor,Units.MilliLiter));
339 }
340
351 public void PropertyEdited(string propName, object propValue)
352 {
353 if (propName == nameof(Volume))
354 {
355 // the uint32 converter can't convert from uint32 to uint32 but throws an exception.
356 if (propValue is uint u)
357 {
358 Volume = u;
359 }
360 else
361 {
362 var conv = TypeDescriptor.GetConverter(Volume, true);
363 if (conv.IsValid(propValue))
364 {
365 // ReSharper disable once PossibleNullReferenceException
366 Volume = (uint)conv.ConvertFrom(null, System.Globalization.CultureInfo.InvariantCulture, propValue);
367 }
368 }
369 }
370 else if (propName == "Autosampler")
371 {
372 mDevInEditor = MockDevice.Instances.FirstOrDefault(someDev => someDev.Name == propValue?.ToString());
373 if (mComposition != null)
374 {
375 mComposition.DevInEditor = mDevInEditor;
376 }
377 }
378 }
379
381
382 public event PropertyChangedEventHandler PropertyChanged;
383
384 #region Implementation of IGiveARuntimeHint
385
390 {
391 get
392 {
393 if (Volume > 250)
394 {
395 return 30;
396 }
397
398 if (Volume > 100)
399 {
400 return 15;
401 }
402
403 return 10;
404 }
405 }
406
407 #endregion
408 }
409
413 [CoffeeCategory(3)]
414 // ReSharper disable once UnusedType.Global
416 {
417 public bool SoftStop { get; set; }
418 public override void Execute()
419 {
420 mDevice.TriggerAbort(LocalizeMockPlugin
421 .PretendCoffeeMachineIsBroken_Execute_The_coffee_machine_s_heater_failed_,SoftStop);
422 }
423
424 public override string GetTaskAction()
425 {
426 return String.Format(LocalizeMockPlugin.PretendCoffeeMachineIsBroken_GetTaskAction_Will_make_the_device_abort_the_schedule_after_a_few_seconds_,SoftStop);
427 }
428 }
432 [CoffeeCategory(4)]
434 {
435 public string ErrorDescription { get; set; } = "Some random error message that is shown to the user";
436 public ErrorType ErrorType { get; set; } = ErrorType.MissingVial;
440 public bool ResolvedAfterHandling { get; set; } = false;
441 public override void Execute()
442 {
444 }
445
446 public override string GetTaskAction()
447 {
448 return $"Raising error type {ErrorType} with description \"{ErrorDescription}\"";
449 }
450 }
451}
Classes and interfaces that are meant for plugins. The classes and interfaces below this namespace ar...
ErrorType
Lets a device implementing IHaveInteractiveErrorHandling specify which kind of error occurred.
A fake device. This namespace contains the fake device driver and auxiliary classes for settings,...
Example task implementations. Since there are lots of things that can be done from a task,...
The classes in this namespace demonstrate how to define your own sample list column types.
Helps you manipulate the desired consumable, or works as a dummy.
void ModifyLevel(string consumableLocation, Quantity amountDelta)
Change the level of a consumable.
For tasks that intend to modify consumable levels.
Definition: IConsumer.cs:10
To be implemented by the "device driver" part of a Chronos plugin.
To be implemented if the task needs to access a device ("Autosampler" property in Chronos)
If you can calculate your runtime, you should implement this interface.
Implement this interface in your task if you want the method editor to notify it of changed propertie...
Use this if none of the predefined categories fit and you have a better idea than "Misc".
Keeps track of all consumables that are associated to our mock coffee machine.
static string GetLocationIdentifier(MockDevice dev, string ingredientName)
A chronos plugin implementation for a fake device. We pretend we are controlling a mixture of coffee ...
Definition: MockDevice.cs:53
void BrewFrappuccino(BrewFrappuccino.CompositionData composition)
Pretend we are doing some operation on a complex parameter set.
Definition: MockDevice.cs:96
void ShowTheMessage(string messageText)
Let our device set a status message and display some message box instead of doing real work.
Definition: MockDevice.cs:158
string Name
User-selected name for the device instance.
Definition: MockDevice.cs:87
void TriggerAbort(string reason, bool softStop)
This will trigger the AbortSchedule-Event 5 seconds after it was called from a task.
Definition: MockDevice.cs:231
void RaiseError(string errorDescription, ErrorType errType, bool resolved)
"Retry" here means that we don't retry some action, but that we raise the error again.
Definition: MockDevice.cs:370
Just provide a TypeConverter, and Chronos is happy.
Provides an editor for the BrewFrappuccino-Task's "Composition" information.
Base class for our example, just contains some empty default implementations and a check for the righ...
IConsumableManipulator Consumables
You will get an instance of a helper class that helps your task to find the correct consumable puddle...
void CheckForCoffeeMachine(IDevice yourDevice)
It makes no sense to use any other "Autosampler" than our fake coffee machine here.
virtual void PostValidate()
Called after the schedule construction is completed.
virtual void PreValidate()
Called before the schedule construction is completed.
abstract string GetTaskAction()
Description of the tasks's action (for hints/time table)
abstract void Execute()
Do whatever you have to do with your parameters.
Custom category in the method editor for coffee making related tasks.
override string Name
Localization aware category name.
Calls a method of the device class with one if its task parameters.
override void Execute()
Do something with our device: The resulting message box is displayed by the device.
override void PostValidate()
Called after the schedule construction is completed.
void RegisterCoffeeConsumption()
Inform the consumables tracker of the needed coffee amount.
override string GetTaskAction()
Show this task's action in the timetable.
string Message
Trivial property which can be changed in the method editor.
A task working on a complex parameter set.
void RegisterConsumption(CompositionData composition)
Register consumption of coffee / cream with the consumables tracker.
override void PostValidate()
Called after the schedule construction is completed.
PropertyChangedEventHandler PropertyChanged
CompositionData Composition
Our extremely complex composition which could in no way be done with normal text-editable properties.
CreamType
Enum properties result in nice drop-down lists.
void PropertyEdited(string propName, object propValue)
The method editor informs us about changed values.
override string GetTaskAction()
Description of the tasks's action (for hints/time table)
override void Execute()
Send the recipe to our device.
int? CalculatedRuntime
Return some fake runtimes depending on the requested volume.
Let's pretend the composition is really complex and better done with a custom editor.
override string ToString()
This value will be shown (read only) in the property field, with a button next to it that invokes our...
Provide an editor for our complex parameter set, the standard component model way.
override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
Which kind of editor should be shown?
override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
Pass the value to edit to our editor dialog and return the changed(?) value.
This task will trigger a timer in our device which will make it complain about an error situation,...
override void Execute()
Do whatever you have to do with your parameters.
override string GetTaskAction()
Description of the tasks's action (for hints/time table)
In contrast to PretendCoffeeMachineIsBroken, this simulates an error that an autosampler could have w...
override void Execute()
Do whatever you have to do with your parameters.
override string GetTaskAction()
Description of the tasks's action (for hints/time table)
bool ResolvedAfterHandling
Should we consider the error fixed after error handling has run?