445 lines
18 KiB
C#
445 lines
18 KiB
C#
/*
|
|
* 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
|
|
{
|
|
/// <summary>
|
|
/// 마지막으로 스크린샷 저장했던 폴더 열기
|
|
/// </summary>
|
|
public ICommand CMD_OpenFolder { get; }
|
|
|
|
/// <summary>
|
|
/// - 기본적으로 Aurora ViewManager의 메인/서브 메뉴 리스트를 이동하면서 캡처
|
|
/// - Param으로 Dictionary<(string, string), List<string>> 타입의 메뉴 리스트가 들어오면
|
|
/// 1번째 (string, string) : Aurora main/sub 메뉴
|
|
/// 2번째 List<string> : 위의 main/sub 메뉴로 이동한 상태에서 ScreenShotSequence.SYS_REQ_MENU_CHANGE_EXT 이벤트의 param으로 해당 string을 담아 Publish하면 해당 뷰에서 내부 메뉴를 체인지한다는 약속.
|
|
/// Sequence 동작 시 메인/서브/추가메뉴 조합으로 모두 traverse하면서 스크린샷 진행
|
|
/// </summary>
|
|
public ICommand CMD_ScreenShotAll { get; }
|
|
|
|
/// <summary>
|
|
/// 현재 열려 있는 뷰 상태로 Single 스크린샷
|
|
/// </summary>
|
|
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<ScreenShotSequence.ScreenShotWorkItem> 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<ScreenShotSequence.ScreenShotWorkItem>();
|
|
|
|
foreach (var item in _AuroraEnv.ViewManager.GetMenuList()) {
|
|
if (obj != null && obj is Dictionary<(string, string), List<string>> 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<string>> MenuList = new Dictionary<(string, string), List<string>>();
|
|
|
|
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<ScreenShotWorkItem> 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<ScreenShotWorkItem> 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<string> 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");
|
|
}
|
|
}
|
|
}
|