public void ComposeTableRow(TemplateNodeInfo node, out ITableRow nodeRow, out List<ITableRow> attributesRows)
        {
            Debug.Assert(node.IsInstance);

            Int64? parentNodeId = null;

            if (node.Parent != null)
            {
                if (node.Parent.TemplateNodeId == null)
                {
                    throw new InvalidOperationException(node + ": it's parent is not saved (has no id)");
                }

                parentNodeId = node.Parent.TemplateNodeId;
            }

            nodeRow = new TableRow(this.TableDefinition);
            node.ConnectionGroup.ReadGroupIdFrom(this._storage.ConnectionGroupDirectory);

            nodeRow.Values.Add(
                ConnectionIdFn,
                node.ConnectionGroup.Identity
            );

            nodeRow.Values.Add(
                TemplateNodeIdFn,
                this._storage.TemplateNodeDirectory.GetId(node.ConnectionGroup, node.Template)
            );

            nodeRow.Values.Add(ParentIdFn,      parentNodeId);
            nodeRow.Values.Add(NodeUIdFn,       node.UId);
            nodeRow.Values.Add(NodeUNameFn,     node.UName);
            nodeRow.Values.Add(NodeUIconFn,     node.IconImageReferenceName);
            nodeRow.Values.Add(NodeEnabledFn,  !node.IsDisabled);
            nodeRow.Values.Add(NodeFontColorFn, node.FontColor);
            nodeRow.Values.Add(NodeFontStyleFn, node.FontStyle);

            if (node.CounterValue != null)
            {
                nodeRow.Values.Add(NodeCounterValue, node.CounterValue);
            }

            nodeRow.Values.Add(
                NodeSequenceNumberFn,
                node.Parent != null ? node.Parent.Childs.IndexOf(node) : 0
            );

            List<TemplateNodeUpdateJob> jobs = node.GetRefreshJob(true);

            foreach (TemplateNodeUpdateJob job in jobs)
            {
                if (job != null && job.LastRan != null)
                {
                    nodeRow.Values.Add(NodeScheduledUpdateFn, job.LastRan);
                }
            }

            attributesRows = new List<ITableRow>();

            foreach (KeyValuePair<string, string> pair in node.Attributes.Values)
            {
                ITableRow row = new TableRow(NodeInstanceAttributeTable.CreateTableDefinition());

                row.Values.Add(NodeInstanceAttributeTable.NameFn, pair.Key);
                row.Values.Add(NodeInstanceAttributeTable.ValueFn, pair.Value);

                attributesRows.Add(row);
            }
        }
		private void UpdateScheduledDate(TemplateNodeInfo nodeInfo)
		{
			string sNextUpdateDateTime = ComposeBlankDateTimeString();

			if (nodeInfo != null)
			{
				IEnumerable<TemplateNodeUpdateJob> updateJobs = nodeInfo.GetRefreshJob(true)
					.Where(job => job != null && !job.IsEmpty());

				DateTime? nearestUpdateDate = null;

				foreach (TemplateNodeUpdateJob updateJob in updateJobs)
				{
					DateTime nextDate;

					if (updateJob.Settings.GetNextTime(DateTime.Now, out nextDate))
					{
						if (nearestUpdateDate != null)
						{
							if (nextDate.CompareTo(nearestUpdateDate) < 0)
							{
								nearestUpdateDate = nextDate;
							}
						}
						else
						{
							nearestUpdateDate = nextDate;
						}
					}
				}

				if (nearestUpdateDate != null)
				{
					sNextUpdateDateTime = nearestUpdateDate.Value.ToString();
				}
			}

			this.SafeInvoke(() =>
			{
				lbNextUpdateDateTime.Text = sNextUpdateDateTime;
			});
		}