// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using Nova.CodeDOM;
using Expression = Nova.CodeDOM.Expression;
namespace Nova.UI
{
/// <summary>
/// The view model for a <see cref="CodeDOM.Statement"/>.
/// </summary>
public abstract class StatementVM : CodeObjectVM
{
#region /* CONSTRUCTORS */
/// <summary>
/// Create a view model instance for the specified <see cref="CodeDOM.Statement"/>.
/// </summary>
protected StatementVM(Statement statement, Dictionary<CodeObject, CodeObjectVM> dictionary)
: base(statement, dictionary)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// The underlying <see cref="CodeDOM.Statement"/> model.
/// </summary>
public Statement Statement
{
get { return (Statement)CodeObject; }
}
#endregion
#region /* RENDERING */
public override int BorderHPad
{
get { return 2; }
}
public override int BorderVPad
{
get { return 1; }
}
/// <summary>
/// Determines if terminators should be hidden.
/// </summary>
public static bool HideTerminators;
/// <summary>
/// Determines if statement argument parens should be hidden.
/// </summary>
public static bool HideStatementParens;
protected virtual void RenderPrefix(CodeRenderer renderer, RenderFlags flags)
{ }
protected virtual void RenderStatement(CodeRenderer renderer, RenderFlags flags)
{
renderer.RenderText(Statement.Keyword, KEYWORD_BRUSH, this);
}
protected virtual void RenderArgumentPrefix(CodeRenderer renderer, RenderFlags flags)
{
renderer.RenderText(" ", PUNC_BRUSH, this);
}
protected virtual void RenderArgument(CodeRenderer renderer, RenderFlags flags)
{ }
protected virtual void RenderSuffix(CodeRenderer renderer, RenderFlags flags)
{
if (!flags.HasFlag(RenderFlags.Description))
RenderTerminator(renderer, flags);
}
protected internal void RenderTerminator(CodeRenderer renderer, RenderFlags flags)
{
if (Statement.HasTerminator && !HideTerminators)
renderer.RenderText(Statement.Terminator, PUNC_BRUSH, this);
}
protected override void RenderAfter(CodeRenderer renderer, RenderFlags flags)
{
if (!flags.HasFlag(RenderFlags.NoPostAnnotations))
RenderAnnotations(renderer, AnnotationFlags.IsPostfix, flags);
}
protected virtual bool RenderParens()
{
return !HideStatementParens;
}
public override void Render(CodeRenderer renderer, RenderFlags flags)
{
int newLines = Statement.NewLines;
bool isPrefix = flags.HasFlag(RenderFlags.IsPrefix);
if (!isPrefix && newLines > 0)
{
if (!flags.HasFlag(RenderFlags.SuppressNewLine))
renderer.NewLines(newLines, ParentVM);
}
else if (flags.HasFlag(RenderFlags.PrefixSpace))
renderer.RenderText(" ", PUNC_BRUSH, ParentVM);
flags &= ~RenderFlags.SuppressNewLine;
bool increaseIndent = flags.HasFlag(RenderFlags.IncreaseIndent);
if (!flags.HasFlag(RenderFlags.NoBorder))
{
CreateBorder(renderer, flags);
increaseIndent = true; // Always increase the indent level for wrapped lines inside a border
}
RenderFlags passFlags = (flags & RenderFlags.PassMask);
RenderBefore(renderer, passFlags | RenderFlags.IsPrefix);
// Increase the indent level for any newlines that occur within the statement if the flag is set
if (increaseIndent)
renderer.IndentOnNewLineBegin(this);
RenderPrefix(renderer, flags);
RenderStatement(renderer, flags);
if (Statement.HasArgument)
{
RenderArgumentPrefix(renderer, passFlags);
bool showParens = Statement.HasArgumentParens && RenderParens();
if (showParens)
renderer.RenderText(Expression.ParseTokenStartGroup, PUNC_BRUSH, this);
RenderArgument(renderer, passFlags | RenderFlags.ForceBorder);
if (showParens)
{
if (Statement.IsEndFirstOnLine)
renderer.NewLine();
renderer.RenderText(Expression.ParseTokenEndGroup, PUNC_BRUSH, this);
}
}
RenderSuffix(renderer, flags);
RenderEOLComments(renderer, flags);
if (increaseIndent)
renderer.IndentOnNewLineEnd(this);
RenderAfter(renderer, passFlags | (flags & RenderFlags.NoPostAnnotations));
// If we have a border, return to the previous one
if (!flags.HasFlag(RenderFlags.NoBorder))
renderer.ReturnToBorderParent(this);
if (isPrefix)
{
// If this object is rendered as a child prefix object of another, then IsFirstOnLine actually
// represents IsLastOnLine, and we render the whitespace here at the end instead of at the top.
if (newLines > 0)
renderer.NewLines(newLines, ParentVM);
else
renderer.RenderText(" ", PUNC_BRUSH, ParentVM);
}
}
#endregion
#region /* COMMANDS */
public static readonly RoutedCommand HideTerminatorsCommand = new RoutedCommand("Hide Terminators", typeof(StatementVM));
public static readonly RoutedCommand HideStatementParensCommand = new RoutedCommand("Hide Statement Parens", typeof(StatementVM));
public static new void BindCommands(Window window)
{
WPFUtil.AddCommandBinding(window, HideTerminatorsCommand, hideTerminators_Executed);
WPFUtil.AddCommandBinding(window, HideStatementParensCommand, hideParens_Executed);
}
private static void hideTerminators_Executed(object sender, ExecutedRoutedEventArgs e)
{
HideTerminators = !HideTerminators;
CodeRenderer.ReRenderAll();
}
private static void hideParens_Executed(object sender, ExecutedRoutedEventArgs e)
{
HideStatementParens = !HideStatementParens;
CodeRenderer.ReRenderAll();
}
#endregion
}
}