FileWatcher/code/src/Form1.cs

834 lines
28 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using IronPython.Hosting;
using IronPython.Runtime;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using FolderSelect;
namespace FileWatcher
{
public sealed partial class Form1 : Form
{
public static FolderSelectDialog s_FolderDialogue = null;
public About m_About = null;
public NewFileGroup m_NewFileGroup = null;
public TabPage m_TabPageReference = null;
private ScriptEngine pyEngine = null;
private ScriptScope pyScope = null;
private EventRaisingStreamWriter m_LogStream = null;
private EventRaisingStreamWriter m_ErrorStream = null;
private MemoryStream m_MemoryStream = new MemoryStream();
private delegate void SetTextCallback(object sender, MyEvtArgs<string> e);
private List<string> CommandHistory = new List<string>();
private int MaxCommandHistorySize;
private int CurrentCommandHistoryItem;
private static bool m_ReallyClose;
// Better folder dialogue
// http://www.etcoding.com/post/2012/01/03/Better-folder-browser-dialog-in-WinForms
// Or just use this reflector hack:
// http://www.lyquidity.com/devblog/?p=136
#region Singleton
private static readonly Form1 instance = new Form1();
static Form1()
{
}
public static Form1 Instance
{
get
{
return instance;
}
}
#endregion
private Form1()
{
pyEngine = Python.CreateEngine();
pyEngine.Runtime.LoadAssembly(Assembly.GetAssembly(typeof(FileWatcher.Form1)));
pyScope = pyEngine.CreateScope();
m_LogStream = new EventRaisingStreamWriter(m_MemoryStream);
m_LogStream.StringWritten += new EventHandler<MyEvtArgs<string>>(script_StringWritten);
pyEngine.Runtime.IO.SetOutput(m_MemoryStream, m_LogStream);
m_ErrorStream = new EventRaisingStreamWriter(m_MemoryStream);
m_ErrorStream.StringWritten += new EventHandler<MyEvtArgs<string>>(script_ErrorStringWritten);
pyEngine.Runtime.IO.SetErrorOutput(m_MemoryStream, m_ErrorStream);
string pythonDir = FileGroupTab.GetPythonDir();
if (pythonDir != null)
{
string pythonLibs = Path.Combine(pythonDir, "Lib");
if (Directory.Exists(pythonLibs))
{
string import = "import sys" + Environment.NewLine + "sys.path.append('" + pythonLibs + "')" + Environment.NewLine;
ScriptSource source = pyEngine.CreateScriptSourceFromString(import, SourceCodeKind.AutoDetect);
object result = source.Execute(pyScope);
}
}
InitializeComponent();
s_FolderDialogue = new FolderSelectDialog();
s_FolderDialogue.Title = "Select a folder";
s_FolderDialogue.InitialDirectory = @"c:\";
m_ReallyClose = false;
Title = "";
LoadFileGroups();
if (Program.Args.ContainsKey("--minimize") || Program.Args.ContainsKey("-m"))
{
WindowState = FormWindowState.Minimized;
Form1_Resize(this, null);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
SetTrayIcon();
#if DEBUG
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
string[] names = a.GetManifestResourceNames();
foreach (string name in names)
System.Console.WriteLine(name);
#endif
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null) components.Dispose();
if (m_LogStream != null) m_LogStream.Dispose();
if (m_ErrorStream != null) m_ErrorStream.Dispose();
if (m_MemoryStream != null) m_MemoryStream.Dispose();
}
base.Dispose(disposing);
}
public static string ApplicationName
{
get { return "FileWatcher"; }
}
public string Title
{
get { return Text; }
set { Text = value.Length > 0 ? ApplicationName + " - " + value : ApplicationName; }
}
public static void Quit()
{
Application.Exit();
}
public void Save()
{
XmlDocument xmlDoc = new XmlDocument();
XmlNode xmlnode = xmlDoc.CreateNode(XmlNodeType.XmlDeclaration, "", "");
xmlDoc.AppendChild(xmlnode);
XmlElement root;
XmlElement xmlelem1;
XmlElement xmlelem2;
XmlElement xmlelem3;
XmlElement xmlelem4;
root = xmlDoc.CreateElement("", "root", "");
xmlDoc.AppendChild(root);
xmlelem1 = xmlDoc.CreateElement("", "groups", "");
root.AppendChild(xmlelem1);
foreach (TabPage tabPage in tabControl1.TabPages)
{
xmlelem2 = xmlDoc.CreateElement("", "group", "");
xmlelem2.SetAttribute("name", tabPage.Text);
xmlelem1.AppendChild(xmlelem2);
xmlelem3 = xmlDoc.CreateElement("", "directories", "");
xmlelem2.AppendChild(xmlelem3);
FileGroupTab fileGroup = null;
foreach (FileGroupTab fg in tabPage.Controls)
{
fileGroup = fg;
}
if (fileGroup != null)
{
foreach (string str in fileGroup.GetPaths())
{
xmlelem4 = xmlDoc.CreateElement("", "directory", "");
xmlelem4.SetAttribute("path", str);
xmlelem3.AppendChild(xmlelem4);
}
xmlelem3 = xmlDoc.CreateElement("", "extensions", "");
xmlelem3.SetAttribute("value", fileGroup.ExtensionString);
xmlelem2.AppendChild(xmlelem3);
xmlelem3 = xmlDoc.CreateElement("", "script", "");
xmlelem3.SetAttribute("path", fileGroup.ScriptPath);
xmlelem2.AppendChild(xmlelem3);
xmlelem3 = xmlDoc.CreateElement("", "delay", "");
xmlelem3.SetAttribute("value", fileGroup.Delay);
xmlelem2.AppendChild(xmlelem3);
if (fileGroup.Settings.relativeScriptCB.Checked)
{
xmlelem3 = xmlDoc.CreateElement("", "relativeScriptPath", "");
xmlelem2.AppendChild(xmlelem3);
}
if (fileGroup.Settings.stopScriptCB.Checked)
{
xmlelem3 = xmlDoc.CreateElement("", "stopScriptWhenFileUpdated", "");
xmlelem2.AppendChild(xmlelem3);
}
if (fileGroup.Settings.restartDelayCB.Checked)
{
xmlelem3 = xmlDoc.CreateElement("", "restartDelayTimerWhenFileUpdated", "");
xmlelem2.AppendChild(xmlelem3);
}
}
}
xmlelem1 = xmlDoc.CreateElement("", "preferences", "");
root.AppendChild(xmlelem1);
if (Preferences.Instance.autoSaveCB.Checked)
{
xmlelem2 = xmlDoc.CreateElement("", "autosave", "");
xmlelem1.AppendChild(xmlelem2);
}
xmlelem2 = xmlDoc.CreateElement("", "editor", "");
xmlelem1.AppendChild(xmlelem2);
xmlelem3 = xmlDoc.CreateElement("", "defaults", "");
xmlelem2.AppendChild(xmlelem3);
foreach (string str in Preferences.Instance.GetDefaultPrograms())
{
xmlelem4 = xmlDoc.CreateElement("", "default", "");
xmlelem4.SetAttribute("name", str);
xmlelem3.AppendChild(xmlelem4);
}
xmlelem3 = xmlDoc.CreateElement("", "programs", "");
xmlelem2.AppendChild(xmlelem3);
foreach (Tuple<string, string> tuple in Preferences.Instance.GetEditorProgramPaths())
{
xmlelem4 = xmlDoc.CreateElement("", "program", "");
xmlelem4.SetAttribute("name", tuple.Item1);
xmlelem4.SetAttribute("path", tuple.Item2);
xmlelem3.AppendChild(xmlelem4);
}
xmlDoc.Save(Path.Combine(new FileInfo(Application.ExecutablePath).DirectoryName, "settings.xml"));
Logger.Log("Saved settings.xml");
}
public void AutoSave()
{
if (Preferences.Instance.autoSaveCB.Checked)
{
Save();
}
}
public void SetTrayIcon()
{
if (WindowState == FormWindowState.Minimized)
{
notifyIcon1.Icon = new Icon(GetType().Module.Assembly.GetManifestResourceStream("FileWatcher.res.stock_3d-texture-spherical_16x16.ico"));
}
else
{
notifyIcon1.Icon = new Icon(GetType().Module.Assembly.GetManifestResourceStream("FileWatcher.res.stock_3d-texture-and-shading_16x16.ico"));
}
}
public void LoadFileGroups()
{
if ( null == m_TabPageReference )
{
m_TabPageReference = tabPage1;
tabControl1.TabPages.Remove(tabPage1);
}
}
public void NewFileGroup()
{
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.E))
{
//tabControl1.SelectedTab.Controls.
//return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
if (null == m_About || m_About.IsDisposed)
{
m_About = new About();
}
m_About.ShowDialog(this);
}
private void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
{
Preferences.Instance.ShowDialog(this);
}
private void toolStripButton3_Click(object sender, EventArgs e)
{
if (null == m_NewFileGroup || m_NewFileGroup.IsDisposed)
{
m_NewFileGroup = new NewFileGroup();
}
while (true)
{
DialogResult result = m_NewFileGroup.ShowDialog(this);
if (result == DialogResult.OK)
{
String groupName = m_NewFileGroup.GetFileGroupName();
String groupExtensions = m_NewFileGroup.GetFileGroupExtensions();
String scriptName = m_NewFileGroup.GetFileGroupScript();
foreach (TabPage page in tabControl1.TabPages)
{
if (page.Name == groupName)
{
continue;
}
}
TabPage tp = new TabPage();
tp.Text = groupName;
tabControl1.SuspendLayout();
tabControl1.TabPages.Add(tp);
tabControl1.ResumeLayout();
FileGroupTab groupTab = new FileGroupTab();
groupTab.ExtensionString = groupExtensions;
groupTab.ScriptPath = scriptName;
tp.SuspendLayout();
tp.Controls.Add(groupTab);
groupTab.Dock = DockStyle.Fill;
tp.ResumeLayout();
break;
}
else
{
break;
}
}
}
private void toolStripButton5_Click(object sender, EventArgs e)
{
}
private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)
{
}
private void folderBrowserDialog1_HelpRequest(object sender, EventArgs e)
{
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
Show();
WindowState = FormWindowState.Normal;
SetTrayIcon();
Activate();
}
private void Form1_Load(object sender, EventArgs e)
{
//global::FileWatcher.Properties.Resources
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.Load(Path.Combine(new FileInfo(Application.ExecutablePath).DirectoryName, "settings.xml"));
}
catch (System.IO.FileNotFoundException)
{
Save();
return;
}
catch (XmlException exc)
{
Console.WriteLine(exc.Message);
MessageBox.Show("There is an error in your settings.xml: " + exc.Message, "XML Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Save();
return;
}
List<String> invalidPaths = new List<String>();
XmlNode root = xmlDoc.SelectSingleNode("root");
if (root == null)
{
return;
}
XmlNode groupsXML = root.SelectSingleNode("groups");
if (groupsXML != null)
{
foreach (XmlNode node in groupsXML.SelectNodes("group"))
{
XmlAttribute nameXML = node.Attributes["name"];
XmlNode directoriesXML = node.SelectSingleNode("directories");
XmlNode extensionsXML = node.SelectSingleNode("extensions");
XmlNode scriptXML = node.SelectSingleNode("script");
XmlNode delayXML = node.SelectSingleNode("delay");
XmlNode relativeScriptPathXML = node.SelectSingleNode("relativeScriptPath");
XmlNode stopScriptWhenFileUpdatedXML = node.SelectSingleNode("stopScriptWhenFileUpdated");
XmlNode restartDelayTimerWhenFileUpdatedXML = node.SelectSingleNode("restartDelayTimerWhenFileUpdated");
string name = nameXML != null ? nameXML.InnerText : "";
string extensions = "";
string scriptPath = "";
string delay = "";
List<String> directories = new List<string>();
if (directoriesXML != null)
{
foreach (XmlNode directory in directoriesXML)
{
string dir = directory.Attributes["path"].InnerText;
// TODO: check to see if the directory is relative or not
if (!Directory.Exists(Path.Combine(new FileInfo(Application.ExecutablePath).DirectoryName, dir)))
{
invalidPaths.Add(dir);
}
directories.Add(dir);
}
}
if (extensionsXML != null)
{
XmlAttribute elem = extensionsXML.Attributes["value"];
if (elem != null)
{
extensions = elem.InnerText;
}
}
if (scriptXML != null)
{
XmlAttribute elem = scriptXML.Attributes["path"];
if (elem != null)
{
scriptPath = elem.InnerText;
}
}
if (delayXML != null)
{
XmlAttribute elem = delayXML.Attributes["value"];
if (elem != null)
{
delay = elem.InnerText;
}
}
if (name.Length > 0)
{
FileGroupTab groupTab = new FileGroupTab();
groupTab.ExtensionString = extensions;
groupTab.ScriptPath = scriptPath;
groupTab.Directories = directories;
groupTab.Delay = delay;
groupTab.Settings.relativeScriptCB.Checked = relativeScriptPathXML != null;
groupTab.Settings.stopScriptCB.Checked = stopScriptWhenFileUpdatedXML != null;
groupTab.Settings.restartDelayCB.Checked = restartDelayTimerWhenFileUpdatedXML != null;
TabPage tp = new TabPage();
tp.Text = name;
tabControl1.SuspendLayout();
tabControl1.TabPages.Add(tp);
tabControl1.ResumeLayout();
tp.SuspendLayout();
tp.Controls.Add(groupTab);
groupTab.Dock = DockStyle.Fill;
tp.ResumeLayout();
}
else
{
MessageBox.Show("There is a group with no name that was not loaded, the next time the settings are saved this unnamed group will be lost. Edit your settings.xml to save it, or carry on.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
if (invalidPaths.Count > 0)
{
MessageBox.Show("There are invalid paths in your settings file: '" + String.Join("', ", invalidPaths.ToArray()) + "'", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
XmlNode preferencesXML = root.SelectSingleNode("preferences");
if (preferencesXML != null)
{
XmlNode autosaveXML = preferencesXML.SelectSingleNode("autosave");
if (autosaveXML != null)
{
Preferences.Instance.autoSaveCB.Checked = true;
}
XmlNode editorXML = preferencesXML.SelectSingleNode("editor");
if (editorXML != null)
{
List<string> defaultPrograms = new List<string>();
List<Tuple<string, string>> userDefinedPrograms = new List<Tuple<string, string>>();
XmlNode defaultsXML = editorXML.SelectSingleNode("defaults");
if (defaultsXML != null)
{
foreach (XmlNode node in defaultsXML.SelectNodes("default"))
{
XmlAttribute attName = node.Attributes["name"];
if (attName != null)
{
defaultPrograms.Add(attName.InnerText);
}
}
}
XmlNode programsXML = editorXML.SelectSingleNode("programs");
if (programsXML != null)
{
foreach (XmlNode node in programsXML.SelectNodes("program"))
{
XmlAttribute attName = node.Attributes["name"];
XmlAttribute attPath = node.Attributes["path"];
if (attName != null && attPath != null)
{
userDefinedPrograms.Add(new Tuple<string, string>(attName.InnerText, attPath.InnerText));
}
}
}
Preferences.Instance.LoadEditorPreferences(defaultPrograms, userDefinedPrograms);
}
}
Logger.Log("Loaded settings.xml");
}
private void Form1_Resize(object sender, EventArgs e)
{
if (FormWindowState.Minimized == WindowState)
{
Hide();
SetTrayIcon();
}
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
}
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
m_ReallyClose = true;
Form1.Quit();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
m_ReallyClose = true;
Form1.Quit();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (!m_ReallyClose)
{
e.Cancel = true;
WindowState = FormWindowState.Minimized;
}
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Escape)
{
WindowState = FormWindowState.Minimized;
Form1_Resize(this, null);
e.Handled = true;
}
}
private void toolStripButton2_Click(object sender, EventArgs e)
{
if (s_FolderDialogue.ShowDialog())
{
foldersListBox.Items.Add(s_FolderDialogue.FileName);
Save();
}
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
while (foldersListBox.SelectedItems.Count > 0)
{
foldersListBox.Items.Remove(foldersListBox.SelectedItems[0]);
}
Save();
}
private void toolStripButton7_Click(object sender, EventArgs e)
{
}
private void hideToolStripMenuItem_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
Form1_Resize(this, null);
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
Save();
}
private void toolStripButton1_Click_1(object sender, EventArgs e)
{
Save();
}
private void toolStripButton3_Click_1(object sender, EventArgs e)
{
if (null == m_NewFileGroup || m_NewFileGroup.IsDisposed)
{
m_NewFileGroup = new NewFileGroup();
}
while (true)
{
DialogResult result = m_NewFileGroup.ShowDialog(this);
if (result == DialogResult.OK)
{
String groupName = m_NewFileGroup.GetFileGroupName();
String groupExtensions = m_NewFileGroup.GetFileGroupExtensions();
String scriptName = m_NewFileGroup.GetFileGroupScript();
foreach (TabPage page in tabControl1.TabPages)
{
if (page.Name == groupName)
{
continue;
}
}
TabPage tp = new TabPage();
tp.Text = groupName;
tabControl1.SuspendLayout();
tabControl1.TabPages.Add(tp);
tabControl1.SelectedTab = tp;
tabControl1.ResumeLayout();
FileGroupTab groupTab = new FileGroupTab();
groupTab.ExtensionString = groupExtensions;
groupTab.ScriptPath = scriptName;
tp.SuspendLayout();
tp.Controls.Add(groupTab);
groupTab.Dock = DockStyle.Fill;
tp.ResumeLayout();
break;
}
else
{
break;
}
}
}
private void toolStripButton4_Click(object sender, EventArgs e)
{
if (tabControl1.SelectedTab != null)
{
if (MessageBox.Show(
"Are you sure you want to delete " + tabControl1.SelectedTab.Text + "?",
"Confirm delete",
MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
FileGroupTab fileGroup = null;
foreach (FileGroupTab fg in tabControl1.SelectedTab.Controls)
{
fileGroup = fg;
}
if (fileGroup != null && MessageBox.Show(
"Do you want to delete the script associated with this file group?",
"Delete script?",
MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
string script_path = fileGroup.ScriptPath;
File.Delete(script_path);
}
tabControl1.TabPages.Remove(tabControl1.SelectedTab);
}
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
try
{
Logger.WriteLine("> " + textBox1.Text);
//CompiledCode compiled = source.Compile();
//compiled.Execute(pyScope);
//pyEngine.Execute(textBox1.Text, pyScope);
ScriptSource source = pyEngine.CreateScriptSourceFromString(textBox1.Text, SourceCodeKind.AutoDetect);
object result = source.Execute(pyScope);
if (result != null)
{
Logger.WriteLine(result.ToString());
}
}
catch (Microsoft.Scripting.SyntaxErrorException ex)
{
Logger.Error("Syntax error:" + ex.Message);
}
catch (IronPython.Runtime.UnboundNameException ex)
{
Logger.Error(ex.Message);
}
catch (System.MissingMemberException ex)
{
Logger.Error(ex.Message);
}
e.Handled = true;
}
}
private void script_StringWritten(object sender, MyEvtArgs<string> e)
{
if (textBox2.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(script_StringWritten);
this.Invoke(d, new object[] { sender, e });
}
else
{
textBox2.AppendText(e.Value);
textBox2.SelectionStart = textBox2.Text.Length;
textBox2.ScrollToCaret();
}
}
private void script_ErrorStringWritten(object sender, MyEvtArgs<string> e)
{
if (textBox2.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(script_ErrorStringWritten);
this.Invoke(d, new object[] { sender, e });
}
else
{
textBox2.AppendText(e.Value, Color.Maroon);
textBox2.SelectionStart = textBox2.Text.Length;
textBox2.ScrollToCaret();
}
}
}
}