diff --git a/ProgramQueuer/MainWindow.xaml b/ProgramQueuer/MainWindow.xaml index 14b5701..0b2a6ce 100755 --- a/ProgramQueuer/MainWindow.xaml +++ b/ProgramQueuer/MainWindow.xaml @@ -3,14 +3,16 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters="clr-namespace:ProgramQueuer.Helpers" xmlns:properties="clr-namespace:ProgramQueuer.Properties" - Title="MainWindow" + Title="Program Queuer" Closing="Window_Closing" AllowDrop="True" DragEnter="ListView_DragEnter" Drop="ListView_Drop" + Loaded="Window_Loaded" Width="{Binding Path=width, Source={x:Static properties:Settings.Default}, Mode=TwoWay}" - Height="{Binding Path=height, Source={x:Static properties:Settings.Default}, Mode=TwoWay}" Loaded="Window_Loaded" Icon="/ProgramQueuer;component/reports.ico"> + Height="{Binding Path=height, Source={x:Static properties:Settings.Default}, Mode=TwoWay}" Icon="/ProgramQueuer;component/program.ico" StateChanged="Window_StateChanged"> + @@ -18,9 +20,9 @@ - - + + @@ -35,7 +37,7 @@ - + @@ -59,6 +61,9 @@ + @@ -76,15 +81,40 @@ - - + + + + + + + + + - - + + + + Output + Override Console Window + + + + Controls whether the cmd (command line window) is displayed or not.If this is checked, ProgramQueuer will hide the window and transfer all output in the textbox below.If this is not checked, the original cmd window is displayed. + + + + + diff --git a/ProgramQueuer/MainWindow.xaml.cs b/ProgramQueuer/MainWindow.xaml.cs index 9ba69c0..226bbb0 100755 --- a/ProgramQueuer/MainWindow.xaml.cs +++ b/ProgramQueuer/MainWindow.xaml.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Text; +using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Data; @@ -11,8 +13,13 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using System.Resources; +using System.Windows.Threading; using ProgramQueuer.Queuer; using WPF.JoshSmith.ServiceProviders.UI; +using Microsoft.Win32; + +using NotifyIcon = System.Windows.Forms.NotifyIcon; namespace ProgramQueuer { @@ -22,24 +29,45 @@ namespace ProgramQueuer public partial class MainWindow : Window { EntryManager _manager; + OpenFileDialog _openFile; + NotifyIcon _icon; public MainWindow() { InitializeComponent(); _manager = new EntryManager(); + _openFile = new OpenFileDialog { Filter = "All Files (*.*)|*.*", + CheckFileExists = true, + Multiselect = true, + InitialDirectory = ProgramQueuer.Properties.Settings.Default.lastPath }; + this._icon = new NotifyIcon { Icon = Properties.Resources.program, Visible = true }; + this._icon.MouseClick += new System.Windows.Forms.MouseEventHandler(_icon_MouseClick); this.DataContext = _manager; this.listPrograms.ItemsSource = _manager.QueueList; } + void _icon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e) + { + this.Visibility = System.Windows.Visibility.Visible; + Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, + new Action(delegate() + { + this.WindowState = WindowState.Normal; + this.Activate(); + }) + ); + } + private void Window_Loaded(object sender, RoutedEventArgs e) { + _manager.RedirectOutput = ProgramQueuer.Properties.Settings.Default.redirectOutput; new ListViewDragDropManager(this.listPrograms); } private void GridSplitter_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e) { - ProgramQueuer.Properties.Settings.Default.split_height = (int)((sender as GridSplitter).Parent as Grid).RowDefinitions[2].Height.Value; + ProgramQueuer.Properties.Settings.Default.split_height = textboxStatus.Height; } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) @@ -50,6 +78,11 @@ namespace ProgramQueuer e.Cancel = true; return; } + else + _manager.ForceStop(); + this._icon.Visible = false; + ProgramQueuer.Properties.Settings.Default.redirectOutput = _manager.RedirectOutput; + ProgramQueuer.Properties.Settings.Default.lastPath = _openFile.InitialDirectory; ProgramQueuer.Properties.Settings.Default.Save(); } @@ -87,6 +120,7 @@ namespace ProgramQueuer foreach (string file in files) { _manager.QueueList.Add(new ProgramEntry { Name = file , Status = "Queued"}); + _openFile.InitialDirectory = new FileInfo(file).DirectoryName; } } } @@ -98,9 +132,19 @@ namespace ProgramQueuer private void buttonStopCurrent_Click(object sender, RoutedEventArgs e) { - if (MessageBox.Show("Are you sure you want to stop current running process and continue to next?", "Stop current worker?", MessageBoxButton.YesNo) == MessageBoxResult.Yes) + if (_manager.CurrentEntry == ((sender as Control).DataContext as ProgramEntry)) { - _manager.ForceStopCurrent(); + if (MessageBox.Show("Are you sure you want to kill this process and continue with the next one available?", "Stop current process?", MessageBoxButton.YesNo) == MessageBoxResult.Yes) + { + ((sender as Control).DataContext as ProgramEntry).Process.Kill(); + } + } + else + { + if (MessageBox.Show("Are you sure you want to kill this process?", "Stop selected process?", MessageBoxButton.YesNo) == MessageBoxResult.Yes) + { + ((sender as Control).DataContext as ProgramEntry).Process.Kill(); + } } } @@ -112,7 +156,80 @@ namespace ProgramQueuer private void buttonAdd_Click(object sender, RoutedEventArgs e) { + if (_openFile.ShowDialog() == true) + { + foreach (string file in _openFile.FileNames) + { + _manager.QueueList.Add(new ProgramEntry { Name = file, Status = "Queued" }); + _openFile.InitialDirectory = new FileInfo(file).DirectoryName; + } + } + } + private void checkboxOverrideOutput_Checked(object sender, RoutedEventArgs e) + { + if (textboxStatus != null) + textboxStatus.Visibility = Visibility.Visible; + } + + private void checkboxOverrideOutput_Unchecked(object sender, RoutedEventArgs e) + { + if (textboxStatus != null) + textboxStatus.Visibility = Visibility.Collapsed; + } + + private void ButtonHelp_Click(object sender, RoutedEventArgs e) + { + popupHelp.IsOpen = true; + } + + private void buttonStartCurrent_Click(object sender, RoutedEventArgs e) + { + _manager.RunProgram((sender as Control).DataContext as ProgramEntry); + } + + private void buttonClear_Click(object sender, RoutedEventArgs e) + { + popupEmpty.IsOpen = true;/* + */ + } + + private void Window_StateChanged(object sender, EventArgs e) + { + if (this.WindowState == System.Windows.WindowState.Minimized) + { + this.Visibility = System.Windows.Visibility.Collapsed; + } + } + + private void buttonClearFinished_Click(object sender, RoutedEventArgs e) + { + for (int i = 0; i < _manager.QueueList.Count; i++) + { + if (_manager.QueueList[i].Finished == true) + { + _manager.QueueList.Remove(_manager.QueueList[i]); + i--; + } + } + popupEmpty.IsOpen = false; + } + + private void buttonClearAll_Click(object sender, RoutedEventArgs e) + { + for (int i = 0; i < _manager.QueueList.Count; i++) + { + if (_manager.QueueList[i].Working) + { + MessageBox.Show("Cannot clear list while program are still in working mode. Please stop all running instances.", "Processes still running."); + return; + } + } + if (MessageBox.Show("Are you sure you want to clear list?", "Clear list?", MessageBoxButton.YesNo) == MessageBoxResult.Yes) + { + _manager.QueueList.Clear(); + } + popupEmpty.IsOpen = false; } } } diff --git a/ProgramQueuer/ProgramQueuer.csproj b/ProgramQueuer/ProgramQueuer.csproj index f0a3638..99e77ed 100755 --- a/ProgramQueuer/ProgramQueuer.csproj +++ b/ProgramQueuer/ProgramQueuer.csproj @@ -35,11 +35,13 @@ 4 - reports.ico + program.ico + + @@ -63,9 +65,6 @@ - - Settings.xaml - MSBuild:Compile Designer @@ -78,10 +77,6 @@ MainWindow.xaml Code - - Designer - MSBuild:Compile - @@ -126,10 +121,22 @@ - + - + + + + + + + + + + + + + + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -114,4 +117,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\program.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/ProgramQueuer/Properties/Settings.Designer.cs b/ProgramQueuer/Properties/Settings.Designer.cs index cb7f332..8526975 100755 --- a/ProgramQueuer/Properties/Settings.Designer.cs +++ b/ProgramQueuer/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.1 +// Runtime Version:4.0.30319.269 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -73,7 +73,7 @@ namespace ProgramQueuer.Properties { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("50")] + [global::System.Configuration.DefaultSettingValueAttribute("75")] public double columnWidth2 { get { return ((double)(this["columnWidth2"])); @@ -94,5 +94,29 @@ namespace ProgramQueuer.Properties { this["columnWidth3"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool redirectOutput { + get { + return ((bool)(this["redirectOutput"])); + } + set { + this["redirectOutput"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string lastPath { + get { + return ((string)(this["lastPath"])); + } + set { + this["lastPath"] = value; + } + } } } diff --git a/ProgramQueuer/Properties/Settings.settings b/ProgramQueuer/Properties/Settings.settings index 35c7044..e34df32 100755 --- a/ProgramQueuer/Properties/Settings.settings +++ b/ProgramQueuer/Properties/Settings.settings @@ -15,10 +15,16 @@ 300 - 50 + 75 200 + + True + + + + \ No newline at end of file diff --git a/ProgramQueuer/Queuer/EntryManager.cs b/ProgramQueuer/Queuer/EntryManager.cs index 4cada2e..482388c 100755 --- a/ProgramQueuer/Queuer/EntryManager.cs +++ b/ProgramQueuer/Queuer/EntryManager.cs @@ -12,32 +12,19 @@ namespace ProgramQueuer.Queuer public class EntryManager : INotifyPropertyChanged { bool _working; - bool _clearNext; - string _buffer; + bool _redirectOutput; ProgramEntry _currentEntry; - Process _currentProcess; - ProcessIOManager _processManager; public EntryManager() { QueueList = new ObservableCollection(); - _buffer = ""; _currentEntry = null; - _processManager = new ProcessIOManager(); - _processManager.StderrTextRead += new StringReadEventHandler(_processManager_StdoutTextRead); - _processManager.StdoutTextRead += new StringReadEventHandler(_processManager_StdoutTextRead); - _currentProcess = new Process(); - _currentProcess.StartInfo.UseShellExecute = false; - _currentProcess.StartInfo.RedirectStandardOutput = true; - _currentProcess.StartInfo.RedirectStandardError = true; - _currentProcess.StartInfo.RedirectStandardInput = true; - _currentProcess.StartInfo.CreateNoWindow = true; - _currentProcess.EnableRaisingEvents = true; - _currentProcess.Exited += new EventHandler(_currentProcess_Exited); + _redirectOutput = true; } public ObservableCollection QueueList; public event PropertyChangedEventHandler PropertyChanged = delegate { }; + public event EventHandler OnEntryFinish = delegate { }; public ProgramEntry CurrentEntry { @@ -59,45 +46,49 @@ namespace ProgramQueuer.Queuer } } + public bool RedirectOutput + { + get { return _redirectOutput; } + set + { + _redirectOutput = value; + PropertyChanged(this, new PropertyChangedEventArgs("RedirectOutput")); + } + } public void RunQueuer() { if (QueueList.Count > 0) { Working = true; + _currentEntry = QueueList[0]; RunProgram(QueueList[0]); } } - public void ForceStopCurrent() - { - _currentProcess.Kill(); - } - public void ForceStop() { this.Working = false; - _currentProcess.Kill(); + foreach (var entry in QueueList) + if (entry.Working) + entry.Process.Kill(); } - private void RunProgram(ProgramEntry entry) + public void RunProgram(ProgramEntry entry) { try { - _currentEntry = entry; - _currentEntry.Output = ""; - _currentEntry.Working = true; - _currentEntry.Status = "Starting"; - _currentProcess.StartInfo.FileName = _currentEntry.Name; - _currentProcess.StartInfo.WorkingDirectory = new FileInfo(_currentEntry.Name).DirectoryName; - _currentProcess.Start(); - _processManager.RunningProcess = _currentProcess; - _processManager.StartProcessOutputRead(); + entry.Output = ""; + entry.Working = true; + entry.Process.Exited += _currentProcess_Exited; + entry.StartProcess(_redirectOutput); + entry.Status = "Running"; } catch (Exception e) { - _currentEntry.Working = false; - _currentEntry.Finished = false; - _currentEntry.Output += string.Format("Error while starting {0}:\n\n{1}", _currentEntry.Name, e.ToString()); + entry.Working = false; + entry.Finished = false; + entry.Status = string.Format("Error while starting: {0}", e.Message); + entry.Output += string.Format("Error while starting {0}:\n\n{1}", _currentEntry.Name, e.ToString()); if (RunNext()) { _currentEntry = null; @@ -108,68 +99,46 @@ namespace ProgramQueuer.Queuer private bool RunNext() { - _currentEntry.Status = "Finished"; - if (QueueList.IndexOf(_currentEntry) >= 0 && QueueList.IndexOf(_currentEntry) < QueueList.Count - 1) - RunProgram(QueueList[QueueList.IndexOf(_currentEntry) + 1]); - else - return true; - return false; + for (int i = 0; i < QueueList.Count; i++) + { + if (!QueueList[i].Finished && !QueueList[i].Working) + { + _currentEntry = QueueList[i]; + RunProgram(_currentEntry); + return false; + } + } + return true; } void _currentProcess_Exited(object sender, EventArgs e) { - _processManager.StopMonitoringProcessOutput(); - _currentEntry.Working = false; - _currentEntry.Finished = true; - if (!this.Working) - return; - if (RunNext()) + string path = (sender as Process).StartInfo.FileName; + ProgramEntry curr = null; + foreach (var entry in QueueList) { - _currentEntry = null; - this.Working = false; + if (entry.Process == sender as Process) + { + curr = entry; + break; + } } - } + if (_redirectOutput) + curr.ProcessManager.StopMonitoringProcessOutput(); + curr.Working = false; + curr.Finished = true; + curr.Status = "Finished"; - void _processManager_StdoutTextRead(string text) - { - string[] lines = text.Split('\r'); - if (!text.EndsWith("\r") && !text.EndsWith("\n") && _clearNext) - { - _buffer += text; - return; - } - else - { - text = _buffer + text; - _buffer = ""; - } + OnEntryFinish(curr, new EventArgs()); - - if (_clearNext && text == "\n") - _clearNext = false; - - while (text.IndexOf('\b') >= 0) - { - if (_currentEntry.Output.Length > 0 && _currentEntry.Output[_currentEntry.Output.Length - 1] != '\n') - _currentEntry.Output = _currentEntry.Output.Remove(_currentEntry.Output.Length - 1); - text = text.Remove(text.IndexOf('\b'), 1); - } - - if (_clearNext && text.Replace("\n", "").Replace("\r", "").Trim() != "") - if (_currentEntry.Output.LastIndexOf('\n') < _currentEntry.Output.Length - 1) - _currentEntry.Output = _currentEntry.Output.Remove(_currentEntry.Output.LastIndexOf('\n') + 1) + text; - else - _currentEntry.Output += text; - else - _currentEntry.Output += text; - - if (text.Replace("\n", "").Trim() != "") - _currentEntry.Status = text.Replace("\n", "").Replace("\r", ""); - - if (lines.Length == 2 && lines[1] == "") - _clearNext = true; - else - _clearNext = false; + if (curr == _currentEntry) + if (!this.Working) + return; + else if (RunNext()) + { + _currentEntry = null; + this.Working = false; + } } } } diff --git a/ProgramQueuer/Queuer/ProcessIOManager.cs b/ProgramQueuer/Queuer/ProcessIOManager.cs index cabd5a8..1e4dd14 100755 --- a/ProgramQueuer/Queuer/ProcessIOManager.cs +++ b/ProgramQueuer/Queuer/ProcessIOManager.cs @@ -248,7 +248,7 @@ namespace ProgramQueuer.Queuer StderrTextRead(textbuffer.ToString()); } } - catch (Exception e) + catch (Exception) { } // 'Clear' the text buffer diff --git a/ProgramQueuer/Queuer/ProgramEntry.cs b/ProgramQueuer/Queuer/ProgramEntry.cs index 86752f7..3359267 100755 --- a/ProgramQueuer/Queuer/ProgramEntry.cs +++ b/ProgramQueuer/Queuer/ProgramEntry.cs @@ -1,8 +1,10 @@ using System; +using System.Diagnostics; using System.ComponentModel; using System.Collections.Generic; using System.Linq; using System.Text; +using System.IO; namespace ProgramQueuer.Queuer { @@ -11,13 +13,25 @@ namespace ProgramQueuer.Queuer bool _error; bool _working; bool _finished; + bool _clearNext; string _name; string _output; string _status; + string _buffer; + Process _process; + ProcessIOManager _processManager; public ProgramEntry() { Finished = false; + + _process = new Process(); + _process.StartInfo.UseShellExecute = false; + _process.EnableRaisingEvents = true; + + _processManager = new ProcessIOManager(); + _processManager.StderrTextRead += new StringReadEventHandler(_processManager_StdoutTextRead); + _processManager.StdoutTextRead += new StringReadEventHandler(_processManager_StdoutTextRead); } public event PropertyChangedEventHandler PropertyChanged = delegate { }; @@ -62,6 +76,17 @@ namespace ProgramQueuer.Queuer } } + public Process Process + { + get { return _process; } + set { _process = value; } + } + + public ProcessIOManager ProcessManager + { + get { return _processManager; } + set { _processManager = value; } + } public bool Working { get { return _working; } @@ -81,5 +106,63 @@ namespace ProgramQueuer.Queuer PropertyChanged(this, new PropertyChangedEventArgs("Error")); } } + + public void StartProcess(bool redirect) + { + _process.StartInfo.RedirectStandardOutput = redirect; + _process.StartInfo.RedirectStandardError = redirect; + _process.StartInfo.RedirectStandardInput = redirect; + _process.StartInfo.CreateNoWindow = redirect; + _process.StartInfo.FileName = this.Name; + _process.StartInfo.WorkingDirectory = new FileInfo(this.Name).DirectoryName; + _process.Start(); + if (redirect) + { + _processManager.RunningProcess = _process; + _processManager.StartProcessOutputRead(); + } + } + + void _processManager_StdoutTextRead(string text) + { + string[] lines = text.Split('\r'); + if (!text.EndsWith("\r") && !text.EndsWith("\n") && _clearNext) + { + _buffer += text; + return; + } + else + { + text = _buffer + text; + _buffer = ""; + } + + + if (_clearNext && text == "\n") + _clearNext = false; + + while (text.IndexOf('\b') >= 0) + { + if (this.Output.Length > 0 && this.Output[this.Output.Length - 1] != '\n') + this.Output = this.Output.Remove(this.Output.Length - 1); + text = text.Remove(text.IndexOf('\b'), 1); + } + + if (_clearNext && text.Replace("\n", "").Replace("\r", "").Trim() != "") + if (this.Output.LastIndexOf('\n') < this.Output.Length - 1) + this.Output = this.Output.Remove(this.Output.LastIndexOf('\n') + 1) + text; + else + this.Output += text; + else + this.Output += text; + + if (text.Replace("\n", "").Trim() != "") + this.Status = text.Replace("\n", "").Replace("\r", ""); + + if (lines.Length == 2 && lines[1] == "") + _clearNext = true; + else + _clearNext = false; + } } } diff --git a/ProgramQueuer/Resources/Help.png b/ProgramQueuer/Resources/Help.png new file mode 100755 index 0000000..a78b1cc Binary files /dev/null and b/ProgramQueuer/Resources/Help.png differ diff --git a/ProgramQueuer/Resources/Program.ico b/ProgramQueuer/Resources/Program.ico new file mode 100755 index 0000000..f1282c6 Binary files /dev/null and b/ProgramQueuer/Resources/Program.ico differ diff --git a/ProgramQueuer/Resources/force_run.png b/ProgramQueuer/Resources/force_run.png new file mode 100755 index 0000000..105ac78 Binary files /dev/null and b/ProgramQueuer/Resources/force_run.png differ diff --git a/ProgramQueuer/Resources/trash-icon.png b/ProgramQueuer/Resources/trash-icon.png new file mode 100755 index 0000000..d9de72c Binary files /dev/null and b/ProgramQueuer/Resources/trash-icon.png differ diff --git a/ProgramQueuer/Settings.xaml b/ProgramQueuer/Settings.xaml deleted file mode 100755 index c4865de..0000000 --- a/ProgramQueuer/Settings.xaml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/ProgramQueuer/Settings.xaml.cs b/ProgramQueuer/Settings.xaml.cs deleted file mode 100755 index 3794ab3..0000000 --- a/ProgramQueuer/Settings.xaml.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; - -namespace ProgramQueuer -{ - /// - /// Interaction logic for Settings.xaml - /// - public partial class Settings : Window - { - public Settings() - { - InitializeComponent(); - } - } -} diff --git a/ProgramQueuer/app.config b/ProgramQueuer/app.config index b549024..78f5f80 100755 --- a/ProgramQueuer/app.config +++ b/ProgramQueuer/app.config @@ -20,11 +20,17 @@ 300 - 50 + 75 200 + + True + + + + \ No newline at end of file diff --git a/ProgramQueuer/program.ico b/ProgramQueuer/program.ico new file mode 100755 index 0000000..e444b93 Binary files /dev/null and b/ProgramQueuer/program.ico differ diff --git a/ProgramQueuer/reports.ico b/ProgramQueuer/reports.ico deleted file mode 100755 index 7969ccb..0000000 Binary files a/ProgramQueuer/reports.ico and /dev/null differ