Skip to content

Commit

Permalink
Merge pull request #188 from gglogowski/handle-obsolete-schema-in-swq…
Browse files Browse the repository at this point in the history
…l-studio

Add Filtering based on obsolete metadata. Filtering code refactoring.
  • Loading branch information
Víťa Tauer committed Jul 30, 2019
2 parents 56f9a18 + e631c6c commit ad55258
Show file tree
Hide file tree
Showing 22 changed files with 470 additions and 207 deletions.
12 changes: 11 additions & 1 deletion Src/SwqlStudio/MainForm.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Src/SwqlStudio/MainForm.cs
Expand Up @@ -418,6 +418,7 @@ private void preferencesToolStripMenuItem_DropDownOpening(object sender, EventAr
{
enableAutocompleteToolStripMenuItem.Checked = Settings.Default.AutocompleteEnabled;
promptToSaveOnCloseToolStripMenuItem.Checked = Settings.Default.PromptToSaveOnClose;
showObsoleteToolStripMenuItem.Checked = Settings.Default.ShowObsolete;
}

private void searchInTreeHotKeyToolStripMenuItem_Click(object sender, EventArgs e)
Expand Down Expand Up @@ -506,5 +507,12 @@ private void replaceToolStripMenuItem_Click(object sender, EventArgs e)

activeTab.ReplaceDialog();
}

private void showObsoleteToolStripMenuItem_Click(object sender, EventArgs e)
{
Settings.Default.ShowObsolete = !Settings.Default.ShowObsolete;
Settings.Default.Save();
filesDock.RefreshObjectExplorerFilters();
}
}
}
4 changes: 3 additions & 1 deletion Src/SwqlStudio/Metadata/Entity.cs
Expand Up @@ -2,7 +2,7 @@

