658 lines
20 KiB
C#
658 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using RyzStudio.IO;
|
|
using RyzStudio.Runtime.InteropServices;
|
|
using RyzStudio.Windows.Forms;
|
|
|
|
namespace RandomFileRunner
|
|
{
|
|
public partial class MainForm : Form
|
|
{
|
|
private readonly FileSearcher _fileSearcher;
|
|
private CancellationTokenSource _cancellationToken = new CancellationTokenSource();
|
|
|
|
private List<string> _foundFiles = new List<string>();
|
|
private Process _currentProcess = null;
|
|
|
|
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
|
|
_fileSearcher = new FileSearcher();
|
|
_fileSearcher.OnDirectoryFound += fileSearcher_OnDirectoryFound;
|
|
_fileSearcher.OnFileFound += fileSearcher_OnFileFound;
|
|
_fileSearcher.OnSearchCompleted += fileSearcher_OnSearchCompleted;
|
|
|
|
memoBox1.WordWrap = false;
|
|
memoBox1.ScrollBars = ScrollBars.Vertical;
|
|
}
|
|
|
|
protected async override void OnLoad(EventArgs e)
|
|
{
|
|
base.OnLoad(e);
|
|
|
|
this.ClearSession();
|
|
|
|
var args = this.GetCommandLine();
|
|
|
|
string jsonfigFilename = null;
|
|
|
|
if (!args.TryGetValue("o", out jsonfigFilename))
|
|
{
|
|
if (!args.TryGetValue("open", out jsonfigFilename))
|
|
{
|
|
jsonfigFilename = null;
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(jsonfigFilename))
|
|
{
|
|
jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig");
|
|
}
|
|
|
|
if (System.IO.File.Exists(jsonfigFilename))
|
|
{
|
|
await LoadSessionFile(jsonfigFilename);
|
|
|
|
UIControl.Invoke(button1, (x) => button1.Enabled = (this.CurrentSession.SearchItems.Count > 0));
|
|
}
|
|
}
|
|
|
|
protected async override void OnShown(EventArgs e)
|
|
{
|
|
base.OnShown(e);
|
|
|
|
memoBox1.Focus();
|
|
}
|
|
|
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
|
{
|
|
base.OnFormClosing(e);
|
|
|
|
if (this.IsBusy)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
|
|
if (this.CurrentSession.ClosePrevOnNext)
|
|
{
|
|
CloseCurrentProcess(_currentProcess);
|
|
}
|
|
|
|
if (this.CurrentSession.NextHotKey != null)
|
|
{
|
|
if (this.CurrentSession.NextHotKey.KeyCode != Keys.None)
|
|
{
|
|
//#if !DEBUG
|
|
User32.UnregisterHotKey((IntPtr)Handle, 1);
|
|
//#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
switch (m.Msg)
|
|
{
|
|
case User32.WM_HOTKEY:
|
|
if (m.WParam.ToInt32() == 1)
|
|
{
|
|
dialogFooter1_OnButton1Click(null, null);
|
|
}
|
|
|
|
break;
|
|
//case WM_QUERYENDSESSION:
|
|
// requestExit = true;
|
|
// //this.Close();
|
|
// Application.Exit();
|
|
|
|
// break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
|
|
public bool IsBusy
|
|
{
|
|
get => field;
|
|
private set
|
|
{
|
|
field = value;
|
|
|
|
UIControl.Invoke(pictureBox1, (x) => pictureBox1.Image = (value ? RyzStudio.Resources.T3Resource.loading_block : null));
|
|
UIControl.Invoke(textBox1, (x) => textBox1.Enabled = !value);
|
|
UIControl.Invoke(button1, (x) => button1.LabelText = (value ? "&Cancel" : "&Search"));
|
|
UIControl.Invoke(dialogFooter1, (x) => dialogFooter1.Button1Visible = !value);
|
|
}
|
|
}
|
|
|
|
public AppSession CurrentSession
|
|
{
|
|
get
|
|
{
|
|
if (field == null) field = new AppSession();
|
|
|
|
return field;
|
|
}
|
|
private set => field = value;
|
|
} = new AppSession();
|
|
|
|
private List<string> SearchPathList
|
|
{
|
|
get
|
|
{
|
|
return (memoBox1.Lines?.ToList() ?? new List<string>()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
|
}
|
|
}
|
|
|
|
private void menuStrip1_MenuActivate(object sender, EventArgs e)
|
|
{
|
|
saveAsToolStripMenuItem.Enabled = (!this.IsBusy && (this.SearchPathList.Count > 0));
|
|
toolStripMenuItem2.Enabled = (!this.IsBusy && (_foundFiles.Count > 0));
|
|
}
|
|
|
|
#region Main Menu
|
|
|
|
/// <summary>
|
|
/// New
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private async void newToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
await Task.Run(() =>
|
|
{
|
|
if (this.IsBusy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (this.CurrentSession.ClosePrevOnNext)
|
|
{
|
|
CloseCurrentProcess(_currentProcess);
|
|
}
|
|
|
|
ClearSession();
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private async void openToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (this.IsBusy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (openFileDialog2.ShowDialog() == DialogResult.OK)
|
|
{
|
|
await LoadSessionFile(openFileDialog2.FileName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save as
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private async void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (this.IsBusy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
saveFileDialog1.Title = "Save session";
|
|
saveFileDialog1.Filter = "Session files (*.jsonfig)|*.jsonfig";
|
|
saveFileDialog1.DefaultExt = "jsonfig";
|
|
|
|
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
|
|
{
|
|
await SaveSessionFile(saveFileDialog1.FileName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Export file list
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private async void toolStripMenuItem2_Click(object sender, EventArgs e)
|
|
{
|
|
if (this.IsBusy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_foundFiles.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
saveFileDialog1.Title = "Save File List";
|
|
saveFileDialog1.Filter = "Text files (*.txt)|*.txt";
|
|
saveFileDialog1.DefaultExt = "txt";
|
|
|
|
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
|
|
{
|
|
try
|
|
{
|
|
await System.IO.File.WriteAllTextAsync(saveFileDialog1.FileName, string.Join(Environment.NewLine, _foundFiles.ToArray()));
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
RyzStudio.Forms.T3MessageBox.Show(this, exc.Message, "Save File List", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Close
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void exitToolStripMenuItem2_Click(object sender, EventArgs e)
|
|
{
|
|
this.Close();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Export File List
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private async void toolStripMenuItem1_Click(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Options
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (this.IsBusy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var optionsForm = new OptionsForm(this.CurrentSession);
|
|
if (optionsForm.ShowDialog() == DialogResult.OK)
|
|
{
|
|
this.CurrentSession = optionsForm.Result;
|
|
|
|
InvalidateHotKey();
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Help
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e)
|
|
{
|
|
RyzStudio.Diagnostics.Process.Execute(AppResource.AppHelpURL);
|
|
}
|
|
|
|
/// <summary>
|
|
/// About
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
|
|
{
|
|
var form = new RyzStudio.Forms.T3AboutForm();
|
|
form.ProductURL = AppResource.AppProductURL;
|
|
form.AuthorURL = AppResource.AppAuthorURL;
|
|
form.CompanyURL = AppResource.AppCompanyURL;
|
|
form.ProductCopyrightStartYear = 2021;
|
|
form.ProductLogo = AppResource.icon_64;
|
|
|
|
form.ShowDialog();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Search Engine
|
|
|
|
private async Task fileSearcher_OnFileFound(FileSearcher sender, string searchPath, string fileName)
|
|
{
|
|
await Task.Run(() =>
|
|
{
|
|
_foundFiles.Add(fileName);
|
|
|
|
UIControl.Invoke(label3, (x) => label3.Text = Path.GetFileName(fileName));
|
|
|
|
progressBar2.Maximum = (sender.FileCount + sender.NoAccessFileCount);
|
|
progressBar2.Value = sender.FileCount;
|
|
});
|
|
}
|
|
|
|
private async Task fileSearcher_OnDirectoryFound(FileSearcher sender, string searchPath, string directoryName)
|
|
{
|
|
await Task.Run(() =>
|
|
{
|
|
UIControl.Invoke(label4, (x) => label4.Text = Path.GetFileName(directoryName));
|
|
|
|
progressBar1.Maximum = sender.DirectoryCount;
|
|
progressBar1.Value = sender.BufferLevel;
|
|
});
|
|
}
|
|
|
|
private async Task fileSearcher_OnSearchCompleted(FileSearcher sender, TimeSpan elapsedTime)
|
|
{
|
|
await Task.Run(() =>
|
|
{
|
|
if (!_cancellationToken.IsCancellationRequested)
|
|
{
|
|
UIControl.Invoke(label4, (x) => label4.Text = $"Done ({Math.Floor(elapsedTime.TotalMinutes)}m {elapsedTime.Seconds}s)");
|
|
}
|
|
else
|
|
{
|
|
UIControl.Invoke(label4, (x) => label4.Text = $"Cancelled ({Math.Floor(elapsedTime.TotalMinutes)}m {elapsedTime.Seconds}s)");
|
|
|
|
_cancellationToken = new CancellationTokenSource();
|
|
}
|
|
|
|
UIControl.Invoke(label3, (x) => label3.Text = ((_foundFiles.Count <= 0) ? "0" : _foundFiles.Count.ToString("#,#", System.Globalization.CultureInfo.CurrentCulture)) + " File" + ((_foundFiles.Count == 1) ? "" : "s") + " Found");
|
|
|
|
progressBar1.Value = sender.BufferLevel;
|
|
progressBar2.Value = sender.FileCount;
|
|
|
|
UIControl.Invoke(dialogFooter1, (x) => dialogFooter1.Button1Visible = (_foundFiles.Count > 0));
|
|
|
|
this.IsBusy = false;
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
/// <summary>
|
|
/// Search
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private async void button2_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (this.IsBusy)
|
|
{
|
|
button1.LabelText = "&Cancelling...";
|
|
_cancellationToken.Cancel();
|
|
|
|
return;
|
|
}
|
|
|
|
this.IsBusy = true;
|
|
|
|
progressBar1.ShowText = true;
|
|
progressBar2.ShowText = true;
|
|
|
|
_foundFiles = new List<string>();
|
|
_cancellationToken = new CancellationTokenSource();
|
|
_currentProcess = null;
|
|
|
|
var paths = this.SearchPathList;
|
|
|
|
_fileSearcher.FileSearchPattern = textBox1.Text;
|
|
_fileSearcher.SearchPath = new List<string>();
|
|
|
|
UIControl.Invoke(label4, (x) => label4.Text = $"Peeking...");
|
|
UIControl.Invoke(label3, (x) => label3.Text = "");
|
|
|
|
await Task.Run(() =>
|
|
{
|
|
foreach (var item in paths)
|
|
{
|
|
if (_cancellationToken.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (System.IO.File.Exists(item))
|
|
{
|
|
_foundFiles.Add(item);
|
|
|
|
UIControl.Invoke(label3, (x) => label3.Text = item);
|
|
continue;
|
|
}
|
|
|
|
if (System.IO.Directory.Exists(item))
|
|
{
|
|
_fileSearcher.SearchPath.Add(item);
|
|
|
|
UIControl.Invoke(label3, (x) => label3.Text = item);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
UIControl.Invoke(label4, (x) => label4.Text = $"Peeking... {paths.Count}");
|
|
UIControl.Invoke(label3, (x) => label3.Text = ((_foundFiles.Count <= 0) ? "0" : _foundFiles.Count.ToString("#,#", System.Globalization.CultureInfo.CurrentCulture)) + " File" + ((_foundFiles.Count == 1) ? "" : "s") + " Found");
|
|
});
|
|
|
|
if (_fileSearcher.SearchPath.Count <= 0)
|
|
{
|
|
UIControl.Invoke(label4, (x) => label4.Text = $"Done");
|
|
UIControl.Invoke(label3, (x) => label3.Text = ((_foundFiles.Count <= 0) ? "0" : _foundFiles.Count.ToString("#,#", System.Globalization.CultureInfo.CurrentCulture)) + " File" + ((_foundFiles.Count == 1) ? "" : "s") + " Found");
|
|
}
|
|
else
|
|
{
|
|
UIControl.Invoke(label4, (x) => label4.Text = $"Searching...");
|
|
|
|
await _fileSearcher.Search(_cancellationToken.Token);
|
|
}
|
|
|
|
//this.IsBusy = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Close
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void button1_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
this.Close();
|
|
}
|
|
|
|
|
|
private void CloseCurrentProcess(Process p)
|
|
{
|
|
if (p == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
p.CloseMainWindow();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
private void InvalidateHotKey()
|
|
{
|
|
//#if !DEBUG
|
|
UIControl.Invoke(this, (x) =>
|
|
{
|
|
User32.UnregisterHotKey((IntPtr)Handle, 1);
|
|
});
|
|
//#endif
|
|
|
|
if (this.CurrentSession.NextHotKey != null)
|
|
{
|
|
if (this.CurrentSession.NextHotKey.KeyCode != Keys.None)
|
|
{
|
|
//#if !DEBUG
|
|
UIControl.Invoke(this, (x) =>
|
|
{
|
|
User32.RegisterHotKey((IntPtr)Handle, 1, this.CurrentSession.NextHotKey.ModifierCode, this.CurrentSession.NextHotKey.Key);
|
|
});
|
|
//#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ClearSession()
|
|
{
|
|
_foundFiles = new List<string>();
|
|
_currentProcess = null;
|
|
|
|
UIControl.Invoke(textBox1, (_) => textBox1.Text = "*.*");
|
|
UIControl.Invoke(memoBox1, (_) => memoBox1.Clear());
|
|
|
|
progressBar1.Clear(0);
|
|
progressBar2.Clear(0);
|
|
|
|
UIControl.Invoke(label4, (x) => label4.Text = "");
|
|
UIControl.Invoke(label3, (x) => label3.Text = "");
|
|
UIControl.Invoke(button1, (x) => button1.Enabled = false);
|
|
UIControl.Invoke(dialogFooter1, (x) => dialogFooter1.Button1Visible = false);
|
|
}
|
|
|
|
protected async Task LoadSessionFile(string filename)
|
|
{
|
|
await Task.Run(async () =>
|
|
{
|
|
this.CurrentSession = await RyzStudio.Text.Json.JsonSerialiser.DeserialiseFile<AppSession>(filename);
|
|
|
|
ClearSession();
|
|
|
|
textBox1.Text = (string.IsNullOrWhiteSpace(this.CurrentSession.SearchFilePattern) ? "*" : this.CurrentSession.SearchFilePattern?.Trim());
|
|
|
|
foreach (var item in this.CurrentSession?.SearchItems)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(item))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
UIControl.Invoke(memoBox1, (_) => memoBox1.AddLine(item));
|
|
}
|
|
|
|
UIControl.Invoke(label4, (x) => label4.Text = "Ready");
|
|
UIControl.Invoke(button1, (x) => button1.Enabled = (this.CurrentSession?.SearchItems.Count > 0));
|
|
|
|
// hotkey
|
|
InvalidateHotKey();
|
|
});
|
|
}
|
|
|
|
protected async Task SaveSessionFile(string filename)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(filename))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (this.CurrentSession == null)
|
|
{
|
|
this.CurrentSession = new AppSession();
|
|
}
|
|
|
|
await Task.Run(() =>
|
|
{
|
|
this.CurrentSession.SearchFilePattern = textBox1.Text;
|
|
this.CurrentSession.SearchItems = this.SearchPathList;
|
|
|
|
var result = RyzStudio.Text.Json.JsonSerialiser.SerialiseFile(filename, this.CurrentSession);
|
|
if (result.Success)
|
|
{
|
|
RyzStudio.Forms.T3MessageBox.Show(this, "Session saved!", "Save session");
|
|
}
|
|
else
|
|
{
|
|
RyzStudio.Forms.T3MessageBox.Show(this, result.Message, "Save session", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Run Next
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private async void dialogFooter1_OnButton1Click(object sender, MouseEventArgs e)
|
|
{
|
|
if (this.IsBusy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_foundFiles.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
await Task.Run(() =>
|
|
{
|
|
this.IsBusy = true;
|
|
|
|
if (this.CurrentSession.ClosePrevOnNext)
|
|
{
|
|
CloseCurrentProcess(_currentProcess);
|
|
}
|
|
|
|
string filename = null;
|
|
|
|
// retry 8 times
|
|
for (int i = 0; i < this.CurrentSession.RetryOnError; i++)
|
|
{
|
|
filename = _foundFiles[Random.Shared.Next(0, (_foundFiles.Count - 1))];
|
|
if (System.IO.File.Exists(filename))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
filename = null;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(filename))
|
|
{
|
|
_currentProcess = RyzStudio.Diagnostics.Process.Execute(filename);
|
|
}
|
|
|
|
this.IsBusy = false;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Close
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void dialogFooter1_OnButton2Click(object sender, MouseEventArgs e)
|
|
{
|
|
this.Close();
|
|
}
|
|
|
|
private void memoBox1_TextChanged(object sender, EventArgs e)
|
|
{
|
|
UIControl.Invoke(button1, (x) => button1.Enabled = !string.IsNullOrWhiteSpace(memoBox1.Text));
|
|
}
|
|
|
|
}
|
|
} |