ViewModelMain.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. using System.ComponentModel;
  2. using System.Linq;
  3. using System.Threading.Tasks;
  4. using Avalonia.Threading;
  5. using CommunityToolkit.Mvvm.Input;
  6. using Microsoft.Extensions.DependencyInjection;
  7. using Drawie.Backend.Core.ColorsImpl;
  8. using PixiEditor.Extensions.Common.Localization;
  9. using PixiEditor.Extensions.CommonApi.UserPreferences;
  10. using PixiEditor.Helpers;
  11. using PixiEditor.Helpers.Collections;
  12. using PixiEditor.Models.AnalyticsAPI;
  13. using PixiEditor.Models.Commands;
  14. using PixiEditor.Models.Config;
  15. using PixiEditor.Models.Controllers;
  16. using PixiEditor.Models.Dialogs;
  17. using PixiEditor.Models.DocumentModels;
  18. using PixiEditor.Models.Files;
  19. using PixiEditor.Models.Handlers;
  20. using PixiEditor.OperatingSystem;
  21. using PixiEditor.ViewModels.Document;
  22. using PixiEditor.ViewModels.Menu;
  23. using PixiEditor.ViewModels.SubViewModels;
  24. using PixiEditor.ViewModels.SubViewModels.AdditionalContent;
  25. using PixiEditor.ViewModels.Tools;
  26. using PixiEditor.Views.Dialogs;
  27. namespace PixiEditor.ViewModels;
  28. internal partial class ViewModelMain : ViewModelBase, ICommandsHandler
  29. {
  30. public static ViewModelMain Current { get; set; }
  31. public IServiceProvider Services { get; private set; }
  32. public Action CloseAction { get; set; }
  33. public event Action OnStartupEvent;
  34. public FileViewModel FileSubViewModel { get; set; }
  35. public UpdateViewModel UpdateSubViewModel { get; set; }
  36. public IToolsHandler ToolsSubViewModel { get; set; }
  37. public IoViewModel IoSubViewModel { get; set; }
  38. public LayersViewModel LayersSubViewModel { get; set; }
  39. public ClipboardViewModel ClipboardSubViewModel { get; set; }
  40. public UndoViewModel UndoSubViewModel { get; set; }
  41. public SelectionViewModel SelectionSubViewModel { get; set; }
  42. public ViewOptionsViewModel ViewportSubViewModel { get; set; }
  43. public ColorsViewModel ColorsSubViewModel { get; set; }
  44. public MiscViewModel MiscSubViewModel { get; set; }
  45. public DiscordViewModel DiscordViewModel { get; set; }
  46. public DebugViewModel DebugSubViewModel { get; set; }
  47. public DocumentManagerViewModel DocumentManagerSubViewModel { get; set; }
  48. public CommandController CommandController { get; set; }
  49. public ShortcutController ShortcutController { get; set; }
  50. public StylusViewModel StylusSubViewModel { get; set; }
  51. public WindowViewModel WindowSubViewModel { get; set; }
  52. public SearchViewModel SearchSubViewModel { get; set; }
  53. public RegistryViewModel RegistrySubViewModel { get; set; }
  54. public AdditionalContentViewModel AdditionalContentSubViewModel { get; set; }
  55. public ExtensionsViewModel ExtensionsSubViewModel { get; set; }
  56. public LayoutViewModel LayoutSubViewModel { get; set; }
  57. public MenuBarViewModel MenuBarViewModel { get; set; }
  58. public AnimationsViewModel AnimationsSubViewModel { get; set; }
  59. public NodeGraphManagerViewModel NodeGraphManager { get; set; }
  60. public AutosaveViewModel AutosaveViewModel { get; set; }
  61. public IPreferences Preferences { get; set; }
  62. public ILocalizationProvider LocalizationProvider { get; set; }
  63. public ConfigManager Config { get; set; }
  64. public LocalizedString ActiveActionDisplay
  65. {
  66. get
  67. {
  68. if (ActionDisplays.HasActive())
  69. {
  70. return ActionDisplays.GetActive();
  71. }
  72. var documentDisplay = DocumentManagerSubViewModel.ActiveDocument?.ActionDisplays;
  73. if (documentDisplay != null && documentDisplay.HasActive())
  74. {
  75. return documentDisplay.GetActive();
  76. }
  77. return ToolsSubViewModel.ActiveTool?.ActionDisplay ?? default;
  78. }
  79. }
  80. public ActionDisplayList ActionDisplays { get; }
  81. public bool UserWantsToClose { get; private set; }
  82. public Guid CurrentSessionId { get; } = Guid.NewGuid();
  83. public DateTime LaunchDateTime { get; } = DateTime.Now;
  84. public event Action<DocumentViewModel> BeforeDocumentClosed;
  85. public ViewModelMain()
  86. {
  87. Current = this;
  88. ActionDisplays = new ActionDisplayList(() => OnPropertyChanged(nameof(ActiveActionDisplay)));
  89. }
  90. public void Setup(IServiceProvider services)
  91. {
  92. Services = services;
  93. Config = new ConfigManager();
  94. Preferences = services.GetRequiredService<IPreferences>();
  95. Preferences.Init();
  96. SupportedFilesHelper.InitFileTypes(services.GetServices<IoFileType>());
  97. CommandController = services.GetService<CommandController>();
  98. LocalizationProvider = services.GetRequiredService<ILocalizationProvider>();
  99. string code = Preferences.GetPreference<string>("LanguageCode", null);
  100. LocalizationProvider.LoadData(code);
  101. WindowSubViewModel = services.GetService<WindowViewModel>();
  102. LayoutSubViewModel = services.GetService<LayoutViewModel>();
  103. DocumentManagerSubViewModel = services.GetRequiredService<DocumentManagerViewModel>();
  104. SelectionSubViewModel = services.GetService<SelectionViewModel>();
  105. FileSubViewModel = services.GetService<FileViewModel>();
  106. ToolsSubViewModel = services.GetService<IToolsHandler>();
  107. ToolsSubViewModel.SelectedToolChanged += ToolsSubViewModel_SelectedToolChanged;
  108. IoSubViewModel = services.GetService<IoViewModel>();
  109. LayersSubViewModel = services.GetService<LayersViewModel>();
  110. ClipboardSubViewModel = services.GetService<ClipboardViewModel>();
  111. UndoSubViewModel = services.GetService<UndoViewModel>();
  112. ViewportSubViewModel = services.GetService<ViewOptionsViewModel>();
  113. ColorsSubViewModel = services.GetService<ColorsViewModel>();
  114. ColorsSubViewModel?.SetupPaletteProviders(services);
  115. ToolSetsConfig toolSetConfig = Config.GetConfig<ToolSetsConfig>("ToolSetsConfig");
  116. ToolsSubViewModel?.SetupTools(services, toolSetConfig);
  117. DiscordViewModel = services.GetService<DiscordViewModel>();
  118. UpdateSubViewModel = services.GetService<UpdateViewModel>();
  119. DebugSubViewModel = services.GetService<DebugViewModel>();
  120. StylusSubViewModel = services.GetService<StylusViewModel>();
  121. RegistrySubViewModel = services.GetService<RegistryViewModel>();
  122. AdditionalContentSubViewModel = services.GetService<AdditionalContentViewModel>();
  123. MenuBarViewModel = new MenuBarViewModel(AdditionalContentSubViewModel);
  124. CommandController.Init(services);
  125. LayoutSubViewModel.LayoutManager.InitLayout(this);
  126. MenuBarViewModel.Init(services, CommandController);
  127. MiscSubViewModel = services.GetService<MiscViewModel>();
  128. ShortcutController = new ShortcutController();
  129. ToolsSubViewModel?.SetupToolsTooltipShortcuts();
  130. SearchSubViewModel = services.GetService<SearchViewModel>();
  131. AnimationsSubViewModel = services.GetService<AnimationsViewModel>();
  132. NodeGraphManager = services.GetService<NodeGraphManagerViewModel>();
  133. AutosaveViewModel = services.GetService<AutosaveViewModel>();
  134. ExtensionsSubViewModel = services.GetService<ExtensionsViewModel>(); // Must be last
  135. DocumentManagerSubViewModel.ActiveDocumentChanged += OnActiveDocumentChanged;
  136. BeforeDocumentClosed += OnBeforeDocumentClosed;
  137. }
  138. public bool DocumentIsNotNull(object property)
  139. {
  140. return DocumentManagerSubViewModel.ActiveDocument is not null;
  141. }
  142. public bool DocumentIsNotNull((Color oldColor, Color newColor) obj)
  143. {
  144. return DocumentIsNotNull(null);
  145. }
  146. [RelayCommand]
  147. public async Task CloseWindow()
  148. {
  149. UserWantsToClose = await DisposeAllDocumentsWithSaveConfirmation();
  150. if (UserWantsToClose)
  151. {
  152. var analytics = Services.GetService<AnalyticsPeriodicReporter>();
  153. if (analytics != null)
  154. {
  155. await analytics.StopAsync();
  156. }
  157. }
  158. }
  159. private void ToolsSubViewModel_SelectedToolChanged(object sender, SelectedToolEventArgs e)
  160. {
  161. if (e.OldTool != null)
  162. ((ToolViewModel)e.OldTool).PropertyChanged -= SelectedTool_PropertyChanged;
  163. ((ToolViewModel)e.NewTool).PropertyChanged += SelectedTool_PropertyChanged;
  164. NotifyToolActionDisplayChanged();
  165. }
  166. private void SelectedTool_PropertyChanged(object sender, PropertyChangedEventArgs e)
  167. {
  168. if (e.PropertyName == nameof(ToolViewModel.ActionDisplay))
  169. {
  170. NotifyToolActionDisplayChanged();
  171. }
  172. }
  173. public void NotifyToolActionDisplayChanged()
  174. {
  175. if (!ActionDisplays.Any()) OnPropertyChanged(nameof(ActiveActionDisplay));
  176. }
  177. /// <summary>
  178. /// Closes documents with unsaved changes confirmation dialog.
  179. /// </summary>
  180. /// <returns>If documents was removed successfully.</returns>
  181. private async Task<bool> DisposeAllDocumentsWithSaveConfirmation()
  182. {
  183. int docCount = DocumentManagerSubViewModel.Documents.Count;
  184. for (int i = 0; i < docCount; i++)
  185. {
  186. WindowSubViewModel.MakeDocumentViewportActive(DocumentManagerSubViewModel.Documents.First());
  187. bool canceled = !await DisposeActiveDocumentWithSaveConfirmation();
  188. if (canceled)
  189. {
  190. return false;
  191. }
  192. }
  193. return true;
  194. }
  195. private void OnBeforeDocumentClosed(DocumentViewModel document)
  196. {
  197. if (!AutosaveViewModel.SaveSessionStateEnabled || DebugSubViewModel.ModifiedEditorData)
  198. return;
  199. document.AutosaveViewModel.AutosaveOnClose();
  200. }
  201. /// <summary>
  202. /// Disposes the active document after showing the unsaved changes confirmation dialog.
  203. /// </summary>
  204. /// <returns>If the document was closed successfully.</returns>
  205. public async Task<bool> DisposeActiveDocumentWithSaveConfirmation()
  206. {
  207. if (DocumentManagerSubViewModel.ActiveDocument is null)
  208. return false;
  209. return await DisposeDocumentWithSaveConfirmation(DocumentManagerSubViewModel.ActiveDocument);
  210. }
  211. public async Task<bool> DisposeDocumentWithSaveConfirmation(DocumentViewModel document)
  212. {
  213. const string ConfirmationDialogTitle = "UNSAVED_CHANGES";
  214. const string ConfirmationDialogMessage = "DOCUMENT_MODIFIED_SAVE";
  215. ConfirmationType result = ConfirmationType.No;
  216. bool saved = false;
  217. if (!document.AllChangesSaved)
  218. {
  219. result = await ConfirmationDialog.Show(ConfirmationDialogMessage, ConfirmationDialogTitle);
  220. if (result == ConfirmationType.Yes)
  221. {
  222. if (!await FileSubViewModel.SaveDocument(document, false))
  223. return false;
  224. saved = true;
  225. }
  226. }
  227. if (result != ConfirmationType.Canceled)
  228. {
  229. BeforeDocumentClosed?.Invoke(document);
  230. if (!DocumentManagerSubViewModel.Documents.Remove(document))
  231. throw new InvalidOperationException(
  232. "Trying to close a document that's not in the documents collection. Likely, the document wasn't added there after creation by mistake.");
  233. if (DocumentManagerSubViewModel.ActiveDocument == document)
  234. {
  235. if (DocumentManagerSubViewModel.Documents.Count > 0)
  236. WindowSubViewModel.MakeDocumentViewportActive(DocumentManagerSubViewModel.Documents.Last());
  237. else
  238. WindowSubViewModel.MakeDocumentViewportActive(null);
  239. }
  240. WindowSubViewModel.CloseViewportsForDocument(document);
  241. document.Dispose();
  242. return true;
  243. }
  244. return false;
  245. }
  246. public void OnStartup()
  247. {
  248. OnStartupEvent?.Invoke();
  249. }
  250. private void OnActiveDocumentChanged(object sender, DocumentChangedEventArgs e)
  251. {
  252. NotifyToolActionDisplayChanged();
  253. if (e.OldDocument is not null)
  254. e.OldDocument.SizeChanged -= ActiveDocument_DocumentSizeChanged;
  255. if (e.NewDocument is not null)
  256. e.NewDocument.SizeChanged += ActiveDocument_DocumentSizeChanged;
  257. }
  258. private void ActiveDocument_DocumentSizeChanged(object sender, DocumentSizeChangedEventArgs e)
  259. {
  260. foreach (var viewport in WindowSubViewModel.Viewports.Where(viewport => viewport.Document == e.Document))
  261. {
  262. viewport.CenterViewportTrigger.Execute(this, e.NewSize);
  263. }
  264. }
  265. }