Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
Node.cs
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading.Tasks;
5using System.Windows.Controls;
6using System.Windows.Media;
7using System.Windows.Input;
8using System.Xml;
13using Waher.Content;
15using Waher.Events;
22using Waher.Things;
26
28{
33 {
34 private NodeInformation nodeInfo;
35 private NodeCommand[] commands = null;
36
43 : base(Parent)
44 {
45 this.nodeInfo = NodeInfo;
46
47 if (this.nodeInfo.ParameterList is null)
48 this.parameters = null;
49 else
50 this.parameters = new DisplayableParameters(this.nodeInfo.ParameterList);
51
52 if (this.nodeInfo.HasChildren)
53 {
54 this.children = new SortedDictionary<string, TreeNode>()
55 {
56 { string.Empty, new Loading(this) }
57 };
58 }
59 }
60
64 public string NodeId => this.nodeInfo.NodeId;
65
69 public string SourceId => this.nodeInfo.SourceId;
70
74 public string Partition => this.nodeInfo.Partition;
75
79 public override string Key => this.nodeInfo.NodeId;
80
84 public override string Header => this.nodeInfo.LocalId;
85
89 public override string ToolTip => "Node";
90
94 public override bool CanRecycle => false;
95
100 {
101 get => this.nodeInfo;
102 internal set => this.nodeInfo = value;
103 }
104
108 public override string TypeName
109 {
110 get
111 {
112 if (!(this.parameters is null))
113 {
114 string s = this.parameters["Type"];
115 if (!string.IsNullOrEmpty(s))
116 return s;
117 }
118
119 return this.nodeInfo.NodeType;
120 }
121 }
122
126 public override ImageSource ImageResource
127 {
128 get
129 {
130 if (this.nodeInfo.HasChildren)
131 {
132 if (this.IsExpanded)
133 return XmppAccountNode.folderYellowOpen;
134 else
135 return XmppAccountNode.folderYellowClosed;
136 }
137 else
138 return XmppAccountNode.box;
139 }
140 }
141
146 public override void Write(XmlWriter Output)
147 {
148 // Don't output.
149 }
150
155 {
156 get
157 {
158 TreeNode Loop = this.Parent;
159
160 while (!(Loop is null))
161 {
162 if (Loop is XmppConcentrator Concentrator)
163 return Concentrator;
164
165 Loop = Loop.Parent;
166 }
167
168 return null;
169 }
170 }
171
176 {
177 get
178 {
179 TreeNode Loop = this.Parent;
180
181 while (!(Loop is null))
182 {
183 if (Loop is DataSource DataSource)
184 return DataSource;
185
186 Loop = Loop.Parent;
187 }
188
189 return null;
190 }
191 }
192
193 private bool loadingChildren = false;
194
199 {
200 get
201 {
203 if (Concentrator is null)
204 return null;
205
206 XmppAccountNode AccountNode = Concentrator.XmppAccountNode;
207 if (AccountNode is null)
208 return null;
209
210 return AccountNode.ConcentratorClient;
211 }
212 }
213
217 protected override void LoadChildren()
218 {
219 if (!this.loadingChildren && !this.IsLoaded)
220 {
221 string FullJid = this.Concentrator?.FullJid;
223
224 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
225 {
226 if (this.nodeInfo.HasChildren)
227 {
228 Mouse.OverrideCursor = Cursors.Wait;
229
230 this.loadingChildren = true;
231 ConcentratorClient.GetChildNodes(FullJid, this.nodeInfo, true, true, "en", string.Empty, string.Empty, string.Empty, (Sender, e) =>
232 {
233 this.loadingChildren = false;
234 MainWindow.MouseDefault();
235
236 if (e.Ok)
237 {
238 SortedDictionary<string, TreeNode> Children = new SortedDictionary<string, TreeNode>();
239
240 foreach (NodeInformation Ref in e.NodesInformation)
241 Children[Ref.NodeId] = new Node(this, Ref);
242
243 this.children = Children;
244
245 this.OnUpdated();
246 this.DataSource?.NodesAdded(Children.Values, this);
247 }
248 else
249 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to get child nodes." : e.ErrorText);
250
251 return Task.CompletedTask;
252
253 }, null);
254 }
255 else
256 {
257 if (!(this.children is null))
258 this.DataSource?.NodesRemoved(this.children.Values, this);
259
260 this.children = null;
261
262 this.OnUpdated();
263 }
264 }
265 }
266
267 base.LoadChildren();
268 }
269
273 protected override void UnloadChildren()
274 {
275 base.UnloadChildren();
276
277 if (this.nodeInfo.HasChildren && this.IsLoaded)
278 {
279 if (!(this.children is null))
280 this.DataSource?.NodesRemoved(this.children.Values, this);
281
282 this.children = new SortedDictionary<string, TreeNode>()
283 {
284 { string.Empty, new Loading(this) }
285 };
286
287 this.OnUpdated();
288 }
289 }
290
294 public override bool CanReadSensorData => this.nodeInfo.IsReadable && this.IsOnline;
295
299 public override bool CanSubscribeToSensorData => this.nodeInfo.IsReadable && this.Concentrator.SupportsEvents && this.IsOnline;
300
304 public override async Task<SensorDataClientRequest> StartSensorDataMomentaryReadout()
305 {
309
310 if (!(XmppAccountNode is null) && !((SensorClient = XmppAccountNode.SensorClient) is null))
311 {
313 new ThingReference[] { new ThingReference(this.nodeInfo.NodeId, this.nodeInfo.SourceId, this.nodeInfo.Partition) }, FieldType.Momentary);
314 }
315 else
316 return null;
317 }
318
322 public override Task<SensorDataClientRequest> StartSensorDataFullReadout()
323 {
327
328 if (!(XmppAccountNode is null) && !((SensorClient = XmppAccountNode.SensorClient) is null))
329 {
331 new ThingReference[] { new ThingReference(this.nodeInfo.NodeId, this.nodeInfo.SourceId, this.nodeInfo.Partition) }, FieldType.All);
332 }
333 else
334 throw new NotSupportedException();
335 }
336
340 public override async Task<SensorDataSubscriptionRequest> SubscribeSensorDataMomentaryReadout(FieldSubscriptionRule[] Rules)
341 {
345
346 if (!(XmppAccountNode is null) && !((SensorClient = XmppAccountNode.SensorClient) is null))
347 {
349 new ThingReference[]
350 {
351 new ThingReference(this.nodeInfo.NodeId, this.nodeInfo.SourceId, this.nodeInfo.Partition)
352 },
353 FieldType.Momentary, Rules, Duration.FromSeconds(1), Duration.FromMinutes(1), false);
354 }
355 else
356 return null;
357 }
358
362 public override bool CanConfigure => this.nodeInfo.IsControllable && this.IsOnline;
363
369 public override async Task GetConfigurationForm(EventHandlerAsync<DataFormEventArgs> Callback, object State)
370 {
374
375 if (!(XmppAccountNode is null) && !((ControlClient = XmppAccountNode.ControlClient) is null))
376 {
377 await ControlClient.GetForm(Concentrator.RosterItem.LastPresenceFullJid, "en", Callback, State,
378 new ThingReference(this.nodeInfo.NodeId, this.nodeInfo.SourceId, this.nodeInfo.Partition));
379 }
380 else
381 throw new NotSupportedException();
382 }
383
387 public bool IsOnline
388 {
389 get
390 {
392 if (Concentrator is null)
393 return false;
394
396 if (XmppAccountNode is null)
397 return false;
398
399 XmppClient Client = XmppAccountNode.Client;
400 return !(Client is null) && Client.State == XmppState.Connected;
401 }
402 }
403
407 public override bool CanAddChildren => this.IsOnline;
408
412 public override bool CanEdit => this.IsOnline;
413
417 public override bool CanDelete => this.IsOnline;
418
422 public override void Add()
423 {
424 string FullJid = this.Concentrator?.FullJid;
426
427 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
428 {
429 Mouse.OverrideCursor = Cursors.Wait;
430
431 ConcentratorClient.GetAddableNodeTypes(FullJid, this.nodeInfo, "en", string.Empty, string.Empty, string.Empty, (Sender, e) =>
432 {
433 MainWindow.MouseDefault();
434
435 if (e.Ok)
436 {
437 switch (e.Result.Length)
438 {
439 case 0:
440 MainWindow.ErrorBox("No nodes can be added to this type of node.");
441 break;
442
443 case 1:
444 MainWindow.UpdateGui(() =>
445 {
446 this.Add(e.Result[0].Unlocalized);
447 return Task.CompletedTask;
448 });
449 break;
450
451 default:
452 MainWindow.UpdateGui(() =>
453 {
454 SelectItemDialog Form = new SelectItemDialog("Add node", "Select type of node to add:",
455 "Add node of selected type.", "Type", "Class", e.Result)
456 {
457 Owner = MainWindow.currentInstance
458 };
459
460 bool? Result = Form.ShowDialog();
461
462 if (Result.HasValue && Result.Value)
463 {
464 LocalizedString? Item = Form.SelectedItem;
465 if (Item.HasValue)
466 this.Add(Item.Value.Unlocalized);
467 }
468
469 return Task.CompletedTask;
470 });
471 break;
472 }
473 }
474 else
475 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to add nodes." : e.ErrorText);
476
477 return Task.CompletedTask;
478
479 }, null);
480 }
481 }
482
483 private void Add(string Type)
484 {
485 string FullJid = this.Concentrator?.FullJid;
486 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
487
488 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
489 {
490 Mouse.OverrideCursor = Cursors.Wait;
491
492 ConcentratorClient.GetParametersForNewNode(FullJid, this.nodeInfo, Type, "en", string.Empty, string.Empty, string.Empty, (Sender, e) =>
493 {
494 MainWindow.MouseDefault();
495
496 if (e.Ok)
497 {
498 MainWindow.UpdateGui(async () =>
499 {
500 ParameterDialog Dialog = await ParameterDialog.CreateAsync(e.Form);
501 Dialog.ShowDialog();
502 });
503 }
504 else
505 MainWindow.ErrorBox(e.ErrorText);
506
507 return Task.CompletedTask;
508
509 }, (Sender, e) =>
510 {
511 if (e.Ok)
512 this.Add(new Node(this, e.NodeInformation));
513 else if (!string.IsNullOrEmpty(e.From))
514 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to set parameters." : e.ErrorText);
515
516 return Task.CompletedTask;
517
518 }, null);
519 }
520 }
521
522 internal void Add(Node Node)
523 {
524 if (!this.loadingChildren && this.IsLoaded)
525 {
526 SortedDictionary<string, TreeNode> Children = new SortedDictionary<string, TreeNode>();
527
528 if (!(this.children is null))
529 {
530 foreach (KeyValuePair<string, TreeNode> P in this.children)
531 Children[P.Key] = P.Value;
532 }
533
534 Children[Node.NodeId] = Node;
535 this.children = Children;
536
537 this.OnUpdated();
538 this.DataSource?.NodesAdded(Children.Values, this);
539 }
540 }
541
547 public override async Task Delete(TreeNode Parent, EventHandler OnDeleted)
548 {
549 string FullJid = this.Concentrator?.FullJid;
550 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
551
552 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
553 {
554 Mouse.OverrideCursor = Cursors.Wait;
555
556 await ConcentratorClient.DestroyNode(FullJid, this.nodeInfo, "en", string.Empty, string.Empty, string.Empty, (Sender, e) =>
557 {
558 MainWindow.MouseDefault();
559
560 if (e.Ok)
561 {
562 try
563 {
564 base.Delete(Parent, OnDeleted);
565 }
566 catch (Exception ex)
567 {
568 Log.Exception(ex);
569 }
570 }
571 else
572 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to destroy node." : e.ErrorText);
573
574 return Task.CompletedTask;
575
576 }, null);
577 }
578 }
579
583 public override void Edit()
584 {
585 string FullJid = this.Concentrator?.FullJid;
586 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
587 string OldKey = this.Key;
588
589 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
590 {
591 Mouse.OverrideCursor = Cursors.Wait;
592
593 ConcentratorClient.GetNodeParametersForEdit(FullJid, this.nodeInfo, "en", string.Empty, string.Empty, string.Empty, (Sender, e) =>
594 {
595 MainWindow.MouseDefault();
596
597 if (e.Ok)
598 {
599 MainWindow.UpdateGui(async () =>
600 {
601 ParameterDialog Dialog = await ParameterDialog.CreateAsync(e.Form);
602 Dialog.ShowDialog();
603 });
604 }
605 else
606 MainWindow.ErrorBox(e.ErrorText);
607
608 return Task.CompletedTask;
609
610 }, (Sender, e) =>
611 {
612 if (e.Ok)
613 {
614 this.nodeInfo = e.NodeInformation;
615 this.OnUpdated();
616
617 string NewKey = this.Key;
618 TreeNode Parent = this.Parent;
619
620 if (NewKey != OldKey && !(Parent is null))
621 Parent.RenameChild(OldKey, NewKey, this);
622 }
623 else if (!string.IsNullOrEmpty(e.From))
624 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to set properties." : e.ErrorText);
625
626 return Task.CompletedTask;
627
628 }, null);
629 }
630 }
631
635 public override bool IsSniffable => this.nodeInfo.Sniffable && this.IsOnline;
636
641 public override void AddSniffer(ISniffer Sniffer)
642 {
643 string FullJid = this.Concentrator?.FullJid;
644 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
645
646 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
647 {
648 Mouse.OverrideCursor = Cursors.Wait;
649
650 this.ConcentratorClient.RegisterSniffer(FullJid, this.nodeInfo, DateTime.Now.AddHours(1), Sniffer,
651 string.Empty, string.Empty, string.Empty, (Sender, e) =>
652 {
653 MainWindow.MouseDefault();
654
655 if (e.Ok)
656 {
657 if (Sniffer is TabSniffer TabSniffer)
658 TabSniffer.SnifferId = e.SnifferId;
659 }
660 else
661 MainWindow.ErrorBox(e.ErrorText);
662
663 return Task.CompletedTask;
664
665 }, null);
666 }
667 }
668
674 public override async Task<bool> RemoveSniffer(ISniffer Sniffer)
675 {
676 string FullJid = this.Concentrator?.FullJid;
677 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
678
679 if (Sniffer is TabSniffer TabSniffer &&
680 !TabSniffer.View.Custom &&
681 !(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid) &&
682 !string.IsNullOrEmpty(TabSniffer.SnifferId))
683 {
684 Mouse.OverrideCursor = Cursors.Wait;
685
686 return await this.ConcentratorClient.UnregisterSniffer(FullJid, this.nodeInfo, TabSniffer.SnifferId,
687 string.Empty, string.Empty, string.Empty, (Sender, e) =>
688 {
689 MainWindow.MouseDefault();
690 return Task.CompletedTask;
691 }, null);
692 }
693 else
694 return false;
695 }
696
700 public override void SelectionChanged()
701 {
702 base.SelectionChanged();
703
704 if (!(this.nodeInfo is null) && this.nodeInfo.HasCommands && this.commands is null)
705 {
706 string FullJid = this.Concentrator?.FullJid;
707 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
708
709 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
710 {
711 this.commands = new NodeCommand[0];
712
713 this.ConcentratorClient.GetNodeCommands(FullJid, this.nodeInfo, string.Empty, string.Empty, string.Empty, (Sender, e) =>
714 {
715 if (e.Ok)
716 this.commands = e.Result;
717 else
718 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to get commands." : e.ErrorText);
719
720 return Task.CompletedTask;
721
722 }, null);
723 }
724 }
725 }
726
732 public void AddContexMenuItems(TreeNode Node, ref string CurrentGroup, ContextMenu Menu)
733 {
734 if (Node == this && !(this.commands is null))
735 {
736 MenuItem Item;
737
738 foreach (NodeCommand Command in this.commands)
739 {
740 if (Command.Command == "Search")
741 continue;
742
743 this.GroupSeparator(ref CurrentGroup, Command.SortCategory, Menu);
744
745 Menu.Items.Add(Item = new MenuItem()
746 {
747 Header = Command.Name,
748 IsEnabled = true,
749 Tag = Command
750 });
751
752 Item.Click += this.NodeCommandClick;
753 }
754 }
755 }
756
757 private void NodeCommandClick(object Sender, System.Windows.RoutedEventArgs e)
758 {
759 string FullJid = this.Concentrator?.FullJid;
760 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
761
762 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
763 {
764 MenuItem Item = (MenuItem)Sender;
765 NodeCommand Command = (NodeCommand)Item.Tag;
766
767 if (!string.IsNullOrEmpty(Command.ConfirmationString))
768 {
769 if (System.Windows.MessageBox.Show(MainWindow.currentInstance, Command.ConfirmationString, "Confirm",
770 System.Windows.MessageBoxButton.YesNoCancel, System.Windows.MessageBoxImage.Question) != System.Windows.MessageBoxResult.Yes)
771 {
772 return;
773 }
774 }
775
776 switch (Command.Type)
777 {
778 case CommandType.Simple:
779 Mouse.OverrideCursor = Cursors.Wait;
780
781 ConcentratorClient.ExecuteCommand(FullJid, this.NodeId, this.SourceId, this.Partition, Command.Command,
782 ConcentratorClient.Client.Language, string.Empty, string.Empty, string.Empty, (sender2, e2) =>
783 {
784 MainWindow.MouseDefault();
785
786 this.ShowCommandResult(e2, Command);
787
788 return Task.CompletedTask;
789
790 }, null);
791 break;
792
793 case CommandType.Parametrized:
794 Mouse.OverrideCursor = Cursors.Wait;
795
796 ConcentratorClient.GetCommandParameters(FullJid, this.NodeId, this.SourceId, this.Partition, Command.Command,
797 ConcentratorClient.Client.Language, string.Empty, string.Empty, string.Empty, (sender2, e2) =>
798 {
799 MainWindow.MouseDefault();
800
801 if (e2.Ok)
802 {
803 MainWindow.UpdateGui(async () =>
804 {
805 ParameterDialog Dialog = await ParameterDialog.CreateAsync(e2.Form);
806 Dialog.ShowDialog();
807 });
808 }
809 else
810 MainWindow.ErrorBox(e2.ErrorText);
811
812 return Task.CompletedTask;
813 },
814 (sender2, e2) =>
815 {
816 this.ShowCommandResult(e2, Command);
817 return Task.CompletedTask;
818 }, null);
819 break;
820
821 case CommandType.Query:
822 Mouse.OverrideCursor = Cursors.Wait;
823
824 ConcentratorClient.GetQueryParameters(FullJid, this.NodeId, this.SourceId, this.Partition, Command.Command,
825 ConcentratorClient.Client.Language, string.Empty, string.Empty, string.Empty, (sender2, e2) =>
826 {
827 MainWindow.MouseDefault();
828
829 if (e2.Ok)
830 {
831 MainWindow.UpdateGui(async () =>
832 {
833 ParameterDialog Dialog = await ParameterDialog.CreateAsync(e2.Form);
834
835 if (Dialog.Empty)
836 await e2.Form.Submit();
837 else
838 Dialog.ShowDialog();
839 });
840 }
841 else
842 MainWindow.ErrorBox(e2.ErrorText);
843
844 return Task.CompletedTask;
845 },
846 (sender2, e2) =>
847 {
848 if (e2.Ok)
849 {
850 MainWindow.UpdateGui(async () =>
851 {
852 TabItem TabItem = MainWindow.NewTab(Command.Name, out TextBlock HeaderLabel);
853 MainWindow.currentInstance.Tabs.Items.Add(TabItem);
854
855 QueryResultView ResultView = await QueryResultView.CreateAsync(this, e2.Query, HeaderLabel);
856 TabItem.Content = ResultView;
857
858 TabItem.Focus();
859 });
860 }
861
862 this.ShowCommandResult(e2, Command);
863
864 return Task.CompletedTask;
865
866 }, null);
867 break;
868 }
869 }
870 }
871
872 private void ShowCommandResult(IqResultEventArgs e, NodeCommand Command)
873 {
874 if (!(this.commands is null))
875 {
876 this.commands = null;
877 this.SelectionChanged();
878 }
879
880 if (e.Ok)
881 {
882 if (!string.IsNullOrEmpty(Command.SuccessString))
883 MainWindow.MessageBox(Command.SuccessString, "Success", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
884 }
885 else if (!string.IsNullOrEmpty(e.From)) // If error not sent from node, user has cancelled the command.
886 {
887 if (!string.IsNullOrEmpty(Command.FailureString))
888 MainWindow.MessageBox(Command.FailureString, "Failure", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
889 else
890 MainWindow.ErrorBox(e.ErrorText);
891 }
892 }
893
897 public override bool CanSearch
898 {
899 get
900 {
901 if (!(this.commands is null))
902 {
903 foreach (NodeCommand Command in this.commands)
904 {
905 if (Command.Command == "Search")
906 return true;
907 }
908 }
909
910 return false;
911 }
912 }
913
917 public override void Search()
918 {
919 if (!(this.commands is null))
920 {
921 foreach (NodeCommand Command in this.commands)
922 {
923 if (Command.Command == "Search")
924 {
925 MenuItem Item = new MenuItem()
926 {
927 Header = Command.Name,
928 IsEnabled = true,
929 Tag = Command
930 };
931
932 this.NodeCommandClick(Item, new System.Windows.RoutedEventArgs());
933 return;
934 }
935 }
936 }
937
938 base.Search();
939 }
940
944 public override bool CanCopy => this.IsOnline;
945
949 public override async void Copy()
950 {
951 string FullJid = this.Concentrator?.FullJid;
952 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
953
954 if (!(ConcentratorClient is null) && !string.IsNullOrEmpty(FullJid))
955 {
956 Mouse.OverrideCursor = Cursors.Wait;
957 bool Error = false;
958
959 try
960 {
961 StringBuilder sb = new StringBuilder();
962 await ExportToXml(FullJid, ConcentratorClient, (this.Parent as Node)?.nodeInfo, this.nodeInfo, sb);
963 System.Windows.Clipboard.SetText(XML.PrettyXml(sb.ToString()));
964 MainWindow.MouseDefault();
965 }
966 catch (Exception ex)
967 {
968 MainWindow.ErrorBox(ex.Message);
969 Error = true;
970 }
971 finally
972 {
973 if (!Error)
974 MainWindow.ShowStatus("Copy placed in clipboard.");
975 }
976 }
977 }
978
979 private static async Task ExportToXml(string FullJid, ConcentratorClient ConcentratorClient,
980 NodeInformation Parent, NodeInformation Node, StringBuilder sb)
981 {
982 TaskCompletionSource<DataForm> Request = new TaskCompletionSource<DataForm>();
983 async Task ParametersResult(object Sender, DataFormEventArgs e)
984 {
985 if (e.Ok)
986 {
987 if (e.Form.CanCancel)
988 await e.Form.Cancel();
989
990 Request.TrySetResult(e.Form);
991 }
992 else
993 Request.TrySetException(e.StanzaError ?? new Exception("Unable to get node information."));
994 };
995
996 MainWindow.ShowStatus("Copying " + Node.NodeId + "...");
997
998 await ConcentratorClient.GetNodeParametersForEdit(FullJid, Node, "en", string.Empty, string.Empty, string.Empty,
999 ParametersResult, null, null);
1000
1001 DataForm Form = await Request.Task;
1002
1003 sb.Append("<createNewNode xmlns='");
1005 sb.Append("' type='");
1006 sb.Append(XML.Encode(Node.NodeType));
1007
1008 if (!(Parent is null))
1009 {
1010 sb.Append("' id='");
1011 sb.Append(XML.Encode(Parent.NodeId));
1012
1013 if (!string.IsNullOrEmpty(Parent.SourceId))
1014 {
1015 sb.Append("' src='");
1016 sb.Append(XML.Encode(Parent.SourceId));
1017 }
1018
1019 if (!string.IsNullOrEmpty(Parent.Partition))
1020 {
1021 sb.Append("' pt='");
1022 sb.Append(XML.Encode(Parent.Partition));
1023 }
1024 }
1025 sb.Append("'>");
1026 Form.SerializeSubmit(sb, true);
1027
1028 if (Node.HasChildren)
1029 {
1030 TaskCompletionSource<NodeInformation[]> NodesInformation = new TaskCompletionSource<NodeInformation[]>();
1031
1032 await ConcentratorClient.GetChildNodes(FullJid, Node, true, false, "en", string.Empty, string.Empty, string.Empty, (Sender, e) =>
1033 {
1034 if (e.Ok)
1035 NodesInformation.TrySetResult(e.NodesInformation);
1036 else
1037 NodesInformation.TrySetException(e.StanzaError ?? new Exception("Unable to get information about children."));
1038
1039 return Task.CompletedTask;
1040
1041 }, null);
1042
1043 NodeInformation[] Children = await NodesInformation.Task;
1044
1045 if (!(Children is null))
1046 {
1047 foreach (NodeInformation Child in Children)
1048 await ExportToXml(FullJid, ConcentratorClient, Node, Child, sb);
1049 }
1050 }
1051
1052 sb.Append("</createNewNode>");
1053 }
1054
1058 public override bool CanPaste
1059 {
1060 get
1061 {
1062 string FullJid = this.Concentrator?.FullJid;
1063 if (string.IsNullOrEmpty(FullJid))
1064 return false;
1065
1066 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
1067 if (ConcentratorClient is null)
1068 return false;
1069
1070 if (!this.IsOnline)
1071 return false;
1072
1073 if (!System.Windows.Clipboard.ContainsText())
1074 return false;
1075
1076 string s = System.Windows.Clipboard.GetText();
1077 if (!XML.IsValidXml(s))
1078 return false;
1079
1080 try
1081 {
1082 XmlDocument Doc = new XmlDocument();
1083 Doc.LoadXml(s);
1084
1085 return
1086 !(Doc.DocumentElement is null) &&
1087 Doc.DocumentElement.LocalName == "createNewNode" &&
1088 Doc.DocumentElement.NamespaceURI == ConcentratorServer.NamespaceConcentratorCurrent;
1089 }
1090 catch (Exception)
1091 {
1092 return false;
1093 }
1094 }
1095 }
1096
1100 public override async void Paste()
1101 {
1102 bool Error = false;
1103
1104 try
1105 {
1106 string FullJid = this.Concentrator?.FullJid;
1107 if (string.IsNullOrEmpty(FullJid))
1108 return;
1109
1110 ConcentratorClient ConcentratorClient = this.ConcentratorClient;
1111 if (ConcentratorClient is null)
1112 return;
1113
1114 if (!this.IsOnline)
1115 return;
1116
1117 if (!System.Windows.Clipboard.ContainsText())
1118 return;
1119
1120 string s = System.Windows.Clipboard.GetText();
1121 if (string.IsNullOrEmpty(s))
1122 return;
1123
1124 XmlDocument Doc = new XmlDocument();
1125 Doc.LoadXml(s);
1126
1127 Mouse.OverrideCursor = Cursors.Wait;
1128
1129 await ImportFromXml(FullJid, ConcentratorClient, this, Doc.DocumentElement);
1130 }
1131 catch (XmlException ex)
1132 {
1133 ex = XML.AnnotateException(ex);
1134 MainWindow.ErrorBox(ex.Message);
1135 Error = true;
1136 }
1137 catch (Exception ex)
1138 {
1139 MainWindow.ErrorBox(ex.Message);
1140 Error = true;
1141 }
1142 finally
1143 {
1144 MainWindow.MouseDefault();
1145
1146 if (!Error)
1147 MainWindow.ShowStatus("Contents of clipboard pasted to node.");
1148 }
1149 }
1150
1151 private static async Task ImportFromXml(string FullJid, ConcentratorClient ConcentratorClient,
1152 Node Parent, XmlElement Xml)
1153 {
1154 if (Xml is null ||
1155 Xml.LocalName != "createNewNode" ||
1157 {
1158 throw new Exception("Clipboard does not contain node information.");
1159 }
1160
1161 string NodeType = XML.Attribute(Xml, "type");
1162 if (string.IsNullOrEmpty(NodeType))
1163 throw new Exception("Node type missing.");
1164
1165 DataForm ImportForm = null;
1166 LinkedList<XmlElement> ChildElements = null;
1167
1168 foreach (XmlNode N in Xml.ChildNodes)
1169 {
1170 if (!(N is XmlElement E))
1171 continue;
1172
1173 switch (E.LocalName)
1174 {
1175 case "x":
1176 if (ImportForm is null)
1177 ImportForm = new DataForm(ConcentratorClient.Client, E, null, null, string.Empty, string.Empty);
1178 else
1179 throw new Exception("Multiple form elements in XML.");
1180 break;
1181
1182 case "createNewNode":
1183 if (ChildElements is null)
1184 ChildElements = new LinkedList<XmlElement>();
1185
1186 ChildElements.AddLast(E);
1187 break;
1188
1189 default:
1190 throw new Exception("Unrecognized XML element: " + E.LocalName);
1191 }
1192 }
1193
1194 if (ImportForm is null)
1195 throw new Exception("Parameter form element missing from XML.");
1196
1197 MainWindow.ShowStatus("Adding " + NodeType + " to " + Parent.NodeId + "...");
1198
1199 TaskCompletionSource<Node> Request = new TaskCompletionSource<Node>();
1200 int IdCounter = 0;
1201
1202 await ConcentratorClient.GetParametersForNewNode(FullJid, Parent.nodeInfo, NodeType, "en", string.Empty, string.Empty, string.Empty,
1203 async (object Sender, DataFormEventArgs e) =>
1204 {
1205 try
1206 {
1207 if (e.Ok)
1208 {
1209 Dictionary<string, bool> VariablesProcessed = new Dictionary<string, bool>();
1210
1211 foreach (Networking.XMPP.DataForms.Field Field in e.Form.Fields)
1212 {
1213 VariablesProcessed[Field.Var] = true;
1214
1215 Networking.XMPP.DataForms.Field InputField = ImportForm[Field.Var];
1216
1217 if (Field.HasError)
1218 {
1219 if (InputField is null)
1220 {
1221 Request.TrySetException(new Exception("Unable to add node of type " +
1222 NodeType + " to node " + Parent.NodeId + ". Required field " + Field.Var +
1223 " did not have a value in the node being pasted from the clipboard. " +
1224 "Error reported: " + Field.Error));
1225 return;
1226 }
1227 else if (Field.Var == "NodeId")
1228 {
1229 if (IdCounter++ == 0)
1230 await Field.SetValue(InputField.ValueString);
1231 else
1232 await Field.SetValue(InputField.ValueString + " (" + IdCounter.ToString() + ")");
1233 }
1234 else if (IdCounter > 1)
1235 {
1236 Request.TrySetException(new Exception("Unable to add node of type " +
1237 NodeType + " to node " + Parent.NodeId + ". Value in clipboard for field " +
1238 Field.Var + " was not acceptable. Error reported: " + Field.Error));
1239 return;
1240 }
1241 else
1242 await Field.SetValue(InputField.ValueStrings);
1243 }
1244 else if (!(InputField is null))
1245 await Field.SetValue(InputField.ValueStrings);
1246 }
1247
1248 List<Networking.XMPP.DataForms.Field> ExtendedFields = null;
1249
1250 foreach (Networking.XMPP.DataForms.Field Field in ImportForm.Fields)
1251 {
1252 if (VariablesProcessed.ContainsKey(Field.Var))
1253 continue;
1254
1255 VariablesProcessed[Field.Var] = true;
1256
1257 if (ExtendedFields is null)
1258 {
1259 ExtendedFields = new List<Networking.XMPP.DataForms.Field>();
1260 ExtendedFields.AddRange(e.Form.Fields);
1261 }
1262
1263 ExtendedFields.Add(Field);
1264 }
1265
1266 if (!(ExtendedFields is null))
1267 e.Form.Fields = ExtendedFields.ToArray();
1268
1269 await e.Form.Submit();
1270 }
1271 else
1272 {
1273 Request.TrySetException(e.StanzaError ?? new Exception("Unable to add a node of type " +
1274 NodeType + " to node " + Parent.NodeId + "."));
1275 }
1276 }
1277 catch (Exception ex)
1278 {
1279 Request.TrySetException(ex);
1280 }
1281
1282 }, (object Sender, NodeInformationEventArgs e) =>
1283 {
1284 if (e.Ok)
1285 {
1286 Node NewNode = new Node(Parent, e.NodeInformation);
1287 Parent.Add(NewNode);
1288 Request.TrySetResult(NewNode);
1289 }
1290 else if (!string.IsNullOrEmpty(e.From))
1291 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ? "Unable to set parameters." : e.ErrorText);
1292
1293 return Task.CompletedTask;
1294 }, null);
1295
1296 Node CreatedNode = await Request.Task;
1297
1298 if (!(ChildElements is null))
1299 {
1300 foreach (XmlElement Child in ChildElements)
1301 await ImportFromXml(FullJid, ConcentratorClient, CreatedNode, Child);
1302 }
1303 }
1304
1305 }
1306}
Interaction logic for QueryResultView.xaml
Interaction logic for ParameterDialog.xaml
static async Task< ParameterDialog > CreateAsync(DataForm Form)
Interaction logic for ParameterDialog.xaml
Interaction logic for xaml
Represents a data source in a concentrator.
Definition: DataSource.cs:16
Represents a node in a concentrator.
Definition: Node.cs:33
bool IsOnline
If the concentrator hosting the node is online.
Definition: Node.cs:388
override string Header
Tree Node header text.
Definition: Node.cs:84
override bool CanDelete
If the node can be deleted.
Definition: Node.cs:417
override bool CanAddChildren
If children can be added to the node.
Definition: Node.cs:407
override bool CanReadSensorData
If it's possible to read sensor data from the node.
Definition: Node.cs:294
override ImageSource ImageResource
Image resource for the node.
Definition: Node.cs:127
XmppConcentrator Concentrator
Reference to the concentrator node.
Definition: Node.cs:155
override bool CanEdit
If the node can be edited.
Definition: Node.cs:412
override void Add()
Is called when the user wants to add a node to the current node.
Definition: Node.cs:422
override bool CanSubscribeToSensorData
If it's possible to subscribe to sensor data from the node.
Definition: Node.cs:299
void AddContexMenuItems(TreeNode Node, ref string CurrentGroup, ContextMenu Menu)
Adds context sensitive menu items to a context menu.
Definition: Node.cs:732
override async void Copy()
Is called when the user wants to copy the node to the clipboard.
Definition: Node.cs:949
override void AddSniffer(ISniffer Sniffer)
Adds a sniffer to the node.
Definition: Node.cs:641
override string TypeName
Node Type Name.
Definition: Node.cs:109
override async Task GetConfigurationForm(EventHandlerAsync< DataFormEventArgs > Callback, object State)
Gets the configuration form for the node.
Definition: Node.cs:369
override void LoadChildren()
Method is called to make sure children are loaded.
Definition: Node.cs:217
DataSource DataSource
Reference to the data source node.
Definition: Node.cs:176
override async Task< SensorDataClientRequest > StartSensorDataMomentaryReadout()
Starts readout of momentary sensor data values.
Definition: Node.cs:304
override async Task< SensorDataSubscriptionRequest > SubscribeSensorDataMomentaryReadout(FieldSubscriptionRule[] Rules)
Starts subscription of momentary sensor data values.
Definition: Node.cs:340
override void Write(XmlWriter Output)
Saves the object to a file.
Definition: Node.cs:146
override void Edit()
Is called when the user wants to edit a node.
Definition: Node.cs:583
override void Search()
Performs a search on the node.
Definition: Node.cs:917
override Task< SensorDataClientRequest > StartSensorDataFullReadout()
Starts readout of all sensor data values.
Definition: Node.cs:322
override void UnloadChildren()
Method is called to notify children can be unloaded.
Definition: Node.cs:273
override void SelectionChanged()
Method called when selection has been changed.
Definition: Node.cs:700
override async void Paste()
Is called when the user wants to paste data from the clipboard to the node.
Definition: Node.cs:1100
Node(TreeNode Parent, NodeInformation NodeInfo)
Represents a node in a concentrator.
Definition: Node.cs:42
string Partition
Partition ID
Definition: Node.cs:74
ConcentratorClient ConcentratorClient
Reference to the concentrator client
Definition: Node.cs:199
override string Key
Key in parent child collection.
Definition: Node.cs:79
override bool CanRecycle
If the node can be recycled.
Definition: Node.cs:94
override string ToolTip
Tool Tip for node.
Definition: Node.cs:89
override async Task Delete(TreeNode Parent, EventHandler OnDeleted)
Method called when a node is to be deleted.
Definition: Node.cs:547
override async Task< bool > RemoveSniffer(ISniffer Sniffer)
Removes a sniffer from the node.
Definition: Node.cs:674
override bool CanConfigure
If it's possible to configure control parameters on the node.
Definition: Node.cs:362
Represents a data source in a concentrator.
Definition: Loading.cs:11
Abstract base class for tree nodes in the connection view.
Definition: TreeNode.cs:24
virtual DisplayableParameters DisplayableParameters
Gets available displayable parameters.
Definition: TreeNode.cs:214
TreeNode Parent
Parent node. May be null if a root node.
Definition: TreeNode.cs:107
virtual void OnUpdated()
Raises the Updated event.
Definition: TreeNode.cs:224
bool IsExpanded
If the node is expanded.
Definition: TreeNode.cs:233
Class representing a normal XMPP account.
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
static XmlException AnnotateException(XmlException ex)
Creates a new XML Exception object, with reference to the source XML file, for information.
Definition: XML.cs:1588
static bool IsValidXml(string Xml)
Checks if a string is valid XML
Definition: XML.cs:1223
static string PrettyXml(string Xml)
Reformats XML to make it easier to read.
Definition: XML.cs:1548
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
Implements an XMPP concentrator client interface.
Task GetNodeParametersForEdit(string To, IThingReference Node, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< DataFormEventArgs > FormCallback, EventHandlerAsync< NodeInformationEventArgs > NodeCallback, object State)
Gets the set of parameters for the purpose of editing a node.
Task GetChildNodes(string To, IThingReference Node, bool Parameters, bool Messages, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< NodesInformationEventArgs > Callback, object State)
Gets information about all child nodes of a node in a data source.
Task GetAddableNodeTypes(string To, IThingReference Node, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< LocalizedStringsResponseEventArgs > Callback, object State)
Gets a list of what type of nodes can be added to a given node.
Task< bool > UnregisterSniffer(string To, IThingReference Node, string SnifferId, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Registers a new sniffer on a node.
Task DestroyNode(string To, IThingReference Node, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Destroys a node.
Task GetQueryParameters(string To, IThingReference Node, string Command, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< DataFormEventArgs > FormCallback, EventHandlerAsync< NodeQueryResponseEventArgs > QueryCallback, object State)
Gets the set of parameters for a parametrized query.
Task RegisterSniffer(string To, IThingReference Node, DateTime Expires, ISniffer Sniffer, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< SnifferRegistrationEventArgs > Callback, object State)
Registers a new sniffer on a node.
Task GetNodeCommands(string To, IThingReference Node, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< CommandsEventArgs > Callback, object State)
Gets available commands for a node.
Task GetCommandParameters(string To, IThingReference Node, string Command, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< DataFormEventArgs > FormCallback, EventHandlerAsync< NodeCommandResponseEventArgs > CommandCallback, object State)
Gets the set of parameters for a parametrized command.
Task ExecuteCommand(string To, IThingReference Node, string Command, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< NodeCommandResponseEventArgs > Callback, object State)
Executes a node command.
Task GetParametersForNewNode(string To, IThingReference Node, string NodeType, string Language, string ServiceToken, string DeviceToken, string UserToken, EventHandlerAsync< DataFormEventArgs > FormCallback, EventHandlerAsync< NodeInformationEventArgs > NodeCallback, object State)
Gets a set of parameters for the creation of a new node.
Implements an XMPP concentrator server interface.
const string NamespaceConcentratorCurrent
Neuro-Foundation v1 namespace
Information about a command on a node.
Definition: NodeCommand.cs:9
Event arguments for node information responses.
bool HasChildren
If the node has child nodes.
Parameter[] ParameterList
List of displayable parameters.
Implements an XMPP control client interface.
Task GetForm(string To, string Language, params ThingReference[] Nodes)
Gets a control form.
Event arguments for data form results.
Implements support for data forms. Data Forms are defined in the following XEPs:
Definition: DataForm.cs:42
bool CanCancel
If the form can be cancelled.
Definition: DataForm.cs:860
int SerializeSubmit(StringBuilder Output)
Serializes the form as a form submission.
Definition: DataForm.cs:916
async Task Submit()
Submits the form.
Definition: DataForm.cs:798
Field[] Fields
Fields in the form.
Definition: DataForm.cs:716
async Task Cancel()
Cancels the form.
Definition: DataForm.cs:827
Base class for form fields
Definition: Field.cs:16
Event arguments for responses to IQ queries.
bool Ok
If the response is an OK result response (true), or an error response (false).
XmppException StanzaError
Any stanza error returned.
string LastPresenceFullJid
Full JID of last resource sending online presence.
Definition: RosterItem.cs:343
Maintains the status of a field subscription rule.
Implements an XMPP sensor client interface.
Definition: SensorClient.cs:21
Task< SensorDataClientRequest > RequestReadout(string Destination, FieldType Types)
Requests a sensor data readout.
Task< SensorDataSubscriptionRequest > Subscribe(string Destination, FieldType Types, FieldSubscriptionRule[] Fields, bool ImmediateReadout)
Subscribes to sensor data readout.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
XmppState State
Current state of connection.
Definition: XmppClient.cs:985
string Language
Language of the client in the XMPP network.
Definition: XmppClient.cs:950
XmppClient Client
XMPP Client.
Contains a reference to a thing
Interface for nodes that can aggregate items in menues to descendant nodes.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Definition: ISniffer.cs:11
XmppState
State of XMPP connection.
Definition: XmppState.cs:7
FieldType
Field Type flags
Definition: FieldType.cs:10
CommandType
Command type.
Definition: ICommand.cs:11
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:13
static Duration FromMinutes(int Minutes)
Creates a Duration object from a given number of minutes.
Definition: Duration.cs:579
static Duration FromSeconds(int Seconds)
Creates a Duration object from a given number of seconds.
Definition: Duration.cs:589