SuperDesign/Source/RySmartEditor/Controls/ScintillaDiffer/ScintillaDiffControl.cs
zilinsoft 993f1ca1a9 ### 2024-12-20 星期五更新
------
#### SuperDesign    V3.0.2412.2001
- *.[新增]新增程序更新日志设置和自动发布功能。
- *.[修复]修复Post数据格式不正确时双击文本框会导致软件闪退的BUG。
2024-12-20 08:15:19 +08:00

1654 lines
64 KiB
C#

#region License
/*
MIT License
Copyright(c) 2020 Petteri Kautonen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using DiffPlex;
using DiffPlex.DiffBuilder;
using DiffPlex.DiffBuilder.Model;
using DiffPlex.Model;
using ScintillaDiff.Enumerations;
using ScintillaDiff.UtilityClasses;
using ScintillaNET;
using static ScintillaDiff.ScintillaDiffStyles;
namespace ScintillaDiff
{
/// <summary>
/// A control for comparing two text files using <see cref="Scintilla"/> controls.
/// Implements the <see cref="System.Windows.Forms.UserControl" />
/// </summary>
/// <seealso cref="System.Windows.Forms.UserControl" />
public partial class ScintillaDiffControl : UserControl
{
/// <summary>
/// Initializes a new instance of the <see cref="ScintillaDiffControl"/> class.
/// </summary>
public ScintillaDiffControl()
{
InitializeComponent();
if(!this.DesignMode)
{
//
// scintillaOne
//
scintillaOne = new ScrollSyncScintilla();
this.scintillaOne.AutoCMaxHeight = 9;
this.scintillaOne.BiDirectionality = ScintillaNET.BiDirectionalDisplayType.Disabled;
this.scintillaOne.CaretLineBackColor = System.Drawing.Color.White;
this.scintillaOne.CaretLineVisible = true;
this.scintillaOne.Dock = System.Windows.Forms.DockStyle.Fill;
this.scintillaOne.LexerName = null;
this.scintillaOne.Location = new System.Drawing.Point(0, 23);
this.scintillaOne.ScrollSync = this.scintillaTwo;
this.scintillaOne.ScrollWidth = 1;
this.scintillaOne.Size = new System.Drawing.Size(434, 431);
this.scintillaOne.TabIndents = true;
this.scintillaOne.TabIndex = 0;
this.scintillaOne.UseRightToLeftReadingLayout = false;
this.scintillaOne.WrapMode = ScintillaNET.WrapMode.None;
this.scintillaOne.TextChanged += new System.EventHandler(this.Scintilla_TextChanged);
//
// scintillaTwo
//
scintillaTwo = new ScrollSyncScintilla();
this.scintillaTwo.AutoCMaxHeight = 9;
this.scintillaTwo.BiDirectionality = ScintillaNET.BiDirectionalDisplayType.Disabled;
this.scintillaTwo.CaretLineBackColor = System.Drawing.Color.White;
this.scintillaTwo.CaretLineVisible = true;
this.scintillaTwo.Dock = System.Windows.Forms.DockStyle.Fill;
this.scintillaTwo.LexerName = null;
this.scintillaTwo.Location = new System.Drawing.Point(0, 23);
this.scintillaTwo.ScrollSync = this.scintillaOne;
this.scintillaTwo.ScrollWidth = 1;
this.scintillaTwo.Size = new System.Drawing.Size(480, 431);
this.scintillaTwo.TabIndents = true;
this.scintillaTwo.TabIndex = 0;
this.scintillaTwo.UseRightToLeftReadingLayout = false;
this.scintillaTwo.WrapMode = ScintillaNET.WrapMode.None;
this.scintillaTwo.TextChanged += new System.EventHandler(this.Scintilla_TextChanged);
this.scMain.Panel1.Controls.Add(scintillaOne);
this.scMain.Panel1.Controls.SetChildIndex(scintillaOne, 0);
this.scMain.Panel2.Controls.Add(scintillaTwo);
this.scMain.Panel2.Controls.SetChildIndex(scintillaTwo, 0);
scintillaOne.Tag = -1;
scintillaTwo.Tag = -1;
ReInit();
}
// this tag values are for line number length counting..
}
public void ReInit()
{
SetSymbolMasks();
InitScintillaMargins();
SetSymbols();
SetLineBackgroundColors();
}
#region PrivateEvents
// if the control size has changed, set the splitter to the middle..
private void ScintillaDiffer_SizeChanged(object sender, EventArgs e)
{
RecalculateSize();
}
// ReSharper disable once CommentTypo
#region https://github.com/jacobslusser/ScintillaNET/wiki/Displaying-Line-Numbers
private void Scintilla_TextChanged(object sender, EventArgs e)
{
Scintilla scintilla = (Scintilla) sender;
int maxLineNumberCharLengthFromTag = (int) scintilla.Tag;
// ReSharper disable once CommentTypo
// Did the number of characters in the line number display change?
// i.e. nnn VS nn, or nnnn VS nn, etc...
var maxLineNumberCharLength = scintilla.Lines.Count.ToString().Length;
if (maxLineNumberCharLength == maxLineNumberCharLengthFromTag)
return;
// Calculate the width required to display the last line number
// and include some padding for good measure.
const int padding = 2;
scintilla.Margins[0].Width =
scintilla.TextWidth(Style.LineNumber, new string('9', maxLineNumberCharLength + 1)) + padding;
scintilla.Tag = maxLineNumberCharLength;
}
#endregion
#endregion
#region PrivateFields
private ScrollSyncScintilla scintillaOne;
private ScrollSyncScintilla scintillaTwo;
private string textLeft = string.Empty;
private string textRight = string.Empty;
private Bitmap imageRowAdded = RySmartEditor.Properties.Resources.plus;
private Bitmap imageRowDeleted = RySmartEditor.Properties.Resources.minus;
private Bitmap imageRowOk = RySmartEditor.Properties.Resources.ok;
private Bitmap imageRowDiff = RySmartEditor.Properties.Resources.diff;
private int imageRowAddedScintillaIndex = 28;
private int imageRowDeletedScintillaIndex = 29;
private int imageRowOkScintillaIndex = 30;
private int imageRowDiffScintillaIndex = 31;
private int markColorCharacterChanged = 27;
private int markColorCharacterRemoved = 28;
private int markColorCharacterAdded = 29;
private int markColorIndexRemovedOrAdded = 30;
private int markColorIndexModifiedBackground = 31;
private bool useRowOkSign;
private DiffStyle diffStyle = DiffStyle.DiffList;
private Color diffColorDeleted = Color.FromArgb(0xFF, 0XFF, 0XB2, 0XB2);
private Color diffColorAdded = Color.FromArgb(0xFF, 0XD4, 0XF2, 0XC4);
private Color diffColorCharDeleted = Color.FromArgb(0xFF, 0XE1, 0X7D, 0X7D);
private Color diffColorCharAdded = Color.FromArgb(0xFF, 0X9A, 0XEA, 0X6F);
private Color diffColorChangeBackground = Color.FromArgb(0xFF, 0XFC, 0XFF, 0X8C);
private int diffIndex;
private readonly StringBuilder builderLeft = new StringBuilder();
private readonly StringBuilder builderRight = new StringBuilder();
private bool characterComparison;
private bool characterComparisonMarkAddRemove;
#endregion
#region PublicProperties
/// <summary>
/// Gets the left <see cref="Scintilla"/> control.
/// </summary>
[Browsable(false)]
// ReSharper disable once ConvertToAutoPropertyWhenPossible
// ReSharper disable once UnusedMember.Global
public Scintilla LeftScintilla => scintillaOne;
/// <summary>
/// Gets the value indicating whether a navigation to the previous difference is possible. (<seealso cref="Previous"/>).
/// </summary>
[Browsable(false)]
public bool CanGoPrevious => diffIndex > 0 && DiffLocations.Count > 0;
/// <summary>
/// Gets the value indicating whether a navigation to the next difference is possible. (<seealso cref="Next"/>).
/// </summary>
[Browsable(false)]
public bool CanGoNext => diffIndex + 1 < DiffLocations.Count;
/// <summary>
/// Gets the right <see cref="Scintilla"/> control.
/// </summary>
[Browsable(false)]
// ReSharper disable once ConvertToAutoPropertyWhenPossible
// ReSharper disable once UnusedMember.Global
public Scintilla RightScintilla => scintillaTwo;
/// <summary>
/// Gets the difference locations found by the <see cref="Differ"/> class.
/// </summary>
[Browsable(false)]
public List<int> DiffLocations { get; internal set; } = new List<int>();
/// <summary>
/// Gets a value indicating whether the two compared texts differs from each-other.
/// </summary>
// ReSharper disable once UnusedMember.Global
[Browsable(false)]
public bool IsMatch => textLeft.Equals(textRight);
/// <summary>
/// Gets or sets the value indicating whether the entire line of a change should be highlighted, or just the text within that line.
/// </summary>
[Browsable(false)]
public bool IsEntireLineHighlighted { get; set; } = false;
/// <summary>
/// Gets or sets the value indicating whether the entire line of a change should be highlighted, or just the text within that line.
/// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
// ReSharper disable once IdentifierTypo :: this is left behind to maintain backwards compatibility..
// ReSharper disable once UnusedMember.Global :: this is left behind to maintain backwards compatibility..
public bool IsEntireLineHighligted => IsEntireLineHighlighted; // don't
#endregion
#region PublicEvents
/// <summary>
/// A delegate for the <see cref="ExternalStyleNeeded"/> event.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="StyleRefreshEventArgs"/> instance containing the event data.</param>
public delegate void OnExternalStyleNeeded(object sender, StyleRefreshEventArgs e);
/// <summary>
/// Occurs when external styling is needed to keep the document style up to date
/// (i.e. a class property change has caused the diff to update thus clearing the document's style).
/// </summary>
public event OnExternalStyleNeeded ExternalStyleNeeded;
#endregion
#region PublicVisualProperties
/// <summary>
/// Gets or sets a value indicating whether to use character comparison on lines.
/// </summary>
/// <value><c>true</c> if to use character comparison on lines; otherwise, <c>false</c>.</value>
[Browsable(true)]
[Category("Behaviour")]
[Description("Gets or sets a value indicating whether to use character comparison on lines.")]
public bool CharacterComparison
{
get => characterComparison;
set
{
if (value != characterComparison)
{
characterComparison = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets a value indicating whether the character comparison should mark added and removed characters.
/// </summary>
/// <value><c>true</c> if the character comparison should mark added and removed characters; otherwise, <c>false</c>.</value>
[Browsable(true)]
[Category("Behaviour")]
[Description("Gets or sets a value indicating whether the character comparison should mark added and removed characters.")]
public bool CharacterComparisonMarkAddRemove
{
get => characterComparisonMarkAddRemove;
set
{
if (value != characterComparisonMarkAddRemove)
{
characterComparisonMarkAddRemove = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets the symbol for a removed character.
/// </summary>
/// <value>The removed character symbol.</value>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the symbol for a removed character.")]
public char RemovedCharacterSymbol { get; set; } = '-';
/// <summary>
/// Gets or sets the symbol for an added character.
/// </summary>
/// <value>The added character symbol.</value>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the symbol for an added character.")]
public char AddedCharacterSymbol { get; set; } = '+';
/// <summary>
/// Gets or sets the index for the style for a mark color used by the <see cref="Scintilla"/> control to indicate a addition or a deletion difference.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value must be between 0 and 31.</exception>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the index for the style index for a mark color used by the Scintilla control to indicate a addition or a deletion difference.")]
public int MarkColorIndexModifiedBackground
{
get => markColorIndexModifiedBackground;
set
{
if (value != markColorIndexModifiedBackground)
{
if (value < 0 || value > 31)
{
// ReSharper disable once LocalizableElement
throw new ArgumentOutOfRangeException(nameof(value), "The value must be between 0 and 31.");
}
markColorIndexModifiedBackground = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets the index for the style for a background color color used by the <see cref="Scintilla"/> control to indicate a change in file line.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value must be between 0 and 31.</exception>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the index for the style for a background color color used by the Scintilla control to indicate a change in file line.")]
public int MarkColorIndexRemovedOrAdded
{
get => markColorIndexRemovedOrAdded;
set
{
if (value != markColorIndexRemovedOrAdded)
{
if (value < 0 || value > 31)
{
// ReSharper disable once LocalizableElement
throw new ArgumentOutOfRangeException(nameof(value), "The value must be between 0 and 31.");
}
markColorIndexRemovedOrAdded = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets a value indicating whether to mark unchanged lines with an ok sign.
/// </summary>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets a value indicating whether to mark unchanged lines with an ok sign.")]
public bool UseRowOkSign
{
get => useRowOkSign;
set
{
if (useRowOkSign != value)
{
useRowOkSign = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets a diff style of the control.
/// </summary>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets a diff style of the control.")]
public DiffStyle DiffStyle
{
get => diffStyle;
set
{
if (diffStyle != value)
{
diffStyle = value;
// don't synchronize the scroll bars with list view..
if (diffStyle == DiffStyle.DiffList)
{
scintillaOne.ScrollSync = null;
scintillaTwo.ScrollSync = null;
}
else
{
// synchronize the scroll bars with side-by-side view..
scintillaOne.ScrollSync = scintillaTwo;
scintillaTwo.ScrollSync = scintillaOne;
}
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets the indicator for the diff that a row was added.
/// </summary>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the indicator for the diff that a row was added.")]
public Bitmap ImageRowAdded
{
get => imageRowAdded;
set
{
if (value != imageRowAdded && value != null)
{
imageRowAdded = value;
SetSymbols();
}
}
}
/// <summary>
/// Gets or sets the index for the <see cref="ImageRowAdded"/> used by the <see cref="Scintilla"/> control.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value must be between 0 and 31.</exception>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the index for the ImageRowAdded used by the Scintilla control.")]
public int ImageRowAddedScintillaIndex
{
get => imageRowAddedScintillaIndex;
set
{
if (value != imageRowAddedScintillaIndex)
{
if (value < 0 || value > 31)
{
// ReSharper disable once LocalizableElement
throw new ArgumentOutOfRangeException(nameof(value), "The value must be between 0 and 31.");
}
imageRowAddedScintillaIndex = value;
SetSymbolMasks();
}
}
}
/// <summary>
/// Gets or sets the indicator for the diff that a row was deleted.
/// </summary>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the indicator for the diff that a row was deleted.")]
public Bitmap ImageRowDeleted
{
get => imageRowDeleted;
set
{
if (value != imageRowDeleted && value != null)
{
imageRowDeleted = value;
SetSymbols();
}
}
}
/// <summary>
/// Gets or sets the index for the <see cref="ImageRowDeleted"/> used by the <see cref="Scintilla"/> control.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value must be between 0 and 31.</exception>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the index for the ImageRowDeleted used by the Scintilla control.")]
public int ImageRowDeletedScintillaIndex
{
get => imageRowDeletedScintillaIndex;
set
{
if (value != imageRowDeletedScintillaIndex)
{
if (value < 0 || value > 31)
{
// ReSharper disable once LocalizableElement
throw new ArgumentOutOfRangeException(nameof(value), "The value must be between 0 and 31.");
}
imageRowDeletedScintillaIndex = value;
SetSymbolMasks();
}
}
}
/// <summary>
/// Gets or sets the indicator for the diff that a row hasn't changed.
/// </summary>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the indicator for the diff that a row hasn't changed.")]
public Bitmap ImageRowOk
{
get => imageRowOk;
set
{
if (value != imageRowOk && value != null)
{
imageRowOk = value;
SetSymbols();
}
}
}
/// <summary>
/// Gets or sets the index for the <see cref="ImageRowOk"/> used by the <see cref="Scintilla"/> control.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value must be between 0 and 31.</exception>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the index for the ImageRowOk used by the Scintilla control.")]
public int ImageRowOkScintillaIndex
{
get => imageRowOkScintillaIndex;
set
{
if (value != imageRowOkScintillaIndex)
{
if (value < 0 || value > 31)
{
// ReSharper disable once LocalizableElement
throw new ArgumentOutOfRangeException(nameof(value), "The value must be between 0 and 31.");
}
imageRowOkScintillaIndex = value;
SetSymbolMasks();
}
}
}
/// <summary>
/// Gets or sets the indicator for the diff that two rows have some differences.
/// </summary>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the indicator for the diff that two rows have some differences.")]
public Bitmap ImageRowDiff
{
get => imageRowDiff;
set
{
if (value != imageRowDiff && value != null)
{
imageRowDiff = value;
SetSymbols();
}
}
}
/// <summary>
/// Gets or sets the index for the <see cref="ImageRowDiff"/> used by the <see cref="Scintilla"/> control.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value must be between 0 and 31.</exception>
[Browsable(true)]
[Category("Appearance")]
[Description("Gets or sets the index for the ImageRowDiff used by the Scintilla control.")]
public int ImageRowDiffScintillaIndex
{
get => imageRowDiffScintillaIndex;
set
{
if (value != imageRowDiffScintillaIndex)
{
if (value < 0 || value > 31)
{
// ReSharper disable once LocalizableElement
throw new ArgumentOutOfRangeException(nameof(value), "The value must be between 0 and 31.");
}
imageRowDiffScintillaIndex = value;
SetSymbolMasks();
}
}
}
/// <summary>
/// Gets or sets the text on the left <see cref="Scintilla"/> control.
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("Gets or sets the text on the left Scintilla control.")]
public string TextLeft
{
get => textLeft;
set
{
textLeft = value;
DiffTexts();
}
}
/// <summary>
/// 获取或修改左边区域的标题
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("获取或修改左边区域的标题")]
public string TitleLeft
{
get => label1.Text;
set
{
label1.Text = value;
}
}
/// <summary>
/// 获取或修改右边区域的标题
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("获取或修改右边区域的标题")]
public string TitleRight
{
get => label2.Text;
set
{
label2.Text = value;
}
}
/// <summary>
/// 获取或修改标题是否可见
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("获取或修改标题是否可见")]
public bool TitleVisible
{
get => panel1.Visible;
set
{
panel1.Visible = panel2.Visible= value;
}
}
/// <summary>
/// Gets or sets the text on the right <see cref="Scintilla"/> control.
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("Gets or sets the text on the right Scintilla control.")]
public string TextRight
{
get => textRight;
set
{
textRight = value;
DiffTexts();
}
}
/// <summary>
/// Gets or sets the text deleted color for the <see cref="Scintilla"/> control.
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("Gets or sets the text deleted color for the Scintilla control.")]
public Color DiffColorDeleted
{
get => diffColorDeleted;
set
{
if (value != diffColorDeleted)
{
diffColorDeleted = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets the text inserted color for the <see cref="Scintilla"/> control.
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("Gets or sets the text inserted color for the Scintilla control.")]
public Color DiffColorAdded
{
get => diffColorAdded;
set
{
if (value != diffColorAdded)
{
diffColorAdded = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets the text deleted color for the <see cref="Scintilla"/> control.
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("Gets or sets the character deleted color for the Scintilla control.")]
public Color DiffColorCharDeleted
{
get => diffColorCharDeleted;
set
{
if (value != diffColorCharDeleted)
{
diffColorCharDeleted = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets the text inserted color for the <see cref="Scintilla"/> control.
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("Gets or sets the character inserted color for the Scintilla control.")]
public Color DiffColorCharAdded
{
get => diffColorCharAdded;
set
{
if (value != diffColorCharAdded)
{
diffColorCharAdded = value;
DiffTexts();
}
}
}
/// <summary>
/// Gets or sets the background color for a changed text row for the <see cref="Scintilla"/> control.
/// </summary>
[Browsable(true)]
[Category("Diff")]
[Description("Gets or sets the background color for a changed text row for the Scintilla control.")]
public Color DiffColorChangeBackground
{
get => diffColorChangeBackground;
set
{
if (value != diffColorChangeBackground)
{
diffColorChangeBackground = value;
DiffTexts();
}
}
}
#endregion
#region PrivateProperties
#endregion
#region PrivateMethods
/// <summary>
/// Re-calculates the split container's (<see cref="SplitContainer"/>) splitter position.
/// </summary>
private void RecalculateSize()
{
int size = scMain.ClientSize.Width - scMain.SplitterWidth;
if (size >= 0)
scMain.SplitterDistance = size / 2;
}
/// <summary>
/// Sets the margin styles of both the <see cref="Scintilla"/> controls.
/// </summary>
private void InitScintillaMargins()
{
scintillaOne.Margins[0].Type = MarginType.Number;
scintillaTwo.Margins[0].Type = MarginType.Number;
scintillaOne.Margins[1].Width = 25;
scintillaOne.Margins[1].Type = MarginType.Symbol;
scintillaTwo.Margins[1].Width = 25;
scintillaTwo.Margins[1].Type = MarginType.Symbol;
}
/// <summary>
/// Sets the bit masks to the second margin symbols.
/// </summary>
public void SetSymbolMasks()
{
// the Scintilla does like this bit masks or "bitmaps"..
scintillaOne.Margins[1].Mask =
GetScintillaSymbolIndex(imageRowAddedScintillaIndex) |
GetScintillaSymbolIndex(imageRowDeletedScintillaIndex) |
GetScintillaSymbolIndex(imageRowDiffScintillaIndex) |
GetScintillaSymbolIndex(imageRowOkScintillaIndex);
scintillaTwo.Margins[1].Mask = scintillaOne.Margins[1].Mask;
}
/// <summary>
/// Shifts value of one with the given amount to the left.
/// </summary>
/// <param name="amount">The amount of how much to shift number one to the left.</param>
/// <returns>An unsigned integer containing the value shifted to the left.</returns>
uint GetScintillaSymbolIndex(int amount)
{
return (uint) 1 << amount;
}
/// <summary>
/// Sets the symbol images for both the left and right <see cref="Scintilla"/> controls.
/// </summary>
public void SetSymbols()
{
// the plus-symbol..
scintillaOne.Markers[imageRowAddedScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaOne.Markers[imageRowAddedScintillaIndex].DefineRgbaImage(imageRowAdded);
// the minus-symbol..
scintillaOne.Markers[imageRowDeletedScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaOne.Markers[imageRowDeletedScintillaIndex].DefineRgbaImage(imageRowDeleted);
// the plus-symbol..
scintillaTwo.Markers[imageRowAddedScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaTwo.Markers[imageRowAddedScintillaIndex].DefineRgbaImage(imageRowAdded);
// the minus-symbol..
scintillaTwo.Markers[imageRowDeletedScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaTwo.Markers[imageRowDeletedScintillaIndex].DefineRgbaImage(imageRowDeleted);
// the row ok symbol..
scintillaOne.Markers[imageRowOkScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaOne.Markers[imageRowOkScintillaIndex].DefineRgbaImage(imageRowOk);
// the row ok symbol..
scintillaTwo.Markers[imageRowOkScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaTwo.Markers[imageRowOkScintillaIndex].DefineRgbaImage(imageRowOk);
// the row diff symbol..
scintillaOne.Markers[imageRowDiffScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaOne.Markers[imageRowDiffScintillaIndex].DefineRgbaImage(imageRowDiff);
// the row diff symbol..
scintillaTwo.Markers[imageRowDiffScintillaIndex].Symbol = MarkerSymbol.RgbaImage;
scintillaTwo.Markers[imageRowDiffScintillaIndex].DefineRgbaImage(imageRowDiff);
}
/// <summary>
/// Sets the colors for the background of lines, depending on change type.
/// </summary>
public void SetLineBackgroundColors()
{
int deleted = (int)ChangeType.Deleted;
int inserted = (int)ChangeType.Inserted;
int modified = (int)ChangeType.Modified;
scintillaOne.Styles[deleted].FillLine = true;
scintillaOne.Styles[deleted].BackColor = DiffColorDeleted;
scintillaOne.Styles[inserted].FillLine = true;
scintillaOne.Styles[inserted].BackColor = DiffColorAdded;
scintillaOne.Styles[modified].FillLine = true;
scintillaOne.Styles[modified].BackColor = DiffColorChangeBackground;
scintillaTwo.Styles[deleted].FillLine = true;
scintillaTwo.Styles[deleted].BackColor = DiffColorDeleted;
scintillaTwo.Styles[inserted].FillLine = true;
scintillaTwo.Styles[inserted].BackColor = DiffColorAdded;
scintillaTwo.Styles[modified].FillLine = true;
scintillaTwo.Styles[modified].BackColor = DiffColorChangeBackground;
}
/// <summary>
/// Appends a row to the left <see cref="Scintilla"/> control.
/// </summary>
/// <param name="rowText">The text to append to the left <see cref="Scintilla"/> document row.</param>
private void AppendRowAdded(string rowText)
{
builderLeft.AppendLine(rowText);
// scintillaOne.Text += rowText + Environment.NewLine;
}
/// <summary>
/// Sets a row added marker based on the given <paramref name="index"/> row amount.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
private void AppendRowAddedMarker(int index)
{
scintillaOne.Lines[index].MarkerAdd(imageRowAddedScintillaIndex);
}
/// <summary>
/// Sets a row added marker based on the given <paramref name="index"/> row amount to either the left side or the right side <see cref="Scintilla"/> document.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
/// <param name="left">A value indicating whether to append the marker to the left or to the right side <see cref="Scintilla"/> document.</param>
private void AppendRowAddedMarker(int index, bool left)
{
if (left)
{
scintillaOne.Lines[index].MarkerAdd(imageRowAddedScintillaIndex);
}
else
{
scintillaTwo.Lines[index].MarkerAdd(imageRowAddedScintillaIndex);
}
}
/// <summary>
/// Appends a row to the left <see cref="Scintilla"/> control.
/// </summary>
/// <param name="rowText">The text to append to the right <see cref="Scintilla"/> document row.</param>
private void AppendRowDeleted(string rowText)
{
builderLeft.AppendLine(rowText);
//scintillaOne.Text += rowText + Environment.NewLine;
}
/// <summary>
/// Sets a row deleted marker based on the given <paramref name="index"/> row amount.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
private void AppendRowDeletedMarker(int index)
{
scintillaOne.Lines[index].MarkerAdd(imageRowDeletedScintillaIndex);
}
/// <summary>
/// Sets a row deleted marker based on the given <paramref name="index"/> row amount to either the left side or the right side <see cref="Scintilla"/> document.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
/// <param name="left">A value indicating whether to append the marker to the left or to the right side <see cref="Scintilla"/> document.</param>
private void AppendRowDeletedMarker(int index, bool left)
{
if (left)
{
scintillaOne.Lines[index].MarkerAdd(imageRowDeletedScintillaIndex);
}
else
{
scintillaTwo.Lines[index].MarkerAdd(imageRowDeletedScintillaIndex);
}
}
/// <summary>
/// Sets a row ok marker based on the given <paramref name="index"/> row amount.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
private void AppendRowOkMarker(int index)
{
if (!UseRowOkSign)
{
return;
}
scintillaOne.Lines[index].MarkerAdd(imageRowOkScintillaIndex);
}
/// <summary>
/// Sets a row ok marker based on the given <paramref name="index"/> row amount to either the left side or the right side <see cref="Scintilla"/> document.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
/// <param name="left">A value indicating whether to append the marker to the left or to the right side <see cref="Scintilla"/> document.</param>
private void AppendRowOkMarker(int index, bool left)
{
if (!UseRowOkSign)
{
return;
}
if (left)
{
scintillaOne.Lines[index].MarkerAdd(imageRowOkScintillaIndex);
}
else
{
scintillaTwo.Lines[index].MarkerAdd(imageRowOkScintillaIndex);
}
}
/// <summary>
/// Sets a row differ marker based on the given <paramref name="index"/> row amount.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
private void AppendRowDiffMarker(int index)
{
scintillaOne.Lines[index].MarkerAdd(imageRowDiffScintillaIndex);
}
/// <summary>
/// Sets a row differ marker based on the given <paramref name="index"/> row amount to either the left side or the right side <see cref="Scintilla"/> document.
/// </summary>
/// <param name="index">The index of the row to set the marker to.</param>
/// <param name="left">A value indicating whether to append the marker to the left or to the right side <see cref="Scintilla"/> document.</param>
private void AppendRowDiffMarker(int index, bool left)
{
if (left)
{
scintillaOne.Lines[index].MarkerAdd(imageRowDiffScintillaIndex);
}
else
{
scintillaTwo.Lines[index].MarkerAdd(imageRowDiffScintillaIndex);
}
}
/// <summary>
/// Appends the same row to the left and right <see cref="Scintilla"/> controls.
/// </summary>
/// <param name="rowText">The text to append to the right and to the left <see cref="Scintilla"/> document rows.</param>
private void AppendRow(string rowText)
{
builderLeft.AppendLine(rowText);
builderRight.AppendLine(rowText);
//scintillaOne.Text += rowText + Environment.NewLine;
//scintillaTwo.Text += rowText + Environment.NewLine;
}
/// <summary>
/// Appends different rows to the left and right side <see cref="Scintilla"/> controls.
/// </summary>
/// <param name="rowTextLeft">The text to append to the the left <see cref="Scintilla"/> document rows.</param>
/// <param name="rowTextRight">The text to append to the right <see cref="Scintilla"/> document rows.</param>
private void AppendRow(string rowTextLeft, string rowTextRight)
{
builderLeft.AppendLine(rowTextLeft);
builderRight.AppendLine(rowTextRight);
// scintillaOne.Text += rowTextLeft + Environment.NewLine;
// scintillaTwo.Text += rowTextRight + Environment.NewLine;
}
/// <summary>
/// Compares to contents of the two texts if both are assigned in a list style view.
/// </summary>
private void DiffTextsList()
{
// collapse the right panel of the split control..
scMain.Panel2Collapsed = true;
// validate that there is text to compare..
if (!string.IsNullOrEmpty(TextLeft) || !string.IsNullOrEmpty(TextRight))
{
// clear the two Scintilla control contents..
scintillaOne.Text = string.Empty;
scintillaTwo.Text = string.Empty;
// clear the two StringBuilder instance contents..
builderLeft.Clear();
builderRight.Clear();
// create a diff for a list style text comparison..
var diffBuilder = new InlineDiffBuilder(new Differ());
// compare the two texts..
var diff = diffBuilder.BuildDiffModel(TextLeft, TextRight);
// output the diff data to the left side Scintilla control;
// first the rows so the style can be appended afterwards..
foreach (var line in diff.Lines)
{
switch (line.Type)
{
case ChangeType.Inserted:
AppendRowAdded(line.Text);
break;
case ChangeType.Deleted:
AppendRowDeleted(line.Text);
break;
case ChangeType.Unchanged:
AppendRow(line.Text);
break;
}
}
scintillaOne.Text = builderLeft.ToString();
// set a variable for the line index..
int lineIndex = 0;
// set the style for the lines now that the Scintilla document's
// contents have been set..
foreach (var line in diff.Lines)
{
if (IsEntireLineHighlighted)
SetLineBackgroundColor(lineIndex, line.Type);
switch (line.Type)
{
case ChangeType.Inserted:
// save the line location..
SaveLineLocation(lineIndex);
AppendRowAddedMarker(lineIndex);
break;
case ChangeType.Deleted:
// save the line location..
SaveLineLocation(lineIndex);
AppendRowDeletedMarker(lineIndex);
break;
case ChangeType.Unchanged:
AppendRowOkMarker(lineIndex);
break;
case ChangeType.Modified:
// save the line location..
SaveLineLocation(lineIndex);
AppendRowDiffMarker(lineIndex);
break;
}
lineIndex++;
}
// reset the index of the next difference..
diffIndex = -1;
// raise the ExternalStyleNeeded event if it's subscribed..
ExternalStyleNeeded?.Invoke(this, new StyleRefreshEventArgs {Scintilla = LeftScintilla});
// sort the jump locations..
DiffLocations.Sort();
}
}
/// <summary>
/// Saves the line location to the <see cref="DiffLocations"/> property.
/// </summary>
/// <param name="lineIndex">The index of the row which location to save.</param>
private void SaveLineLocation(int lineIndex)
{
if (DiffLocations.Contains(lineIndex))
{
return;
}
DiffLocations.Add(lineIndex);
}
private KeyValuePair<string, string> SpanLeftRightChars(DiffResult diffResult, int line, string oldLine,
string newLine, ref List<CharacterChangeType> charChangedList)
{
if (diffResult == null || diffResult.DiffBlocks.Count == 0)
{
return new KeyValuePair<string, string>(oldLine, newLine);
}
oldLine = oldLine ?? string.Empty;
newLine = newLine ?? string.Empty;
if (oldLine.Length == newLine.Length)
{
for (int i = 0; i < oldLine.Length; i++)
{
if (oldLine[i] != newLine[i])
{
charChangedList.Add(new CharacterChangeType
{ChangeType = CharChangedType.Modified, Length = 1, LineIndex = line, Position = i});
}
}
return new KeyValuePair<string, string>(oldLine, newLine);
}
foreach (var diffBlock in diffResult.DiffBlocks)
{
if (diffBlock.DeleteCountA == diffBlock.InsertCountB &&
diffBlock.DeleteStartA == diffBlock.InsertStartB)
{
charChangedList.Add(new CharacterChangeType
{
ChangeType = CharChangedType.Modified, Length = diffBlock.DeleteCountA, LineIndex = line,
Position = diffBlock.DeleteStartA
});
continue;
}
if (diffBlock.DeleteCountA > 0)
{
if (CharacterComparisonMarkAddRemove)
{
oldLine = oldLine.Insert(diffBlock.DeleteStartA,
new string(AddedCharacterSymbol, diffBlock.DeleteCountA));
charChangedList.Add(new CharacterChangeType
{
ChangeType = CharChangedType.Added, Length = diffBlock.DeleteCountA, LineIndex = line,
Position = diffBlock.DeleteStartA
});
}
}
if (diffBlock.InsertCountB > 0)
{
if (CharacterComparisonMarkAddRemove)
{
newLine = newLine.Insert(diffBlock.InsertStartB,
new string(RemovedCharacterSymbol, diffBlock.InsertCountB));
charChangedList.Add(new CharacterChangeType
{
ChangeType = CharChangedType.Removed, Length = diffBlock.InsertCountB, LineIndex = line,
Position = diffBlock.InsertStartB
});
}
}
}
return new KeyValuePair<string, string>(oldLine, newLine);
}
/// <summary>
/// Compares to contents of the two texts if both are assigned in a side by side style view.
/// </summary>
private void DiffTextsSideBySide()
{
// un-collapse the right panel of the split control..
scMain.Panel2Collapsed = false;
// recalculate the position of the split control's
// splitter..
RecalculateSize();
// validate that there is text to compare..
if (!string.IsNullOrEmpty(TextLeft) || !string.IsNullOrEmpty(TextRight))
{
scintillaOne.ReadOnly = false;
scintillaTwo.ReadOnly = false;
// clear the two Scintilla control contents..
scintillaOne.Text = string.Empty;
scintillaTwo.Text = string.Empty;
scintillaOne.ClearAll();
scintillaTwo.ClearAll();
// clear the two StringBuilder instance contents..
builderLeft.Clear();
builderRight.Clear();
// initialize a new instance of the Differ class..
var differ = new Differ();
// create a diff for a side by side text comparison..
var diffBuilder = new SideBySideDiffBuilder(differ);
// compare the two texts..
var diff = diffBuilder.BuildDiffModel(TextLeft, TextRight);
List<CharacterChangeType> changedCharacters =
new List<CharacterChangeType>();
// output the diff data to the left and to the right side Scintilla controls;
// first the rows so the style can be appended afterwards..
for (int i = 0; i < diff.OldText.Lines.Count; i++)
{
if (CharacterComparison)
{
var diffResult = Differ.Instance.CreateCharacterDiffs(diff.NewText.Lines[i].Text ?? string.Empty,
diff.OldText.Lines[i].Text ?? string.Empty, false, false);
var span = SpanLeftRightChars(diffResult, i,
diff.OldText.Lines[i].Text, diff.NewText.Lines[i].Text, ref changedCharacters);
AppendRow(span.Key, span.Value);
}
else // no character comparison..
{
AppendRow(diff.OldText.Lines[i].Text, diff.NewText.Lines[i].Text);
}
}
if (CharacterComparison)
{
diff = diffBuilder.BuildDiffModel(builderLeft.ToString(), builderRight.ToString());
}
scintillaOne.Text = builderLeft.ToString();
scintillaTwo.Text = builderRight.ToString();
scintillaOne.ReadOnly = scintillaTwo.ReadOnly= true;
// clear the list of difference locations..
DiffLocations.Clear();
if (IsEntireLineHighlighted)
{
for (int i = 0; i < diff.OldText.Lines.Count; i++)
{
if (diff.OldText.Lines[i].Type == ChangeType.Modified || diff.NewText.Lines[i].Type == ChangeType.Modified)
{
SetLineBackgroundColor(i, ChangeType.Modified);
HandleDiffSubPieces(diff.NewText.Lines[i].SubPieces, i, false);
HandleDiffSubPieces(diff.OldText.Lines[i].SubPieces, i, true);
}
else if (diff.OldText.Lines[i].Type == ChangeType.Deleted)
{
SetLineBackgroundColor(i, ChangeType.Deleted);
AppendRowDeletedMarker(i, left: true);
}
else if (diff.OldText.Lines[i].Type == ChangeType.Imaginary && diff.NewText.Lines[i].Type == ChangeType.Inserted)
{
SetLineBackgroundColor(i, ChangeType.Inserted);
}
}
}
else
{
// loop through the meta-data of the diff result and set the styling
// for the Scintilla controls accordingly..
for (int i = 0; i < diff.OldText.Lines.Count; i++)
{
switch (diff.OldText.Lines[i].Type)
{
case ChangeType.Inserted:
AppendRowAddedMarker(i, true);
// save the line location..
SaveLineLocation(i);
break;
case ChangeType.Deleted:
AppendRowDeletedMarker(i, true);
// save the line location..
SaveLineLocation(i);
break;
case ChangeType.Unchanged:
AppendRowOkMarker(i, true);
break;
case ChangeType.Modified:
// save the line location..
SaveLineLocation(i);
AppendRowDiffMarker(i, false);
MarkLineWithColor(i, DiffColorChangeBackground, true);
HandleDiffSubPieces(diff.OldText.Lines[i].SubPieces, i, true);
break;
}
switch (diff.NewText.Lines[i].Type)
{
case ChangeType.Inserted:
AppendRowAddedMarker(i, false);
// save the line location..
SaveLineLocation(i);
break;
case ChangeType.Deleted:
AppendRowDeletedMarker(i, false);
// save the line location..
SaveLineLocation(i);
break;
case ChangeType.Unchanged:
AppendRowOkMarker(i, false);
break;
case ChangeType.Modified:
// save the line location..
SaveLineLocation(i);
AppendRowDiffMarker(i, true);
MarkLineWithColor(i, DiffColorChangeBackground, false);
HandleDiffSubPieces(diff.NewText.Lines[i].SubPieces, i, false);
break;
}
}
}
MarkWithBackgroundColor(changedCharacters, diffColorCharAdded,
diffColorCharDeleted);
// reset the index of the next difference..
diffIndex = -1;
// raise the ExternalStyleNeeded event if it's subscribed for both of the Scintilla controls..
ExternalStyleNeeded?.Invoke(this, new StyleRefreshEventArgs {Scintilla = LeftScintilla});
ExternalStyleNeeded?.Invoke(this, new StyleRefreshEventArgs {Scintilla = RightScintilla});
// sort the jump locations..
DiffLocations.Sort();
}
else
{
scintillaOne.ReadOnly = false;
scintillaTwo.ReadOnly = false;
// clear the two Scintilla control contents..
scintillaOne.Text = string.Empty;
scintillaTwo.Text = string.Empty;
scintillaOne.ClearAll();
scintillaTwo.ClearAll();
scintillaOne.ReadOnly = true;
scintillaTwo.ReadOnly = true;
}
}
/// <summary>
/// Marks a given position of a row with a given background color.
/// </summary>
/// <param name="lineIndex">The index of the line to mark with the <see cref="Scintilla"/> control.</param>
/// <param name="subPosition">The position in the line to mark with the given color.</param>
/// <param name="left">A value indicating whether to use the left or the right side <see cref="Scintilla"/> control.</param>
/// <param name="diffPiece">A <see cref="DiffPiece"/> class instance to get the length of the text.</param>
/// <param name="color">A <see cref="Color"/> to use with the marking.</param>
private void MarkWithBackgroundColor(int lineIndex, int subPosition, bool left, DiffPiece diffPiece, Color color)
{
if (diffPiece.Position == null)
{
return;
}
int start = left
? scintillaOne.Lines[lineIndex].Position + subPosition
: scintillaTwo.Lines[lineIndex].Position + subPosition;
Highlight.HighlightRange(left ? scintillaOne : scintillaTwo, MarkColorIndexModifiedBackground, start,
diffPiece.Text.Length, color);
}
private void ClearStylesArea(Scintilla scintilla, int line, int position, int length)
{
for (int i = markColorCharacterChanged; i <= markColorIndexModifiedBackground; i++)
{
Highlight.ClearStyleArea(scintilla, line, position, length,
i);
}
}
private void MarkWithBackgroundColor(List<CharacterChangeType> changedCharacters,
Color colorAdd, Color colorDeleted)
{
foreach (var changedCharacter in changedCharacters)
{
int startOne = scintillaOne.Lines[changedCharacter.LineIndex].Position + changedCharacter.Position;
int startTwo = scintillaTwo.Lines[changedCharacter.LineIndex].Position + changedCharacter.Position;
ClearStylesArea(scintillaOne, changedCharacter.LineIndex, changedCharacter.Position, changedCharacter.Length);
ClearStylesArea(scintillaTwo, changedCharacter.LineIndex, changedCharacter.Position, changedCharacter.Length);
switch (changedCharacter.ChangeType)
{
case CharChangedType.Modified:
Highlight.HighlightRange(scintillaOne, markColorCharacterChanged, startOne, changedCharacter.Length,
colorDeleted);
Highlight.HighlightRange(scintillaTwo, markColorCharacterChanged, startTwo, changedCharacter.Length,
colorAdd);
break;
case CharChangedType.Added:
Highlight.HighlightRange(scintillaOne, markColorCharacterAdded, startOne, changedCharacter.Length,
colorDeleted);
Highlight.HighlightRange(scintillaTwo, markColorCharacterRemoved, startTwo, changedCharacter.Length,
colorAdd);
break;
case CharChangedType.Removed:
Highlight.HighlightRange(scintillaOne, markColorCharacterRemoved, startOne, changedCharacter.Length,
colorDeleted);
Highlight.HighlightRange(scintillaTwo, markColorCharacterAdded, startTwo, changedCharacter.Length,
colorAdd);
break;
}
}
}
/// <summary>
/// Marks a line of a <see cref="Scintilla"/> control with a given <paramref name="color"/>.
/// </summary>
/// <param name="lineIndex">The index of the line to mark with the <see cref="Scintilla"/> control.</param>
/// <param name="color">A <see cref="Color"/> to use with the marking.</param>
/// <param name="left">A value indicating whether to use the left or the right side <see cref="Scintilla"/> control.</param>
private void MarkLineWithColor(int lineIndex, Color color, bool left)
{
int start = left
? scintillaOne.Lines[lineIndex].Position
: scintillaTwo.Lines[lineIndex].Position;
int length = left
? scintillaOne.Lines[lineIndex].Length
: scintillaTwo.Lines[lineIndex].Length;
Highlight.HighlightRange(left ? scintillaOne : scintillaTwo, MarkColorIndexRemovedOrAdded, start, length,
color);
}
/// <summary>
/// Sets the background color for the entire line of a <see cref="Scintilla"/> control.
/// </summary>
/// <param name="lineIndex">The index of the line to highlight.</param>
/// <param name="changeType">The type of change that was made to the line, indicating which color to set the background.</param>
private void SetLineBackgroundColor(int lineIndex, ChangeType changeType)
{
Highlight.HighlightLine(scintillaOne, lineIndex, (int)changeType);
Highlight.HighlightLine(scintillaTwo, lineIndex, (int)changeType);
}
/// <summary>
/// Handles the difference sub-pieces in a side-by-side comparison to set a color for a word.
/// </summary>
/// <param name="subPieces">A list of <see cref="DiffPiece"/> class instances to be marked.</param>
/// <param name="lineIndex">The index of the line to mark with the <see cref="Scintilla"/> control.</param>
/// <param name="left">A value indicating whether to use the left or the right side <see cref="Scintilla"/> control.</param>
private void HandleDiffSubPieces(List<DiffPiece> subPieces, int lineIndex, bool left)
{
int calcPosition = 0;
foreach (var subPiece in subPieces)
{
switch (subPiece.Type)
{
case ChangeType.Deleted:
MarkWithBackgroundColor(lineIndex, calcPosition, left, subPiece,
DiffColorDeleted);
break;
case ChangeType.Inserted:
MarkWithBackgroundColor(lineIndex, calcPosition, left, subPiece,
DiffColorAdded);
break;
}
if (subPiece.Position != null)
{
calcPosition += subPiece.Text.Length;
}
}
}
/// <summary>
/// Jumps the view into a given line index.
/// </summary>
/// <param name="lineIndex">Index of the line to jump the view to.</param>
/// <param name="backwards">if set to <c>true</c> the call was made from the <see cref="Previous"/> method.</param>
/// <returns><c>true</c> if the line index was valid and the view was scrolled, <c>false</c> otherwise.</returns>
private bool JumpToLine(int lineIndex, bool backwards)
{
if (lineIndex < 0 || lineIndex >= DiffLocations.Count)
{
return false;
}
if (diffStyle == DiffStyle.DiffList)
{
int linePos1 = scintillaOne.Lines[DiffLocations[lineIndex]].Position;
scintillaOne.GotoPosition(linePos1);
scintillaOne.ScrollCaret();
}
else if (diffStyle == DiffStyle.DiffSideBySide)
{
int linePos1 = scintillaOne.Lines[DiffLocations[lineIndex]].Position;
scintillaOne.GotoPosition(linePos1);
int linePos2 = scintillaTwo.Lines[DiffLocations[lineIndex]].Position;
scintillaTwo.GotoPosition(linePos2);
scintillaOne.ScrollCaret();
scintillaTwo.ScrollCaret();
}
if (!backwards && lineIndex + 1 >= DiffLocations.Count)
{
return false;
}
return true;
}
#endregion
#region PublicMethods
/// <summary>
/// Compares to contents of the two texts based on the <see cref="DiffStyle"/> property value.
/// </summary>
public void DiffTexts()
{
if (diffStyle == DiffStyle.DiffList)
{
DiffTextsList();
}
else
{
DiffTextsSideBySide();
}
}
/// <summary>
/// Swaps the texts to compare.
/// </summary>
// ReSharper disable once UnusedMember.Global
public void SwapDiff()
{
string temp = textLeft;
textLeft = textRight;
textRight = temp;
DiffTexts();
}
/// <summary>
/// Jumps to the next difference within the diff view.
/// </summary>
/// <returns><c>true</c> if the navigation to the next position was possible, <c>false</c> otherwise.</returns>
public bool Next()
{
if (diffIndex >= DiffLocations.Count)
{
return false;
}
diffIndex++;
return JumpToLine(diffIndex, false);
}
/// <summary>
/// Jumps to the previous difference within the diff view.
/// </summary>
/// <returns><c>true</c> if the navigation to the previous position was possible, <c>false</c> otherwise.</returns>
public bool Previous()
{
if (diffIndex < 0)
{
return false;
}
diffIndex--;
return JumpToLine(diffIndex, true);
}
#endregion
private void ScintillaDiffControl_Load(object sender, EventArgs e)
{
ryCommon.Auto.LeftClick(scintillaOne.Handle, 0, 0);
ryCommon.Auto.LeftClick(scintillaTwo.Handle, 0, 0);
}
}
}