namespace SwqlStudio.Metadata
{
public class Entity
public class Entity : IObsoleteMetadata
{
private readonly List<Property> properties = new List<Property>();
private readonly List<Verb> verbs = new List<Verb>();
Expand All @@ -12,6 +12,8 @@ public class Entity
public string BaseType { get; set; }
public bool IsIndication { get; set; }
public bool IsAbstract { get; set; }
public bool IsObsolete { get; set; }
public string ObsolescenceReason { get; set; }

public bool CanCreate { get; set; }
public bool CanDelete { get; set; }
Expand Down
8 changes: 8 additions & 0 deletions Src/SwqlStudio/Metadata/IObsoleteMetadata.cs
@@ -0,0 +1,8 @@
namespace SwqlStudio.Metadata
{
public interface IObsoleteMetadata
{
bool IsObsolete { get; set; }
string ObsolescenceReason { get; set; }
}
}
5 changes: 4 additions & 1 deletion Src/SwqlStudio/Metadata/Property.cs
@@ -1,13 +1,16 @@

namespace SwqlStudio.Metadata
{
public class Property : ITypedMetadata
public class Property : ITypedMetadata, IObsoleteMetadata
{
public string Name { get; set; }
public string Type { get; set; }
public bool IsNavigable { get; set; }
public bool IsInherited { get; set; }
public bool IsKey { get; set; }
public string Summary { get; set; }

public bool IsObsolete { get; set; }
public string ObsolescenceReason { get; set; }
}
}
49 changes: 33 additions & 16 deletions Src/SwqlStudio/Metadata/SwisMetaDataProvider.cs
Expand Up @@ -10,7 +10,7 @@ class SwisMetaDataProvider : IMetadataProvider
private readonly ConnectionInfo info;

private Dictionary<string, Entity> entities = new Dictionary<string, Entity>();

public SwisMetaDataProvider(ConnectionInfo info)
{
this.info = info;
Expand All @@ -19,22 +19,36 @@ public SwisMetaDataProvider(ConnectionInfo info)
}

private readonly Lazy<Capability> _capabilities;
private Capability Capabilities => _capabilities.Value;

public void Refresh()
private readonly IEnumerable<string> _metadataDefaultAttributes = new[]
{
"Entity.FullName", "Entity.Namespace", "Entity.BaseType",
"(Entity.Type ISA 'System.Indication') AS IsIndication",
"Entity.Properties.Name", "Entity.Properties.Type", "Entity.Properties.IsNavigable",
"Entity.Properties.IsInherited", "Entity.Properties.IsKey", "Entity.Verbs.EntityName", "Entity.Verbs.Name",
"Entity.IsAbstract"
};

private IEnumerable<string> AccessControlMetadataAttributes => Capabilities.HasFlag(Capability.AccessControl)
? new[] {"Entity.CanCreate", "Entity.CanDelete", "Entity.CanInvoke", "Entity.CanRead", "Entity.CanUpdate"}
: new string[0];

private IEnumerable<string> DocumentationMetadataAttributes => Capabilities.HasFlag(Capability.Documentation)
? new[] { "Entity.Summary", "Entity.Properties.Summary", "Entity.Verbs.Summary" }
: new string[0];

const string queryTemplate =
@"SELECT Entity.FullName, Entity.Namespace, Entity.BaseType, (Entity.Type ISA 'System.Indication') AS IsIndication,
Entity.Properties.Name, Entity.Properties.Type, Entity.Properties.IsNavigable, Entity.Properties.IsInherited, Entity.Properties.IsKey,
Entity.Verbs.EntityName, Entity.Verbs.Name, Entity.IsAbstract{0}{1}
FROM Metadata.Entity";
const string crudFragment =
", Entity.CanCreate, Entity.CanDelete, Entity.CanInvoke, Entity.CanRead, Entity.CanUpdate";
const string docFragment = ", Entity.Summary, Entity.Properties.Summary, Entity.Verbs.Summary";
private IEnumerable<string> ObsoleteMetadataAttributes => Capabilities.HasFlag(Capability.Obsolete)
? new[] { "Entity.IsObsolete", "Entity.ObsolescenceReason", "Entity.Properties.IsObsolete", "Entity.Properties.ObsolescenceReason",
"Entity.Verbs.IsObsolete", "Entity.Verbs.ObsolescenceReason" }
: new string[0];

var capabilities = _capabilities.Value;
string query = string.Format(queryTemplate, capabilities.HasFlag(Capability.AccessControl) ? crudFragment : string.Empty,
capabilities.HasFlag(Capability.Documentation) ? docFragment : string.Empty);
private IEnumerable<string> MetadataAttributes => _metadataDefaultAttributes
.Concat(AccessControlMetadataAttributes).Concat(DocumentationMetadataAttributes).Concat(ObsoleteMetadataAttributes);

public void Refresh()
{
string query = $"SELECT {string.Join(",", MetadataAttributes)} FROM Metadata.Entity";

entities = info.Query<Entity>(query).ToDictionary(entity => entity.FullName);

Expand All @@ -53,22 +67,25 @@ public enum Capability
None = 0,
AccessControl = 1,
Documentation = 2,
Obsolete = 4,
}

public Capability GetCapabilities()
{
const string query = @"SELECT Name
FROM Metadata.Property
WHERE EntityName='Metadata.Entity' AND Name IN ('CanCreate', 'Summary')";
WHERE EntityName='Metadata.Entity' AND Name IN ('CanCreate', 'Summary', 'IsObsolete')";

Capability cap = Capability.None;
DataTable dt = info.Query(query);
foreach (DataRow row in dt.Rows)
{
if ((string)row["Name"] == "CanCreate")
if ((string) row["Name"] == "CanCreate")
cap |= Capability.AccessControl;
else if ((string)row["Name"] == "Summary")
else if ((string) row["Name"] == "Summary")
cap |= Capability.Documentation;
else if ((string) row["Name"] == "IsObsolete")
cap |= Capability.Obsolete;
}

return cap;
Expand Down
5 changes: 4 additions & 1 deletion Src/SwqlStudio/Metadata/Verb.cs
Expand Up @@ -2,14 +2,17 @@

namespace SwqlStudio.Metadata
{
public class Verb
public class Verb : IObsoleteMetadata
{
private readonly List<VerbArgument> _arguments = new List<VerbArgument>();

public string Name { get; set; }
public string EntityName { get; set; }
public string Summary { get; set; }

public bool IsObsolete { get; set; }
public string ObsolescenceReason { get; set; }

public List<VerbArgument> Arguments
{
get { return _arguments;}
Expand Down
21 changes: 18 additions & 3 deletions Src/SwqlStudio/ObjectExplorer/DocumentationBuilder.cs
Expand Up @@ -47,6 +47,7 @@ private static Documentation VerbDocumentation(Verb verb)
{
var builder = new StringBuilder();
builder.AppendName(verb.Name);
builder.AppendObsoleteSection(verb);
builder.AppendSummaryParagraph(verb.Summary);
var docs = builder.ToString();
return new Documentation("Verb", docs);
Expand All @@ -58,6 +59,7 @@ private static Documentation EntityDocumentation(IMetadataProvider provider, Ent
builder.AppendName(entity.FullName);
builder.Append($"Base type: {entity.BaseType}\r\n");
builder.AppendAccessControl(provider.ConnectionInfo, entity);
builder.AppendObsoleteSection(entity);
builder.AppendSummaryParagraph(entity.Summary);
var docs = builder.ToString();
return new Documentation("Entity", docs);
Expand All @@ -75,8 +77,10 @@ private static Documentation NamespaceDocumentation(string nameSpace, int childr

private static Documentation PropertyDocumentation(Property property)
{
var docs = MetadataDocumentation(property);
return new Documentation("Property", docs);
var builder = new StringBuilder();
builder.Append(MetadataDocumentation(property));
builder.AppendObsoleteSection(property);
return new Documentation("Property", builder.ToString());
}

private static Documentation ProviderDocumentation(IMetadataProvider provider)
Expand All @@ -100,18 +104,29 @@ public static string ToToolTip(ITypedMetadata metadata)
builder.AppendSummary(metadata.Summary);
return builder.ToString();
}


public static string ToToolTip(ITypedMetadata metadata, IObsoleteMetadata obsoleteMetadata)
{
var builder = new StringBuilder();
builder.AppendSummary(metadata.Summary);
builder.AppendObsoleteSection(obsoleteMetadata);
return builder.ToString();
}


public static string ToToolTip(ConnectionInfo connection, Entity entity)
{
var builder = new StringBuilder();
builder.AppendSummary(entity.Summary);
builder.AppendObsoleteSection(entity);
return builder.ToString();
}

public static string ToToolTip(Verb verb)
{
var builder = new StringBuilder();
builder.AppendSummary(verb.Summary);
builder.AppendObsoleteSection(verb);
return builder.ToString();
}

Expand Down
10 changes: 10 additions & 0 deletions Src/SwqlStudio/ObjectExplorer/Filtering/INodeFilterStrategy.cs
@@ -0,0 +1,10 @@
using System.Windows.Forms;

namespace SwqlStudio.Filtering
{
internal interface INodeFilterStrategy
{
void Initialize(TreeNode node);
VisibilityStatus GetVisibility(TreeNode node);
}
}
77 changes: 77 additions & 0 deletions Src/SwqlStudio/ObjectExplorer/Filtering/NodeFilter.cs
@@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using SwqlStudio.Metadata;
using SwqlStudio.Properties;

namespace SwqlStudio.Filtering
{
internal class NodeFilter
{
private readonly List<INodeFilterStrategy> _filters = new List<INodeFilterStrategy>();
private const int _limitOfExpandedNodes = 5000;
private int _visibleNodesCount;

public NodeFilter(TreeView treeData, string filter)
{
InitializeFilters(treeData, filter);
}

private void InitializeFilters(TreeView treeData, string filter)
{
if (!Settings.Default.ShowObsolete)
{
_filters.Add(new ObsoleteNodeFilter());
}
if (filter != null)
{
_filters.Add(new SearchNodeFilter(filter));
}

TreeNodeUtils.IterateNodes(treeData, node => _filters.ForEach(strategy => strategy.Initialize(node)));

TreeNodeUtils.IterateNodes(treeData, node =>
{
if (FilterAction(node)) _visibleNodesCount++;
});
}

private VisibilityStatus NodeVisibility(TreeNode node) => _filters.Aggregate(VisibilityStatus.None, (current, filter) => current | filter.GetVisibility(node));

internal bool FilterAction(TreeNode node) => !NodeVisibility(node).HasFlag(VisibilityStatus.NotVisible);

internal void UpdateAction(TreeNode data, TreeNode display)
{
var nodeVisibility = NodeVisibility(data);

if (nodeVisibility.HasFlag(VisibilityStatus.ChildVisible))
// this one is not directly visible, gray it out
display.ForeColor = Color.LightBlue;

else if (nodeVisibility.HasFlag(VisibilityStatus.ParentVisible))
// this one is not directly visible, gray it out
display.ForeColor = Color.DarkGray;

// this one is visible directly, ensure it is visible (parents are expanded).
// it's children are visible as well, but may be not expanded
else if (nodeVisibility.HasFlag(VisibilityStatus.Visible))
{
//expand parents of visible node
if (_visibleNodesCount < _limitOfExpandedNodes)
{
display.EnsureVisible();
}
//If too many objects are visible, treeView performance drops dramatically.
//In case of many object only entity level is expanded
else
{
if (data.Tag is Entity)
{
display.EnsureVisible();
}
}
}
}
}
}

0 comments on commit ad55258

Please sign in to comment.