/*
* Copyright (c) 2022 LG Electronics Inc.
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
*/
using Aurora;
using Aurora.Api;
using Aurora.Api.Control;
using Aurora.View;
using AuroraUIComponent.Util.WindowAPI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AuroraUIComponent.Sequence
{
public class ScreenShotSequenceInit
{
///
/// 마지막으로 스크린샷 저장했던 폴더 열기
///
public ICommand CMD_OpenFolder { get; }
///
/// - 기본적으로 Aurora ViewManager의 메인/서브 메뉴 리스트를 이동하면서 캡처
/// - Param으로 Dictionary<(string, string), List> 타입의 메뉴 리스트가 들어오면
/// 1번째 (string, string) : Aurora main/sub 메뉴
/// 2번째 List : 위의 main/sub 메뉴로 이동한 상태에서 ScreenShotSequence.SYS_REQ_MENU_CHANGE_EXT 이벤트의 param으로 해당 string을 담아 Publish하면 해당 뷰에서 내부 메뉴를 체인지한다는 약속.
/// Sequence 동작 시 메인/서브/추가메뉴 조합으로 모두 traverse하면서 스크린샷 진행
///
public ICommand CMD_ScreenShotAll { get; }
///
/// 현재 열려 있는 뷰 상태로 Single 스크린샷
///
public ICommand CMD_ScreenShotSingle { get; }
private IAuroraEnvironment _AuroraEnv;
private string _SeqId;
public PermissionLevel AllowedPermissionLevel = PermissionLevel.NONE;
public ScreenShotSequenceInit(IAuroraEnvironment aurora, string seqId)
{
_AuroraEnv = aurora;
_SeqId = seqId;
CMD_OpenFolder = new DelegateCommand(DoOpenLastFolder);
CMD_ScreenShotAll = new DelegateCommand(DoStartScreenShotAll);
CMD_ScreenShotSingle = new DelegateCommand(DoScreenShotSingle);
}
private void DoOpenLastFolder(object obj)
{
var applyPermission = ApplicationExt.UsePermission;
if (applyPermission && ApplicationExt.PermissionLevel > (ushort)AllowedPermissionLevel) return;
StartScreenShot(ScreenShotSequence.eReqType.REQ_OPEN_FOLDER);
}
private void DoScreenShotSingle(object obj)
{
var applyPermission = ApplicationExt.UsePermission;
if (applyPermission && ApplicationExt.PermissionLevel > (ushort)AllowedPermissionLevel) return;
//if (!MessageUtil.ShowYesNoMessageDialog("ScreenShot", $"Do you want to start ScreenShot Sequence?")) return;
StartScreenShot(ScreenShotSequence.eReqType.REQ_SCREENSHOT_SINGLE);
}
private List MenuList;
private void DoStartScreenShotAll(object obj)
{
var applyPermission = ApplicationExt.UsePermission;
if (applyPermission && ApplicationExt.PermissionLevel > (ushort)AllowedPermissionLevel) return;
//if (!MessageUtil.ShowYesNoMessageDialog("ScreenShot", $"Do you want to start ScreenShot Sequence?")) return;
if (MenuList == null) {
MenuList = new List();
foreach (var item in _AuroraEnv.ViewManager.GetMenuList()) {
if (obj != null && obj is Dictionary<(string, string), List> subViewList) {
if (subViewList.Any(x => x.Key.Item1 == item.mainName && x.Key.Item2 == item.subName) && subViewList.First(x => x.Key.Item1 == item.mainName && x.Key.Item2 == item.subName).Value.Count() > 0) {
foreach (var tab in subViewList.First(x => x.Key.Item1 == item.mainName && x.Key.Item2 == item.subName).Value) {
MenuList.Add(new ScreenShotSequence.ScreenShotWorkItem(item.mainName, item.subName, tab, true));
}
} else {
MenuList.Add(new ScreenShotSequence.ScreenShotWorkItem(item.mainName, item.subName, "", true));
}
} else {
MenuList.Add(new ScreenShotSequence.ScreenShotWorkItem(item.mainName, item.subName, "", true));
}
}
}
if (MenuList.Count > 0) {
string prevMain = MenuList[0].MainMenu;
string prevSub = MenuList[0].SubMenu;
MenuList[0].IsFirstMain = true;
MenuList[0].IsFirstSub = true;
for (int i = 1; i < MenuList.Count; i++) {
if (prevMain != MenuList[i].MainMenu) {
MenuList[i].IsFirstMain = true;
MenuList[i].IsFirstSub = true;
prevMain = MenuList[i].MainMenu;
prevSub = MenuList[i].SubMenu;
} else if (prevSub != MenuList[i].SubMenu) {
MenuList[i].IsFirstSub = true;
prevSub = MenuList[i].SubMenu;
}
}
}
var _title = Application.Current.FindStrToken("ScreenShot");
var result = MessageDialog.Show(
Application.Current.MainWindow,
Application.Current.FindStrToken("ScreenShot"),
new UCScreenShotSelect() {
DataContext = new UCScreenShotSelectViewModel(MenuList)
},
MessageDialog.Type.AffirmativeAndNegative
);
if (result != MessageDialog.Result.Affirmative || !MenuList.Any(x => x.IsSelected)) return;
StartScreenShot(MenuList);
}
private void StartScreenShot(object param)
{
switch (_AuroraEnv.SequenceEntry[_SeqId].RunState) {
case SequenceRunState.Idle:
case SequenceRunState.Finish:
_AuroraEnv.SequenceEntry[_SeqId].Start(param);
break;
case SequenceRunState.Paused: // N/A (현재 중지시키는 UX 없음)
_AuroraEnv.SequenceEntry[_SeqId].Resume();
break;
case SequenceRunState.Running:
case SequenceRunState.StopHandling:
case SequenceRunState.EmergencyStopHandling:
case SequenceRunState.ForceErrorHandling:
MessageUtil.ShowErrorToast($"ScreenShot Sequence is in state {_AuroraEnv.SequenceEntry[_SeqId].RunState.ToString()}. Please Try Again Later");
break;
}
}
}
public class ScreenShotSequence
{
public const string SYS_REQ_MENU_CHANGE_EXT = AuroraSysEvent.SYS_REQ_MENU_CHANGE + "_EXT";
public static Dictionary<(string, string), List> MenuList = new Dictionary<(string, string), List>();
static readonly Logger Log = new Logger("MainSequence");
const string SEQ_Start = "Start"; // 딱 한번 Sequence 진입 시에만 실행될 Node. 필요한 Initialize 처리
const string SEQ_CheckNext = "CheckNext";
const string SEQ_MoveMenu = "MoveMenu";
const string SEQ_ScreenShot = "ScreenShot";
const string SEQ_End = "End";
public SequenceBuilder Builder()
{
SequenceBuilder sb = new SequenceBuilder(1000, true); // 무한, 시퀀스 Stop시 최대 대기시간.
//sb.AddAction(SEQ_FAIL_ERROR_HANDLING, HandleErrorAlarm);
sb.AddAction(SEQ_Start, NodeStart);
sb.AddDecision(SEQ_CheckNext, NodeCheckNext);
sb.AddAction(SEQ_MoveMenu, NodeMoveMenu);
sb.AddAction(SEQ_ScreenShot, NodeScreenShot);
sb.AddAction(SEQ_End, NodeEnd);
sb.Flows(sb.Init > sb[SEQ_Start] > sb[SEQ_CheckNext]);
sb.Flows(sb[SEQ_CheckNext] > sb[SEQ_MoveMenu] > sb[SEQ_ScreenShot]);
sb.Flows(sb[SEQ_CheckNext] > sb[SEQ_ScreenShot] > sb[SEQ_CheckNext]);
sb.Flows(sb[SEQ_CheckNext] > sb[SEQ_End]);
sb.Flows(sb[SEQ_End] > sb.Final);
//// Forced Error
//sb.Flows(sb[SEQ_Start] > sb.ForceError);
//sb.Flows(sb[SEQ_CheckNext] > sb.ForceError);
//sb.Flows(sb[SEQ_MoveMenu] > sb.ForceError);
//sb.Flows(sb[SEQ_ScreenShot] > sb.ForceError);
sb.OnStopped(OnStopped);
sb.OnForceError(OnForceError);
#if SEQ_DRAW
sb.Draw($"{GetType().Name}.pdf");
#endif
return sb;
}
public enum eReqType
{
NONE,
REQ_SCREENSHOT_MULTI,
REQ_SCREENSHOT_SINGLE,
REQ_OPEN_FOLDER
};
private string ManualSaveFolder = "ScreenShot_Manual";
private string SaveFolder = "";
public string GetLastSaveFolder() => SaveFolder;
public class ScreenShotWorkItem : NotifyPropertyChangedBase
{
private string _MainMenu;
public string MainMenu { get => _MainMenu; set => SetProperty(ref _MainMenu, value); }
private string _SubMenu;
public string SubMenu { get => _SubMenu; set => SetProperty(ref _SubMenu, value); }
private string _ExtMenu;
public string ExtMenu { get => _ExtMenu; set => SetProperty(ref _ExtMenu, value); }
private bool _IsSelected; public bool IsSelected { get => _IsSelected; set => SetProperty(ref _IsSelected, value); }
private bool _IsFirstMain; public bool IsFirstMain { get => _IsFirstMain; set => SetProperty(ref _IsFirstMain, value); }
private bool _IsFirstSub; public bool IsFirstSub { get => _IsFirstSub; set => SetProperty(ref _IsFirstSub, value); }
public ScreenShotWorkItem(string mainName, string subName, string tabName = null, bool isSelected = true)
{
MainMenu = mainName;
SubMenu = subName;
ExtMenu = tabName;
IsSelected = isSelected;
}
}
private IList WorkList;
private int ScreenShotCount = 0;
private eReqType _Mode = eReqType.NONE;
private SequenceActionResult NodeStart(SequenceContext context, string id, SequenceActionResult param)
{
ScreenShotCount = 0;
if (param.Param is eReqType reqType) {
if (reqType == eReqType.REQ_OPEN_FOLDER) {
_Mode = reqType;
Log.I($"Open Last ScreenShot Folder : {SaveFolder}");
return SequenceAction.Ok();
} else /* if (reqType == eReqType.REQ_SCREENSHOT_SINGLE) */ {
WorkList = null;
SaveFolder = ManualSaveFolder;
if (!string.IsNullOrEmpty(ApplicationExt.DataPath)) {
SaveFolder = Path.Combine(ApplicationExt.DataPath, "ScreenShot", SaveFolder);
}
_Mode = reqType;
Log.I($"ScreenShot Start : Single");
}
} else if (param.Param is IList menuList) {
WorkList = menuList;
SaveFolder = $"ScreenShot_{DateTime.Now.ToString("yyMMdd-HHmmss")}";
if (!string.IsNullOrEmpty(ApplicationExt.DataPath)) {
SaveFolder = Path.Combine(ApplicationExt.DataPath, "ScreenShot", SaveFolder);
}
_Mode = eReqType.REQ_SCREENSHOT_MULTI;
Log.I($"ScreenShot Start : Total[{WorkList.Count(x => x.IsSelected)}] at [{SaveFolder}]");
} else {
// Not Expected
return new SequenceActionResult(-1, "Invalid Request");
}
if (string.IsNullOrEmpty(SaveFolder)) {
return new SequenceActionResult(-1, "Invalid Folder");
}
if (!Directory.Exists(SaveFolder)) {
Directory.CreateDirectory(SaveFolder);
}
if (!Directory.Exists(SaveFolder)) {
return new SequenceActionResult(-1, "Something Wrong :: Cannot Create Directory");
}
return SequenceAction.Ok();
}
private string NodeCheckNext(SequenceContext context, string id, ICollection branches, SequenceActionResult param)
{
switch (_Mode) {
case eReqType.REQ_SCREENSHOT_SINGLE:
if (ScreenShotCount > 0) {
return SEQ_End;
} else {
return SEQ_ScreenShot;
}
case eReqType.REQ_SCREENSHOT_MULTI:
if (WorkList.Count > 0 && WorkList.Count(x => x.IsSelected) > ScreenShotCount) {
// Move Menu
return SEQ_MoveMenu;
} else {
return SEQ_End;
}
case eReqType.REQ_OPEN_FOLDER:
default:
return SEQ_End;
}
}
public string CheckValidFilename(string testName)
{
Regex containsABadCharacter = new Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars())) + "]");
if (containsABadCharacter.IsMatch(testName)) {
testName = containsABadCharacter.Replace(testName, "_");
};
// other checks for UNC, drive-path format, etc
return testName;
}
private SequenceActionResult NodeMoveMenu(SequenceContext context, string id, SequenceActionResult param)
{
Log.FuncV();
if (_Mode != eReqType.REQ_SCREENSHOT_MULTI) {
return new SequenceActionResult(0, string.Empty);
}
if (WorkList == null || WorkList.Count(x => x.IsSelected) <= ScreenShotCount) {
return new SequenceActionResult(0, string.Empty);
}
var curItem = WorkList.Where(x => x.IsSelected).ElementAt(ScreenShotCount); // [Coverity] CID# 12646
if (curItem == null) {
return new SequenceActionResult(0, string.Empty);
}
Application.Current.AuroraEnv().ViewManager.ChangeMenu(curItem.MainMenu, curItem.SubMenu);
Thread.Sleep(1000);
string fileName;
if (!string.IsNullOrEmpty(curItem.ExtMenu)) {
context.EventPublisher.Publish(new EventMessage("ScreenShot", SYS_REQ_MENU_CHANGE_EXT, curItem.ExtMenu));
if (!curItem.IsFirstSub) {
Thread.Sleep(1000);
}
fileName = $"Screen_{curItem.MainMenu}_{curItem.SubMenu}_{curItem.ExtMenu}.png";
} else {
fileName = $"Screen_{curItem.MainMenu}_{curItem.SubMenu}.png";
}
fileName = CheckValidFilename(fileName);
return new SequenceActionResult(0, fileName);
}
private SequenceActionResult NodeScreenShot(SequenceContext context, string id, SequenceActionResult param)
{
string fileName = null;
if (_Mode == eReqType.REQ_SCREENSHOT_SINGLE) {
fileName = $"{SaveFolder}\\Manual_{DateTime.Now.ToString("yyMMdd-HHmmss")}.png";
Log.FuncV($"Process Single ScreehShot");
} else if (_Mode == eReqType.REQ_SCREENSHOT_MULTI) {
if (param == null || string.IsNullOrEmpty(param.Param as string)) {
// Unknown Error
fileName = $"{SaveFolder}\\Unknown_{DateTime.Now.ToString("yyMMdd-HHmmss")}.png";
} else {
fileName = $"{SaveFolder}\\{param.Param.ToString()}";
}
Log.FuncV($"Process {ScreenShotCount} / {WorkList.Count(x => x.IsSelected)} : {fileName}");
}
if (!string.IsNullOrEmpty(fileName)) {
Application.Current.Dispatcher.Invoke(() => {
var bounds = Application.Current.MainWindow.RenderSize;
RenderTargetBitmap rtb = new RenderTargetBitmap((int)bounds.Width, (int)bounds.Height, 96, 96, PixelFormats.Pbgra32);
rtb.Render(Application.Current.MainWindow);
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(rtb));
using (Stream stm = File.Create(fileName)) {
png.Save(stm);
}
if (_Mode == eReqType.REQ_SCREENSHOT_SINGLE) {
// 클립보드에 이미지 복사
//Clipboard.SetImage(BitmapSource.Create(rtb.PixelWidth, rtb.PixelHeight, 96, 96, PixelFormats.Pbgra32, null, rtb.BackBuffer, rtb.BackBufferStride));
Clipboard.SetImage(rtb);
}
});
}
ScreenShotCount++;
return SequenceAction.Ok();
}
private SequenceActionResult NodeEnd(SequenceContext context, string id, SequenceActionResult param)
{
Log.FuncV($"Open Folder :: {SaveFolder}");
if (!string.IsNullOrEmpty(SaveFolder) && Directory.Exists(SaveFolder)) {
//Process.Start("explorer.exe", SaveFolder);
WindowUtil.OpenOrActivateFolder(SaveFolder);
} else {
return new SequenceActionResult(-1, "Invalid Folder");
}
return SequenceAction.Ok();
}
private void OnStopped(SequenceContext obj)
{
// MessageUtil.ShowSuccessToast();
}
private void OnForceError(SequenceContext arg1, string arg2)
{
MessageUtil.ShowErrorToast("Sequence Failed");
}
}
}