/
githubmirror
/
PowerToys
Обзор
Документация
Войти
/
githubmirror
/
PowerToys
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/modules/Workspaces/WorkspacesEditor/Models/Project.cs
411 строк
15 KB
Kai Tao
Cmdpal extension: Powertoys extension for cmdpal (#44006)
23 дек 2025, 16:07
Не верифицирован
23 дек 2025, 16:07
d87dde1
Код
Авторство
О чём код?
// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using System.Threading.Tasks; using System.Windows.Media.Imaging; using ManagedCommon; using WorkspacesCsharpLibrary.Data; using WorkspacesEditor.Utils; namespace WorkspacesEditor.Models { public class Project : INotifyPropertyChanged { [JsonIgnore] public string EditorWindowTitle { get; set; } public string Id { get; private set; } private string _name; public string Name { get => _name; set { _name = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(Name))); OnPropertyChanged(new PropertyChangedEventArgs(nameof(CanBeSaved))); } } public long CreationTime { get; } // in seconds public long LastLaunchedTime { get; } // in seconds public bool IsShortcutNeeded { get; set; } public bool MoveExistingWindows { get; set; } public string LastLaunched { get { string lastLaunched = WorkspacesEditor.Properties.Resources.LastLaunched + ": "; if (LastLaunchedTime == 0) { return lastLaunched + WorkspacesEditor.Properties.Resources.Never; } const int SECOND = 1; const int MINUTE = 60 * SECOND; const int HOUR = 60 * MINUTE; const int DAY = 24 * HOUR; const int MONTH = 30 * DAY; DateTime lastLaunchDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(LastLaunchedTime); TimeSpan ts = DateTime.UtcNow - lastLaunchDateTime; double delta = Math.Abs(ts.TotalSeconds); if (delta < 1 * MINUTE) { return lastLaunched + WorkspacesEditor.Properties.Resources.Recently; } if (delta < 2 * MINUTE) { return lastLaunched + WorkspacesEditor.Properties.Resources.OneMinuteAgo; } if (delta < 45 * MINUTE) { return lastLaunched + ts.Minutes + " " + WorkspacesEditor.Properties.Resources.MinutesAgo; } if (delta < 90 * MINUTE) { return lastLaunched + WorkspacesEditor.Properties.Resources.OneHourAgo; } if (delta < 24 * HOUR) { return lastLaunched + ts.Hours + " " + WorkspacesEditor.Properties.Resources.HoursAgo; } if (delta < 48 * HOUR) { return lastLaunched + WorkspacesEditor.Properties.Resources.Yesterday; } if (delta < 30 * DAY) { return lastLaunched + ts.Days + " " + WorkspacesEditor.Properties.Resources.DaysAgo; } if (delta < 12 * MONTH) { int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); return lastLaunched + (months <= 1 ? WorkspacesEditor.Properties.Resources.OneMonthAgo : months + " " + WorkspacesEditor.Properties.Resources.MonthsAgo); } else { int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); return lastLaunched + (years <= 1 ? WorkspacesEditor.Properties.Resources.OneYearAgo : years + " " + WorkspacesEditor.Properties.Resources.YearsAgo); } } } public bool CanBeSaved => Name.Length > 0 && Applications.Count > 0; private bool _isRevertEnabled; public bool IsRevertEnabled { get => _isRevertEnabled; set { if (_isRevertEnabled != value) { _isRevertEnabled = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsRevertEnabled))); } } } private bool _isPopupVisible; [JsonIgnore] public bool IsPopupVisible { get => _isPopupVisible; set { _isPopupVisible = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsPopupVisible))); } } public List<Application> Applications { get; set; } public List<object> ApplicationsListed { get { List<object> applicationsListed = []; ILookup<MonitorSetup, Application> apps = Applications.Where(x => !x.Minimized).ToLookup(x => x.MonitorSetup); foreach (IGrouping<MonitorSetup, Application> appItem in apps.OrderBy(x => x.Key.MonitorDpiUnawareBounds.Left).ThenBy(x => x.Key.MonitorDpiUnawareBounds.Top)) { MonitorHeaderRow headerRow = new() { MonitorName = "Screen " + appItem.Key.MonitorNumber, SelectString = Properties.Resources.SelectAllAppsOnMonitor + " " + appItem.Key.MonitorInfo }; applicationsListed.Add(headerRow); foreach (Application app in appItem) { applicationsListed.Add(app); } } IEnumerable<Application> minimizedApps = Applications.Where(x => x.Minimized); if (minimizedApps.Any()) { MonitorHeaderRow headerRow = new() { MonitorName = Properties.Resources.Minimized_Apps, SelectString = Properties.Resources.SelectAllMinimizedApps }; applicationsListed.Add(headerRow); foreach (Application app in minimizedApps) { applicationsListed.Add(app); } } return applicationsListed; } } [JsonIgnore] public string AppsCountString { get { int count = Applications.Count; return count.ToString(CultureInfo.InvariantCulture) + " " + (count == 1 ? Properties.Resources.App : Properties.Resources.Apps); } } public List<MonitorSetup> Monitors { get; } public bool IsPositionChangedManually { get; set; } // telemetry private BitmapImage _previewIcons; private BitmapImage _previewImage; private double _previewImageWidth; public Project(Project selectedProject) { Id = selectedProject.Id; Name = selectedProject.Name; PreviewIcons = selectedProject.PreviewIcons; PreviewImage = selectedProject.PreviewImage; IsShortcutNeeded = selectedProject.IsShortcutNeeded; MoveExistingWindows = selectedProject.MoveExistingWindows; int screenIndex = 1; Monitors = []; foreach (MonitorSetup item in selectedProject.Monitors.OrderBy(x => x.MonitorDpiAwareBounds.Left).ThenBy(x => x.MonitorDpiAwareBounds.Top)) { Monitors.Add(item); screenIndex++; } Applications = []; foreach (Application item in selectedProject.Applications) { Application newApp = new(item); newApp.Parent = this; newApp.InitializationFinished(); Applications.Add(newApp); } } public Project(ProjectWrapper project) { Id = project.Id; Name = project.Name; CreationTime = project.CreationTime; LastLaunchedTime = project.LastLaunchedTime; IsShortcutNeeded = project.IsShortcutNeeded; MoveExistingWindows = project.MoveExistingWindows; Monitors = []; Applications = []; foreach (ApplicationWrapper app in project.Applications) { Models.Application newApp = new() { Id = string.IsNullOrEmpty(app.Id) ? $"{{{Guid.NewGuid()}}}" : app.Id, AppName = app.Application, AppPath = app.ApplicationPath, AppTitle = app.Title, PwaAppId = string.IsNullOrEmpty(app.PwaAppId) ? string.Empty : app.PwaAppId, Version = string.IsNullOrEmpty(app.Version) ? string.Empty : app.Version, PackageFullName = app.PackageFullName, AppUserModelId = app.AppUserModelId, Parent = this, CommandLineArguments = app.CommandLineArguments, IsElevated = app.IsElevated, CanLaunchElevated = app.CanLaunchElevated, Maximized = app.Maximized, Minimized = app.Minimized, IsNotFound = false, Position = new Models.Application.WindowPosition() { Height = app.Position.Height, Width = app.Position.Width, X = app.Position.X, Y = app.Position.Y, }, MonitorNumber = app.Monitor, }; newApp.InitializationFinished(); Applications.Add(newApp); } foreach (MonitorConfigurationWrapper monitor in project.MonitorConfiguration) { System.Windows.Rect dpiAware = new(monitor.MonitorRectDpiAware.Left, monitor.MonitorRectDpiAware.Top, monitor.MonitorRectDpiAware.Width, monitor.MonitorRectDpiAware.Height); System.Windows.Rect dpiUnaware = new(monitor.MonitorRectDpiUnaware.Left, monitor.MonitorRectDpiUnaware.Top, monitor.MonitorRectDpiUnaware.Width, monitor.MonitorRectDpiUnaware.Height); Monitors.Add(new MonitorSetup(monitor.Id, monitor.InstanceId, monitor.MonitorNumber, monitor.Dpi, dpiAware, dpiUnaware)); } } public BitmapImage PreviewIcons { get => _previewIcons; set { _previewIcons = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(PreviewIcons))); } } public BitmapImage PreviewImage { get => _previewImage; set { _previewImage = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(PreviewImage))); } } public double PreviewImageWidth { get => _previewImageWidth; set { _previewImageWidth = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(PreviewImageWidth))); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(PropertyChangedEventArgs e) { PropertyChanged?.Invoke(this, e); } public async void Initialize(Theme currentTheme) { PreviewIcons = await Task.Run(() => DrawHelper.DrawPreviewIcons(this)); Rectangle commonBounds = GetCommonBounds(); PreviewImage = await Task.Run(() => DrawHelper.DrawPreview(this, commonBounds, currentTheme)); PreviewImageWidth = commonBounds.Width / (commonBounds.Height * 1.2 / 200); } private Rectangle GetCommonBounds() { double minX = Monitors.First().MonitorDpiAwareBounds.Left; double minY = Monitors.First().MonitorDpiAwareBounds.Top; double maxX = Monitors.First().MonitorDpiAwareBounds.Right; double maxY = Monitors.First().MonitorDpiAwareBounds.Bottom; for (int monitorIndex = 1; monitorIndex < Monitors.Count; monitorIndex++) { Monitor monitor = Monitors[monitorIndex]; minX = Math.Min(minX, monitor.MonitorDpiAwareBounds.Left); minY = Math.Min(minY, monitor.MonitorDpiAwareBounds.Top); maxX = Math.Max(maxX, monitor.MonitorDpiAwareBounds.Right); maxY = Math.Max(maxY, monitor.MonitorDpiAwareBounds.Bottom); } return new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)); } public void UpdateAfterLaunchAndEdit(Project projectBeforeLaunch) { Id = projectBeforeLaunch.Id; Name = projectBeforeLaunch.Name; IsRevertEnabled = true; MoveExistingWindows = projectBeforeLaunch.MoveExistingWindows; foreach (Application app in Applications) { var sameAppBefore = projectBeforeLaunch.Applications.Where(x => x.Id.Equals(app.Id, StringComparison.OrdinalIgnoreCase)); if (sameAppBefore.Any()) { var appBefore = sameAppBefore.FirstOrDefault(); app.CommandLineArguments = appBefore.CommandLineArguments; app.IsElevated = appBefore.IsElevated; } } } internal void CloseExpanders() { foreach (Application app in Applications) { app.IsExpanded = false; } } internal MonitorSetup GetMonitorForApp(Application app) { MonitorSetup monitorSetup = Monitors.Where(x => x.MonitorNumber == app.MonitorNumber).FirstOrDefault(); if (monitorSetup == null) { // monitors changed: try to determine monitor id based on middle point int middleX = app.Position.X + (app.Position.Width / 2); int middleY = app.Position.Y + (app.Position.Height / 2); MonitorSetup monitorCandidate = Monitors.Where(x => (x.MonitorDpiUnawareBounds.Left < middleX) && (x.MonitorDpiUnawareBounds.Right > middleX) && (x.MonitorDpiUnawareBounds.Top < middleY) && (x.MonitorDpiUnawareBounds.Bottom > middleY)).FirstOrDefault(); if (monitorCandidate != null) { app.MonitorNumber = monitorCandidate.MonitorNumber; return monitorCandidate; } else { // monitors and even the app's area unknown, set the main monitor (which is closer to (0,0)) as the app's monitor monitorCandidate = Monitors.OrderBy(x => Math.Abs(x.MonitorDpiUnawareBounds.Left) + Math.Abs(x.MonitorDpiUnawareBounds.Top)).FirstOrDefault(); if (monitorCandidate != null) { app.MonitorNumber = monitorCandidate.MonitorNumber; return monitorCandidate; } else { // no monitors defined at all. Logger.LogError($"Wrong workspace setup. No monitors defined for the workspace: {Name}."); return null; } } } return monitorSetup; } } }