/*=============================================================================
Project: SharpImage
Module: siFormScriptConsole.cs
Language: C#
Author: Dan Mueller
Date: $Date: 2007-07-06 10:57:00 +1000 (Fri, 06 Jul 2007) $
Revision: $Revision: 2 $
Copyright (c) Queensland University of Technology (QUT) 2007.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=============================================================================*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using Crownwood.Magic.Collections;
using Crownwood.Magic.Common;
using Crownwood.Magic.Controls;
using Crownwood.Magic.Docking;
using Crownwood.Magic.Forms;
using Crownwood.Magic.Win32;
using SharpImage.Main;
using SharpImage.Properties;
namespace SharpImage.Script
{
public partial class siFormScriptConsole : Form
{
#region Constants
//=====================================================================
public const string PROMPT = "> ";
//=====================================================================
#endregion
#region Instance Variables
//=====================================================================
//=====================================================================
#endregion
#region Construction and Disposal
//=====================================================================
///
/// Default constructor
///
///
public siFormScriptConsole(IApplication parent)
{
InitializeComponent();
this.m_ParentApplication = parent;
this.txtConsole.ContextMenuStrip = this.ContextMenuStrip;
this.EnterImmediateMode();
}
//=====================================================================
#endregion
#region Properties
//=====================================================================
private IApplication m_ParentApplication = null;
private bool m_ImmediateMode = false;
private bool m_ImmediateModeFirstTime = true;
private List m_CommandList = new List();
private int m_CurrentCommandInList = 0;
///
/// Gets the application which parents this console.
///
protected IApplication ParentApplication
{
get { return this.m_ParentApplication; }
}
///
/// Gets/sets if the console is allowing user input.
///
private bool ImmediateMode
{
get { return this.m_ImmediateMode; }
set
{
// Set the flag
this.m_ImmediateMode = value;
// Nothing more to do if exiting immediate mode
if (!value)
return;
// Show the prompt if we are entering immediate mode
if (this.m_ImmediateModeFirstTime)
{
this.txtConsole.AppendText(PROMPT);
this.m_ImmediateModeFirstTime = false;
}
else
{
this.txtConsole.AppendText(Environment.NewLine);
this.txtConsole.AppendText(PROMPT);
}// end if
}
}
///
/// Gets a list of the commands executed.
///
protected List CommandList
{
get { return this.m_CommandList; }
}
///
/// Gets the current command in the list.
///
protected int CurrentCommandInList
{
get { return this.m_CurrentCommandInList; }
set
{
if (value < 0)
this.m_CurrentCommandInList = 0;
else if (value >= this.m_CommandList.Count)
this.m_CurrentCommandInList = this.m_CommandList.Count - 1;
else
this.m_CurrentCommandInList = value;
}
}
//=====================================================================
#endregion
#region Events and Delegates
//=====================================================================
public delegate void ScriptCommandHandler(string command);
private delegate void VoidHandler();
private delegate void StringHandler(string str);
private ScriptCommandHandler m_EventStorage_ScriptCommand;
///
/// An event raised when the user types a script command.
///
public event ScriptCommandHandler UserEnteredScriptCommand
{
add { this.m_EventStorage_ScriptCommand += value; }
remove { this.m_EventStorage_ScriptCommand -= value; }
}
///
/// Raise the UserEnteredScriptCommand event.
///
///
protected void RaiseScriptCommand(string command)
{
// Add the command to the command list
// NOTE: Newest commands are stored at the back of the list
this.CommandList.Add(command);
this.CurrentCommandInList = this.CommandList.Count - 1;
// Raise event
if (this.m_EventStorage_ScriptCommand != null)
this.m_EventStorage_ScriptCommand(command);
}
//============================================================================
#endregion
#region Public Methods
//=====================================================================
///
/// Focus the console.
///
///
public new bool Focus()
{
base.Focus();
return this.txtConsole.Focus();
}
///
/// Tell the console to enter immediate mode, which shows the prompt
/// and allows users to enter text.
///
/// This method is thread-safe.
public void EnterImmediateMode()
{
// Make the call thread-safe
if (this.InvokeRequired)
{
this.Invoke(new VoidHandler(this.EnterImmediateMode));
return;
}
this.ImmediateMode = true;
this.txtConsole.Focus();
this.CurrentCommandInList = this.CommandList.Count;
}
///
/// Writes the given string to the console with no carriage return.
///
///
/// This method is thread-safe.
public void Write(string info)
{
// Make the call thread-safe
if (this.InvokeRequired)
{
this.Invoke(new StringHandler(this.Write), info);
return;
}
this.txtConsole.AppendText(info);
}
///
/// Writes the given string to the console and appends a carriage
/// return at the end of the line.
///
///
/// This method is thread-safe.
public void WriteLine(string info)
{
// Make the call thread-safe
if (this.InvokeRequired)
{
this.Invoke(new StringHandler(this.WriteLine), info);
return;
}
// Split at "\r" or "\n" or "\r\n"
string[] split = new string[] { "\r\n", "\r", "\n" };
string[] lines = info.Split(split, 100, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
string formattedLine = line.Trim(' ');
this.txtConsole.AppendText(formattedLine + Environment.NewLine);
}
// Scroll to bottom
this.txtConsole.ScrollToCaret();
}
///
/// Writes a new line to the console.
///
/// This method is thread-safe.
public void WriteNewLine()
{
// Make the call thread-safe
if (this.InvokeRequired)
{
this.Invoke(new VoidHandler(this.WriteNewLine));
return;
}
this.txtConsole.AppendText(Environment.NewLine);
}
///
/// Clears the console text.
///
/// This method is thread-safe.
public void Clear()
{
// Make the call thread-safe
if (this.InvokeRequired)
{
this.Invoke(new VoidHandler(this.Clear));
return;
}
this.txtConsole.Clear();
this.m_ImmediateModeFirstTime = true;
}
//=====================================================================
#endregion
#region Private Methods
//=====================================================================
private void menuContextCopy_Click(object sender, EventArgs e)
{
if (this.txtConsole.Text != null &&
this.txtConsole.Text.Length > 0)
{
if (this.txtConsole.SelectionLength == 0)
// Copy the whole console
Clipboard.SetText(this.txtConsole.Text, TextDataFormat.Text);
else
Clipboard.SetText(this.txtConsole.SelectedText, TextDataFormat.Text);
}
}
private void menuContextPaste_Click(object sender, EventArgs e)
{
this.RemoveNewLineFromClipboard();
this.txtConsole.Paste();
}
private void menuContextClearAll_Click(object sender, EventArgs e)
{
this.Clear();
this.EnterImmediateMode();
}
private void txtConsole_KeyDown(object sender, KeyEventArgs e)
{
// Get the last line in the text box
int indexLastLine = this.txtConsole.Lines.Length - 1;
string lastline = this.txtConsole.Lines[indexLastLine];
// Determine which action to take based on the key pressed
if (e.KeyCode == Keys.Escape)
{
if (string.Compare(lastline, siFormScriptConsole.PROMPT) == 0)
// Don't do anything, the user has pressed escape on an empty prompt
return;
else
{
// Abort the current command
int lastPrompt = this.txtConsole.Text.LastIndexOf(PROMPT);
this.txtConsole.Text = this.txtConsole.Text.Substring(0, lastPrompt);
this.m_ImmediateModeFirstTime = true;
this.EnterImmediateMode();
}
}
else if (this.ImmediateMode && (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return))
{
e.SuppressKeyPress = true;
if (lastline.Length <= 2)
{
// The command was invalid
return;
}
else
{
// Try to run the command
this.ImmediateMode = false;
this.txtConsole.AppendText(Environment.NewLine);
this.RaiseScriptCommand(lastline.Replace(PROMPT, ""));
}
}
else if (this.ImmediateMode && e.KeyCode == Keys.Up)
{
e.SuppressKeyPress = true;
// Check there is something in the command list
if (this.CommandList.Count == 0)
return;
// Cycle backwards through the command list
string command = PROMPT + this.CommandList[this.CurrentCommandInList];
this.CurrentCommandInList--;
if (string.Compare(command, lastline, true) == 0)
command = PROMPT + this.CommandList[this.CurrentCommandInList];
// Set the command in the console
this.SetLastLineInConsole(command);
this.txtConsole.Select(this.txtConsole.Text.Length, 0);
this.txtConsole.ScrollToCaret();
}
else if (this.ImmediateMode && e.KeyCode == Keys.Down)
{
e.SuppressKeyPress = true;
// Check there is something in the command list
if (this.CommandList.Count == 0)
return;
// Cycle forwards through the command list
string command = PROMPT + this.CommandList[this.CurrentCommandInList];
this.CurrentCommandInList++;
if (string.Compare(command, lastline, true) == 0)
command = PROMPT + this.CommandList[this.CurrentCommandInList];
// Set the command in the console
this.SetLastLineInConsole(command);
this.txtConsole.Select(this.txtConsole.Text.Length, 0);
this.txtConsole.ScrollToCaret();
}
else if (this.ImmediateMode && e.KeyCode == Keys.Back && lastline.Length == PROMPT.Length)
{
// The user is trying to delete the prompt - stop them
e.SuppressKeyPress = true;
}
else if (this.ImmediateMode)
{
// Test for allowable keys
if (e.Control && e.KeyCode == Keys.C) return;
if (e.Control && e.KeyCode == Keys.V)
{
this.RemoveNewLineFromClipboard();
return;
}
if (e.KeyCode == Keys.Left) return;
if (e.KeyCode == Keys.Right) return;
if (e.KeyCode == Keys.Home) return;
if (e.KeyCode == Keys.End) return;
// Work out if the user is allowed to edit at the current position
bool isLastLine = this.txtConsole.GetLineFromCharIndex(this.txtConsole.SelectionStart) == (indexLastLine);
bool doesLastLineStartWithPrompt = lastline.StartsWith(siFormScriptConsole.PROMPT);
bool isCaretAfterPrompt = (this.txtConsole.GetFirstCharIndexFromLine(indexLastLine) + 1) < this.txtConsole.SelectionStart;
if (isLastLine && doesLastLineStartWithPrompt && isCaretAfterPrompt)
// The user is allowed to edit
return;
else
// The user is NOT allowed to edit
e.SuppressKeyPress = true;
}
else
{
// The user is NOT allowed to edit
e.SuppressKeyPress = true;
}
}
///
/// Replace the last line in the text box with the given value.
///
///
private void SetLastLineInConsole(string lastline)
{
if (this.txtConsole.Lines.Length == 0)
{
this.txtConsole.Text = lastline;
}
else
{
string[] lines = this.txtConsole.Lines;
lines[lines.Length - 1] = lastline;
this.txtConsole.Lines = lines;
}
}
private void RemoveNewLineFromClipboard()
{
string clipboard = Clipboard.GetText();
if (clipboard == null || clipboard.Length == 0) return;
clipboard = clipboard.Replace("\r\n", "");
clipboard = clipboard.Replace("\r", "");
clipboard = clipboard.Replace("\n", "");
Clipboard.SetText(clipboard);
}
//=====================================================================
#endregion
}
}