Planner: Added the ability to parse group based parameters that link to .cpp files.

This commit is contained in:
Adam M Rivera 2012-04-25 12:11:44 -05:00
parent 3309dec205
commit 155928adef
6 changed files with 270 additions and 91 deletions

View File

@ -226,7 +226,8 @@
<Compile Include="Attributes\DisplayTextAttribute.cs" /> <Compile Include="Attributes\DisplayTextAttribute.cs" />
<Compile Include="Attributes\PrivateAttribute.cs" /> <Compile Include="Attributes\PrivateAttribute.cs" />
<Compile Include="CodeGen.cs" /> <Compile Include="CodeGen.cs" />
<Compile Include="Constants\ParameterMetaDataConstants.cs" /> <Compile Include="Utilities\CollectionExtensions.cs" />
<Compile Include="Utilities\Constants\ParameterMetaDataConstants.cs" />
<Compile Include="Controls\BackstageView\BackstageView.cs"> <Compile Include="Controls\BackstageView\BackstageView.cs">
<SubType>UserControl</SubType> <SubType>UserControl</SubType>
</Compile> </Compile>

View File

@ -1,12 +0,0 @@
namespace ArdupilotMega.Constants
{
public sealed class ParameterMetaDataConstants
{
public const string Delimeter = "@";
public const string Param = "Param";
public const string DisplayName = "DisplayName";
public const string Description = "Description";
public const string Units = "Units";
public const string Range = "Range";
}
}

View File

