// 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 System.Windows.Media;
using Nova.CodeDOM;
namespace Nova.UI
{
/// <summary>
/// The view model for a <see cref="CodeDOM.Comment"/>.
/// </summary>
public class CommentVM : CommentBaseVM
{
#region /* STATICS */
internal static void AddViewModelMapping()
{
CreateViewModel.Add(typeof(Comment),
delegate(CodeObject codeObject, bool isDescription, Dictionary<CodeObject, CodeObjectVM> dictionary) { return new CommentVM((Comment)codeObject, dictionary); });
}
#endregion
#region /* CONSTRUCTORS */
/// <summary>
/// Create a view model instance for the specified <see cref="CodeDOM.Comment"/>.
/// </summary>
public CommentVM(Comment comment, Dictionary<CodeObject, CodeObjectVM> dictionary)
: base(comment, dictionary)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// The underlying <see cref="CodeDOM.Comment"/> model.
/// </summary>
public Comment Comment
{
get { return (Comment)CodeObject; }
}
#endregion
#region /* METHODS */
#endregion
#region /* RENDERING */
/// <summary>
/// Determines if comment text is rendered with a proportional font instead of a fixed font.
/// </summary>
public static bool UseProportionalFont;
public static readonly Brush StaticBorderBrush = Brushes.LightGray;
public static readonly Brush StaticBackgroundBrush = Brushes.White;
public override Brush BorderBrush
{
get { return StaticBorderBrush; }
}
public override Brush BackgroundBrush
{
get { return StaticBackgroundBrush; }
}
public override int BorderHPad
{
get { return 2; }
}
public override int BorderVPad
{
get { return 1; }
}
public override void Render(CodeRenderer renderer, RenderFlags flags)
{
if (HideAll) return;
Comment comment = Comment;
bool isEOL = comment.IsEOL;
bool isInline = flags.HasFlag(RenderFlags.CommentsInline);
bool isBlock = (comment.IsBlock || isInline);
bool isRawFormat = comment.IsRawFormat;
int newLines = comment.NewLines;
bool isPrefix = flags.HasFlag(RenderFlags.IsPrefix);
if (!isPrefix)
{
if (newLines > 0)
{
if (!flags.HasFlag(RenderFlags.SuppressNewLine))
renderer.NewLines(newLines, ParentVM);
}
else if (!comment.IsInfix || isEOL)
renderer.RenderText(isBlock ? " " : " ", PUNC_BRUSH, ParentVM is BlockVM ? ParentVM.ParentVM : ParentVM);
}
CreateBorder(renderer, flags);
TextStyle textStyle = (UseProportionalFont ? TextStyle.Proportional : TextStyle.Normal);
string space = (comment.NoSpaceAfterDelimiter ? "" : " ");
string text = comment.Text;
if (text != null)
{
if (comment.IsTODO || comment.IsHack)
{
// Render special comments such that we can use a different color for the text portion
if (isEOL || isInline)
{
// Render a single-line EOL or in-line block comment.
// There shouldn't be any newlines in the comment, but handle them just in case.
if (!HideDelimiters)
renderer.RenderText((isBlock ? Comment.ParseTokenBlockStart : Comment.ParseToken) + space, COMMENT_BRUSH, this);
renderer.RenderText(text.Replace("\n", "; "), COMMENT_SPECIAL_BRUSH, TextStyle.Bold | TextStyle.NoCache, this);
if (isBlock && !HideDelimiters)
renderer.RenderText((text.EndsWith("*") ? "" : space) + Comment.ParseTokenBlockEnd, COMMENT_BRUSH, this);
}
else
{
// Render a multi-line comment or block comment
string[] lines = text.Split('\n');
bool lastIsEmpty = true;
for (int i = 0; i < lines.Length; ++i)
{
string line = lines[i];
lastIsEmpty = (isBlock && (i == lines.Length - 1) && string.IsNullOrEmpty(line));
if (i > 0 && !(lastIsEmpty && HideDelimiters))
renderer.NewLine();
if (!HideDelimiters)
{
renderer.RenderText(isBlock ? (i == 0 ? Comment.ParseTokenBlockStart + space : (isRawFormat ? "" : (lastIsEmpty ? " " : " *" + space)))
: Comment.ParseToken + space, COMMENT_BRUSH, this);
}
if (lastIsEmpty)
break;
renderer.RenderText(line, COMMENT_SPECIAL_BRUSH, textStyle | TextStyle.Bold | TextStyle.NoCache, this);
}
if (isBlock && !HideDelimiters)
renderer.RenderText(((isRawFormat || lastIsEmpty || text.EndsWith("*")) ? "" : space) + Comment.ParseTokenBlockEnd, COMMENT_BRUSH, this);
}
}
else
{
// Render regular comments as a single string for efficiency
string commentText;
if (isEOL || isInline)
{
// Render a single-line EOL or in-line block comment.
// There shouldn't be any newlines in the comment, but handle them just in case.
commentText = (HideDelimiters ? "" : (isBlock ? Comment.ParseTokenBlockStart : Comment.ParseToken) + space)
+ text.Replace("\n", "; ") + ((isBlock && !HideDelimiters) ? ((text.EndsWith("*") ? "" : space) + Comment.ParseTokenBlockEnd) : "");
}
else
{
// Render a multi-line comment or block comment
commentText = null;
string[] lines = text.Split('\n');
bool lastIsEmpty = true;
for (int i = 0; i < lines.Length; ++i)
{
string line = lines[i];
lastIsEmpty = (isBlock && (i == lines.Length - 1) && string.IsNullOrEmpty(line));
if (i > 0 && !(lastIsEmpty && HideDelimiters))
commentText += '\n';
if (!HideDelimiters)
commentText += (isBlock ? (i == 0 ? Comment.ParseTokenBlockStart + space : (isRawFormat ? "" : (lastIsEmpty ? " " : " *" + space))) : Comment.ParseToken + space);
commentText += line;
}
if (isBlock && !HideDelimiters)
commentText += ((isRawFormat || lastIsEmpty || text.EndsWith("*")) ? "" : space) + Comment.ParseTokenBlockEnd;
}
renderer.RenderText(commentText, COMMENT_BRUSH, textStyle | TextStyle.NoCache, this);
}
}
renderer.ReturnToBorderParent(this);
if (isPrefix)
{
// If this object is rendered as a child prefix object of another, then any whitespace is
// rendered here *after* the object instead of before it.
if (newLines > 0)
renderer.NewLines(newLines, ParentVM);
else
renderer.RenderText(" ", PUNC_BRUSH, ParentVM);
}
}
public override void RenderToolTip(CodeRenderer renderer, RenderFlags flags)
{
TypeRefBaseVM.RenderType(renderer, CodeObject.GetType(), flags, this);
renderer.RenderText(" : ", NORMAL_BRUSH, TextStyle.Proportional | TextStyle.Bold);
string flagsString = Comment.FlagsAsText();
if (flagsString != "None")
renderer.RenderText(flagsString + ", ", NORMAL_BRUSH, TextStyle.Proportional);
renderer.RenderText("Parent = ", NORMAL_BRUSH, TextStyle.Proportional);
ParentVM.Render(renderer, RenderFlags.Description | RenderFlags.SuppressNewLine | RenderFlags.ForceBorder);
RenderMessagesInToolTip(renderer, flags);
}
#endregion
#region /* COMMANDS */
public static readonly RoutedCommand UseProportionalFontCommand = new RoutedCommand("Use Proportional Font for Comments", typeof(CommentVM));
public static new void BindCommands(Window window)
{
WPFUtil.AddCommandBinding(window, UseProportionalFontCommand, proportionalComment_Executed);
}
private static void proportionalComment_Executed(object sender, ExecutedRoutedEventArgs e)
{
UseProportionalFont = !UseProportionalFont;
CodeRenderer.ReRenderAll();
}
#endregion
}
}