// --------------------------------------------------------------------------------------------------------------------
//
// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
//
//
// Defines the LogViewModel type.
//
// --------------------------------------------------------------------------------------------------------------------
namespace HandBrakeWPF.ViewModels
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Caliburn.Micro;
using HandBrakeWPF.Model.Logging;
using HandBrakeWPF.Properties;
using HandBrakeWPF.Services.Interfaces;
using HandBrakeWPF.Services.Logging.EventArgs;
using HandBrakeWPF.Services.Logging.Interfaces;
using HandBrakeWPF.Services.Queue.Interfaces;
using HandBrakeWPF.Utilities;
using HandBrakeWPF.ViewModels.Interfaces;
using Clipboard = System.Windows.Clipboard;
using ILog = Services.Logging.Interfaces.ILog;
using LogEventArgs = Services.Logging.EventArgs.LogEventArgs;
public class LogViewModel : ViewModelBase, ILogViewModel
{
private readonly IErrorService errorService;
private readonly ILogInstanceManager logInstanceManager;
private readonly IQueueService queueService;
private readonly object readLockObject = new object();
private ILog logService;
private StringBuilder log = new StringBuilder();
private long lastReadIndex;
private string selectedLogFile;
public LogViewModel(IErrorService errorService, ILogInstanceManager logInstanceManager, IQueueService queueService)
{
this.errorService = errorService;
this.logInstanceManager = logInstanceManager;
this.queueService = queueService;
this.Title = Resources.LogViewModel_Title;
}
public event EventHandler LogMessageReceived;
public string ActivityLog => this.log.ToString();
public BindingList LogFiles { get; private set; }
public string SelectedLogFile
{
get => this.selectedLogFile;
set
{
if (value == this.selectedLogFile)
{
return;
}
this.selectedLogFile = value;
this.NotifyOfPropertyChange(() => this.SelectedLogFile);
this.ChangeLogFileView();
}
}
public void OpenLogDirectory()
{
string logDir = DirectoryUtilities.GetLogDirectory();
string windir = Environment.GetEnvironmentVariable("WINDIR");
Process prc = new Process { StartInfo = { FileName = windir + @"\explorer.exe", Arguments = logDir } };
prc.Start();
}
public void CopyLog()
{
try
{
Clipboard.SetDataObject(this.ActivityLog, true);
}
catch (Exception exc)
{
this.errorService.ShowError(Resources.Clipboard_Unavailable, Resources.Clipboard_Unavailable_Solution, exc);
}
}
protected override void OnActivate()
{
this.logInstanceManager.NewLogInstanceRegistered += this.LogInstanceManager_NewLogInstanceRegistered;
this.queueService.QueueChanged += this.QueueService_QueueChanged;
this.CollectLogFiles(null);
base.OnActivate();
}
protected override void OnDeactivate(bool close)
{
if (this.logService != null)
{
this.logService.MessageLogged -= this.LogService_MessageLogged;
this.logService.LogReset -= this.LogService_LogReset;
}
this.SelectedLogFile = null;
this.logInstanceManager.NewLogInstanceRegistered -= this.LogInstanceManager_NewLogInstanceRegistered;
this.queueService.QueueChanged -= this.QueueService_QueueChanged;
base.OnDeactivate(close);
}
protected virtual void OnLogMessageReceived(LogEventArgs e)
{
var onLogMessageReceived = this.LogMessageReceived;
onLogMessageReceived?.Invoke(this, e);
}
private void ChangeLogFileView()
{
if (this.logService != null)
{
this.logService.MessageLogged -= this.LogService_MessageLogged;
this.logService.LogReset -= this.LogService_LogReset;
}
if (this.SelectedLogFile == null)
{
return;
}
this.logService = this.logInstanceManager.GetLogInstance(this.SelectedLogFile);
string logDir = DirectoryUtilities.GetLogDirectory();
string logFile = Path.Combine(logDir, this.selectedLogFile);
// This is not an active log, so read from disk.
if (this.logService == null)
{
try
{
if (File.Exists(logFile))
{
this.log.Clear();
using (StreamReader logReader = new StreamReader(logFile))
{
string logContent = logReader.ReadToEnd();
this.log.AppendLine(logContent);
}
}
else
{
this.log.Clear();
this.log.AppendLine("Sorry, The log file was not found.");
}
}
catch (Exception exc)
{
Debug.WriteLine(exc);
this.log.AppendLine(exc.ToString());
}
this.OnLogMessageReceived(null);
this.NotifyOfPropertyChange(() => this.ActivityLog);
}
// Active in-progress log, read from the log service.
if (this.logService != null)
{
this.logService.MessageLogged += this.LogService_MessageLogged;
this.logService.LogReset += LogService_LogReset;
// Refresh the Log Display
this.log.Clear();
foreach (LogMessage logMessage in this.logService.GetLogMessages())
{
this.log.AppendLine(logMessage.Content);
this.lastReadIndex = logMessage.MessageIndex;
if (this.lastReadIndex > logMessage.MessageIndex)
{
throw new Exception("Log Message Index Error");
}
}
this.OnLogMessageReceived(null);
this.NotifyOfPropertyChange(() => this.ActivityLog);
}
}
private void LogService_LogReset(object sender, EventArgs e)
{
this.log.Clear();
this.lastReadIndex = 0;
foreach (LogMessage logMessage in this.logService.GetLogMessages())
{
this.log.AppendLine(logMessage.Content);
this.lastReadIndex = logMessage.MessageIndex;
if (this.lastReadIndex > logMessage.MessageIndex)
{
throw new Exception("Log Message Index Error");
}
}
this.NotifyOfPropertyChange(() => this.ActivityLog);
this.OnLogMessageReceived(null);
}
private void LogService_MessageLogged(object sender, LogEventArgs e)
{
if (this.lastReadIndex < e.Log.MessageIndex)
{
Execute.OnUIThreadAsync(() =>
{
this.lastReadIndex = e.Log.MessageIndex;
this.log.AppendLine(e.Log.Content);
this.OnLogMessageReceived(e);
this.NotifyOfPropertyChange(() => this.ActivityLog);
});
}
}
private void LogInstanceManager_NewLogInstanceRegistered(object sender, LogFileEventArgs e)
{
this.CollectLogFiles(e.FileName);
}
private void QueueService_QueueChanged(object sender, EventArgs e)
{
this.CollectLogFiles(null);
}
private void CollectLogFiles(string filename)
{
lock (readLockObject)
{
BindingList activeLogs = new BindingList(this.logInstanceManager.GetLogFiles());
BindingList logfiles = new BindingList();
// Add Inactive Logs First.
foreach (string logFile in this.queueService.GetLogFilePaths())
{
logfiles.Add(Path.GetFileName(logFile));
}
// Add active logs second.
foreach (var log in activeLogs)
{
logfiles.Add(log);
}
this.LogFiles = logfiles;
this.NotifyOfPropertyChange(() => this.LogFiles);
if (!string.IsNullOrEmpty(filename))
{
this.SelectedLogFile = this.LogFiles.FirstOrDefault(c => c.Equals(filename, StringComparison.InvariantCultureIgnoreCase));
}
else
{
this.SelectedLogFile = this.LogFiles.LastOrDefault(c => !c.Contains("activity_log_main"));
}
if (this.SelectedLogFile == null)
{
this.SelectedLogFile = this.LogFiles.LastOrDefault();
}
}
}
}
}