@ -1,20 +1,14 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Configuration;
using System.Drawing; using System.Drawing;
using System.Data;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Xml.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using ArdupilotMega.Constants;
using ArdupilotMega.Utilities; using ArdupilotMega.Utilities;
using ArdupilotMega.Utilities.Constants;
using log4net; using log4net;
using ArdupilotMega.Controls.BackstageView; using ArdupilotMega.Controls.BackstageView;
using ArdupilotMega.Controls;
namespace ArdupilotMega.GCSViews.ConfigurationView namespace ArdupilotMega.GCSViews.ConfigurationView
{ {

View File

@ -0,0 +1,47 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ArdupilotMega.Utilities
{
public static class CollectionExtensions
{
/// <summary>
/// Performs the specified <paramref name="action"/> on each element of the <paramref name="enumerable"/>.
///
/// </summary>
/// <param name="enumerable">An enumerable instance.
/// </param><param name="action"/>
public static void ForEach(this IEnumerable enumerable, Action<object> action)
{
foreach (object obj in enumerable)
action(obj);
}
/// <summary>
/// Performs the specified <paramref name="action"/> on each element of the <paramref name="enumerable"/>.
///
/// </summary>
/// <param name="enumerable">An enumerable instance.
/// </param><param name="action"/>
public static void ForEach<T>(this IEnumerable enumerable, Action<T> action)
{
foreach (T obj in enumerable)
action(obj);
}
/// <summary>
/// Performs the specified <paramref name="action"/> on each element of the <paramref name="enumerable"/>.
///
/// </summary>
/// <typeparam name="T">The type contained in the <paramref name="enumerable"/>.
/// </typeparam><param name="enumerable"/><param name="action"/>
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (T obj in enumerable)
action(obj);
}
}
}

View File

@ -0,0 +1,24 @@
namespace ArdupilotMega.Utilities.Constants
{
public sealed class ParameterMetaDataConstants
{
#region Markers
public const string ParamDelimeter = "@";
public const string PathDelimeter = ",";
public const string Param = "Param";
public const string Lib = "Lib";
public const string Path = "Path";
#endregion
#region Meta Keys
public const string DisplayName = "DisplayName";
public const string Description = "Description";
public const string Units = "Units";
public const string Range = "Range";
#endregion
}
}

View File

@ -7,14 +7,15 @@ using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
using System.Xml; using System.Xml;
using ArdupilotMega.Constants; using ArdupilotMega.Utilities.Constants;
using log4net; using log4net;
namespace ArdupilotMega.Utilities namespace ArdupilotMega.Utilities
{ {
public static class ParameterMetaDataParser public static class ParameterMetaDataParser
{ {
private static readonly Regex _paramMetaRegex = new Regex(String.Format("{0}(?<MetaKey>[^:]+):(?<MetaValue>.+)", ParameterMetaDataConstants.Delimeter)); private static readonly Regex _paramMetaRegex = new Regex(String.Format("{0}(?<MetaKey>[^:]+):(?<MetaValue>.+)", ParameterMetaDataConstants.ParamDelimeter));
private static readonly Regex _parentDirectoryRegex = new Regex("(?<ParentDirectory>[../]*)(?<Path>.+)");
private static readonly ILog log = private static readonly ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
@ -35,51 +36,16 @@ namespace ArdupilotMega.Utilities
foreach (string parameterLocation in parameterLocations) foreach (string parameterLocation in parameterLocations)
{ {
log.Info(parameterLocation); // Write the start element for this parameter location
objXmlTextWriter.WriteStartElement(parameterLocation);
var request = WebRequest.Create(parameterLocation); // Read and parse the content.
string dataFromAddress = ReadDataFromAddress(parameterLocation);
ParseLibInformation(dataFromAddress, objXmlTextWriter, parameterLocation);
ParseParameterInformation(dataFromAddress, objXmlTextWriter);
// Plenty of timeout // Write the end element for this parameter location
request.Timeout = 10000; objXmlTextWriter.WriteEndElement();
// Set the Method property of the request to GET.
request.Method = "GET";
// Get the response.
using (var response = request.GetResponse())
{
// Display the status.
log.Info(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
using (var dataStream = response.GetResponseStream())
{
if (dataStream != null)
{
// Open the stream using a StreamReader for easy access.
using (var reader = new StreamReader(dataStream))
{
// Write the start element for this parameter location
objXmlTextWriter.WriteStartElement(parameterLocation);
// Read and parse the content.
ParseParameterInformation(reader.ReadToEnd(), objXmlTextWriter);
// Write the end element for this parameter location
objXmlTextWriter.WriteEndElement();
// Close the reader
reader.Close();
}
// Close the datastream
dataStream.Close();
}
}
// Close the response
response.Close();
}
} }
@ -91,6 +57,67 @@ namespace ArdupilotMega.Utilities
} }
} }
/// <summary>
/// Parses the lib information.
/// </summary>
/// <param name="fileContents">The file contents.</param>
/// <param name="objXmlTextWriter">The obj XML text writer.</param>
/// <param name="parameterLocation">The parameter location.</param>
private static void ParseLibInformation(string fileContents, XmlTextWriter objXmlTextWriter, string parameterLocation)
{
var parsedInformation = ParseKeyValuePairs(fileContents, ParameterMetaDataConstants.Lib);
if (parsedInformation != null && parsedInformation.Count > 0)
{
// node is the prefix of the parameter group here
parsedInformation.ForEach(node =>
{
// node.Value is a nested dictionary containing the additional meta data
// In this case we are looking for the @Path key
if (node.Value != null && node.Value.Count > 0)
{
// Find the @Path key
node.Value
.Where(meta => meta.Key == ParameterMetaDataConstants.Path)
// We might have multiple paths to inspect, so break them out by the delimeter
.ForEach(path => path.Value.Split(new []{ ParameterMetaDataConstants.PathDelimeter }, StringSplitOptions.None)
.ForEach(separatedPath =>
{
// Match based on the regex defined at the top of this class
Match pathMatch = _parentDirectoryRegex.Match(separatedPath);
if (pathMatch.Success && pathMatch.Groups["Path"] != null && !String.IsNullOrEmpty(pathMatch.Groups["Path"].Value))
{
if (pathMatch.Groups["ParentDirectory"] != null && !String.IsNullOrEmpty(pathMatch.Groups["ParentDirectory"].Value))
{
// How many directories from the original path do we have to move
int numberOfParentDirectoryMoves = pathMatch.Groups["ParentDirectory"].Value.Split(new string[] { "../" }, StringSplitOptions.None).Count();
// We need to remove the http:// or https:// prefix to build the new URL properly
string httpTest = parameterLocation.Substring(0, 7);
int trimHttpPrefixIdx = httpTest == "http://" ? 7 : 8;
// Get the parts of the original URL
var parameterLocationParts = parameterLocation.Substring(trimHttpPrefixIdx, parameterLocation.Length - trimHttpPrefixIdx).Split(new char[] { '/' });
// Rebuild the new url taking into account the numberOfParentDirectoryMoves
string urlAfterParentDirectory = string.Empty;
for (int i = 0; i < parameterLocationParts.Length && i < parameterLocationParts.Length - numberOfParentDirectoryMoves; i++)
{
urlAfterParentDirectory += parameterLocationParts[i] + "/";
}
// This is the URL of the file we need to parse for comments
string newPath = String.Format("{0}{1}{2}", parameterLocation.Substring(0, trimHttpPrefixIdx), urlAfterParentDirectory, pathMatch.Groups["Path"].Value);
// Parse the param info from the newly constructed URL
ParseParameterInformation(ReadDataFromAddress(newPath), objXmlTextWriter, node.Key);
}
}
}));
}
});
}
}
/// <summary> /// <summary>
/// Parses the parameter information. /// Parses the parameter information.
/// </summary> /// </summary>
@ -98,8 +125,50 @@ namespace ArdupilotMega.Utilities
/// <param name="objXmlTextWriter">The obj XML text writer.</param> /// <param name="objXmlTextWriter">The obj XML text writer.</param>
private static void ParseParameterInformation(string fileContents, XmlTextWriter objXmlTextWriter) private static void ParseParameterInformation(string fileContents, XmlTextWriter objXmlTextWriter)
{ {
ParseParameterInformation(fileContents, objXmlTextWriter, string.Empty);
}
/// <summary>
/// Parses the parameter information.
/// </summary>
/// <param name="fileContents">The file contents.</param>
/// <param name="objXmlTextWriter">The obj XML text writer.</param>
/// <param name="parameterPrefix">The parameter prefix.</param>
private static void ParseParameterInformation(string fileContents, XmlTextWriter objXmlTextWriter, string parameterPrefix)
{
var parsedInformation = ParseKeyValuePairs(fileContents, ParameterMetaDataConstants.Param);
if(parsedInformation != null && parsedInformation.Count > 0)
{
parsedInformation.ForEach(node =>
{
objXmlTextWriter.WriteStartElement(String.Format("{0}{1}", parameterPrefix, node.Key));
if (node.Value != null && node.Value.Count > 0)
{
node.Value.ForEach(meta =>
{
// Write the key value pair to XML
objXmlTextWriter.WriteStartElement(meta.Key);
objXmlTextWriter.WriteString(meta.Value);
objXmlTextWriter.WriteEndElement();
});
}
objXmlTextWriter.WriteEndElement();
});
}
}
/// <summary>
/// Parses the parameter information.
/// </summary>
/// <param name="fileContents">The file contents.</param>
/// <param name="nodeKey">The node key.</param>
/// <returns></returns>
private static Dictionary<string, Dictionary<string, string>> ParseKeyValuePairs(string fileContents, string nodeKey)
{
var returnDict = new Dictionary<string, Dictionary<string, string>>();
var indicies = new List<int>(); var indicies = new List<int>();
GetIndexOfMarkers(ref indicies, fileContents, ParameterMetaDataConstants.Delimeter + ParameterMetaDataConstants.Param, 0); GetIndexOfMarkers(ref indicies, fileContents, ParameterMetaDataConstants.ParamDelimeter + nodeKey, 0);
if(indicies.Count > 0) if(indicies.Count > 0)
{ {
@ -114,7 +183,7 @@ namespace ArdupilotMega.Utilities
if(!String.IsNullOrEmpty(subStringToSearch)) if(!String.IsNullOrEmpty(subStringToSearch))
{ {
var metaIndicies = new List<int>(); var metaIndicies = new List<int>();
GetIndexOfMarkers(ref metaIndicies, subStringToSearch, ParameterMetaDataConstants.Delimeter, 0); GetIndexOfMarkers(ref metaIndicies, subStringToSearch, ParameterMetaDataConstants.ParamDelimeter, 0);
if(metaIndicies.Count > 0) if(metaIndicies.Count > 0)
{ {
@ -124,40 +193,43 @@ namespace ArdupilotMega.Utilities
// Match based on the regex defined at the top of this class // Match based on the regex defined at the top of this class
Match paramNameKeyMatch = _paramMetaRegex.Match(paramNameKey); Match paramNameKeyMatch = _paramMetaRegex.Match(paramNameKey);
if (paramNameKeyMatch.Success && paramNameKeyMatch.Groups["MetaKey"].Value == ParameterMetaDataConstants.Param) if (paramNameKeyMatch.Success && paramNameKeyMatch.Groups["MetaKey"].Value == nodeKey)
{ {
objXmlTextWriter.WriteStartElement(paramNameKeyMatch.Groups["MetaValue"].Value.Trim(new char[] { ' ' })); string key = paramNameKeyMatch.Groups["MetaValue"].Value.Trim(new char[] {' '});
var metaDict = new Dictionary<string, string>();
// Loop through the indicies of the meta data found if(!returnDict.ContainsKey(key))
for (int x = 1; x < metaIndicies.Count; x++)
{ {
// This is the end index for a substring to search for parameter attributes // Loop through the indicies of the meta data found
// If we are on the last index in our collection, we will search to the end of the file for (int x = 1; x < metaIndicies.Count; x++)
var stopMetaIdx = (x == metaIndicies.Count - 1) ? subStringToSearch.Length : metaIndicies[x + 1];
// This meta param string
var metaString = subStringToSearch.Substring(metaIndicies[x], (stopMetaIdx - metaIndicies[x]));
// Match based on the regex defined at the top of this class
Match metaMatch = _paramMetaRegex.Match(metaString);
// Test for success
if (metaMatch.Success)
{ {
// Write the key value pair to XML // This is the end index for a substring to search for parameter attributes
objXmlTextWriter.WriteStartElement(metaMatch.Groups["MetaKey"].Value.Trim(new char[] { ' ' })); // If we are on the last index in our collection, we will search to the end of the file
objXmlTextWriter.WriteString(metaMatch.Groups["MetaValue"].Value.Trim(new char[] { ' ' })); var stopMetaIdx = (x == metaIndicies.Count - 1) ? subStringToSearch.Length : metaIndicies[x + 1];
objXmlTextWriter.WriteEndElement();
// This meta param string
var metaString = subStringToSearch.Substring(metaIndicies[x], (stopMetaIdx - metaIndicies[x]));
// Match based on the regex defined at the top of this class
Match metaMatch = _paramMetaRegex.Match(metaString);
// Test for success
if (metaMatch.Success)
{
string metaKey = metaMatch.Groups["MetaKey"].Value.Trim(new char[] {' '});
if(!metaDict.ContainsKey(metaKey))
{
metaDict.Add(metaKey, metaMatch.Groups["MetaValue"].Value.Trim(new char[] { ' ' }));
}
}
} }
} }
returnDict.Add(key, metaDict);
// End this parameter node
objXmlTextWriter.WriteEndElement();
} }
} }
} }
} }
} }
return returnDict;
} }
/// <summary> /// <summary>
@ -189,5 +261,58 @@ namespace ArdupilotMega.Utilities
} }
} }
} }
/// <summary>
/// Reads the data from address.
/// </summary>
/// <param name="address">The address.</param>
/// <returns></returns>
private static string ReadDataFromAddress(string address)
{
string data = string.Empty;
log.Info(address);
var request = WebRequest.Create(address);
// Plenty of timeout
request.Timeout = 10000;
// Set the Method property of the request to GET.
request.Method = "GET";
// Get the response.
using (var response = request.GetResponse())
{
// Display the status.
log.Info(((HttpWebResponse) response).StatusDescription);
// Get the stream containing content returned by the server.
using (var dataStream = response.GetResponseStream())
{
if (dataStream != null)
{
// Open the stream using a StreamReader for easy access.
using (var reader = new StreamReader(dataStream))
{
// Store the data to return
data = reader.ReadToEnd();
// Close the reader
reader.Close();
}
// Close the datastream
dataStream.Close();
}
}
// Close the response
response.Close();
}
// Return the data
return data;
}
} }
} }