Browse Source

No idea what I was doing since I haven't touched this branch in a long time

CPKreuz 3 years ago
parent
commit
f350f8c26e

+ 2 - 1
PixiEditor/App.xaml

@@ -1,7 +1,8 @@
 <Application x:Class="PixiEditor.App"
 <Application x:Class="PixiEditor.App"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             StartupUri="Views/MainWindow.xaml">
+             >
+    <!--StartupUri="Views/MainWindow.xaml"-->
     <Application.Resources>
     <Application.Resources>
         <ResourceDictionary>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
             <ResourceDictionary.MergedDictionaries>

+ 36 - 1
PixiEditor/App.xaml.cs

@@ -1,7 +1,12 @@
-using PixiEditor.Models.Dialogs;
+using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels;
 using PixiEditor.ViewModels;
+using PixiEditor.Views.Dialogs;
+using System;
+using System.Diagnostics;
 using System.Linq;
 using System.Linq;
+using System.Text.RegularExpressions;
 using System.Windows;
 using System.Windows;
 
 
 namespace PixiEditor
 namespace PixiEditor
@@ -11,6 +16,23 @@ namespace PixiEditor
     /// </summary>
     /// </summary>
     public partial class App : Application
     public partial class App : Application
     {
     {
+        protected override void OnStartup(StartupEventArgs e)
+        {
+            string arguments = string.Join(' ', e.Args);
+
+            if (ParseArgument("--crash (\"?)([A-z0-9:\\/\\ -_.]+)\\1", arguments, out Group[] groups))
+            {
+                CrashReport report = CrashReport.Parse(groups[2].Value);
+                MainWindow = new CrashReportDialog(report);
+            }
+            else
+            {
+                MainWindow = new MainWindow();
+            }
+
+            MainWindow.Show();
+        }
+
         protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
         protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
         {
         {
             base.OnSessionEnding(e);
             base.OnSessionEnding(e);
@@ -21,5 +43,18 @@ namespace PixiEditor
                 e.Cancel = confirmation != ConfirmationType.Yes;
                 e.Cancel = confirmation != ConfirmationType.Yes;
             }
             }
         }
         }
+
+        private bool ParseArgument(string pattern, string args, out Group[] groups)
+        {
+            Match match = Regex.Match(args, pattern, RegexOptions.IgnoreCase);
+            groups = null;
+
+            if (match.Success)
+            {
+                groups = match.Groups.Values.ToArray();
+            }
+
+            return match.Success;
+        }
     }
     }
 }
 }

+ 7 - 86
PixiEditor/Helpers/CrashHelper.cs

@@ -15,66 +15,12 @@ namespace PixiEditor.Helpers
     {
     {
         public static void SaveCrashInfo(Exception exception)
         public static void SaveCrashInfo(Exception exception)
         {
         {
-            StringBuilder builder = new();
-            DateTime currentTime = DateTime.Now;
-
-            builder
-                .AppendLine($"PixiEditor crashed on {currentTime:yyyy.MM.dd} at {currentTime:HH:mm:ss}\n")
-                .AppendLine("-----System Information----")
-                .AppendLine("General:")
-                .AppendLine($"  OS: {Environment.OSVersion.VersionString}")
-                .AppendLine();
-
-            try
-            {
-                GetCPUInformation(builder);
-            }
-            catch (Exception cpuE)
-            {
-                builder.AppendLine($"Error ({cpuE.GetType().FullName}: {cpuE.Message}) while gathering CPU information, skipping...");
-            }
-
-            try
-            {
-                GetGPUInformation(builder);
-            }
-            catch (Exception gpuE)
-            {
-                builder.AppendLine($"Error ({gpuE.GetType().FullName}: {gpuE.Message}) while gathering GPU information, skipping...");
-            }
-
-            try
-            {
-                GetMemoryInformation(builder);
-            }
-            catch (Exception memE)
-            {
-                builder.AppendLine($"Error ({memE.GetType().FullName}: {memE.Message}) while gathering memory information, skipping...");
-            }
-
-            AddExceptionMessage(builder, exception);
-
-            string filename = $"crash-{currentTime:yyyy-MM-dd_HH-mm-ss_fff}.zip";
-            string path = Path.Combine(
-                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
-                "PixiEditor",
-                "crash_logs");
-            Directory.CreateDirectory(path);
-
-            string filePath = Path.Combine(path, filename);
-            string report = builder.ToString();
-
-            try
-            {
-                CreateZip(filePath, report);
-            }
-            catch
-            {
-                File.WriteAllText(Path.ChangeExtension(filePath, ".txt"), report);
-            }
+            CrashReport report = CrashReport.Generate(exception);
+            report.TrySave();
+            report.RestartToCrashReport();
         }
         }
 
 
-        private static void GetCPUInformation(StringBuilder builder)
+        public static void GetCPUInformation(StringBuilder builder)
         {
         {
             builder.AppendLine("CPU:");
             builder.AppendLine("CPU:");
 
 
@@ -89,7 +35,7 @@ namespace PixiEditor.Helpers
             }
             }
         }
         }
 
 
-        private static void GetGPUInformation(StringBuilder builder)
+        public static void GetGPUInformation(StringBuilder builder)
         {
         {
             builder.AppendLine("\nGPU:");
             builder.AppendLine("\nGPU:");
 
 
@@ -104,7 +50,7 @@ namespace PixiEditor.Helpers
             }
             }
         }
         }
 
 
-        private static void GetMemoryInformation(StringBuilder builder)
+        public static void GetMemoryInformation(StringBuilder builder)
         {
         {
             builder.AppendLine("\nMemory:");
             builder.AppendLine("\nMemory:");
 
 
@@ -121,7 +67,7 @@ namespace PixiEditor.Helpers
             }
             }
         }
         }
 
 
-        private static void AddExceptionMessage(StringBuilder builder, Exception e)
+        public static void AddExceptionMessage(StringBuilder builder, Exception e)
         {
         {
 
 
             builder
             builder
@@ -157,31 +103,6 @@ namespace PixiEditor.Helpers
             }
             }
         }
         }
 
 
-        private static void CreateZip(string filePath, string report)
-        {
-            using FileStream zipStream = new(/*Path.Combine(path, filename)*/filePath, FileMode.Create, FileAccess.Write);
-            using ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create);
-
-            using (Stream reportStream = archive.CreateEntry("report.txt").Open())
-            {
-                reportStream.Write(Encoding.UTF8.GetBytes(report));
-            }
-
-            foreach (Document document in ViewModelMain.Current.BitmapManager.Documents)
-            {
-                try
-                {
-                    string documentPath =
-                        $"{(string.IsNullOrWhiteSpace(document.DocumentFilePath) ? "Unsaved" : Path.GetFileNameWithoutExtension(document.DocumentFilePath))}-{document.OpenedUTC}.pixi";
-                    using Stream documentStream = archive.CreateEntry($"Documents/{documentPath}").Open();
-
-                    PixiParser.Serialize(document.ToSerializable(), documentStream);
-                }
-                catch
-                { }
-            }
-        }
-
         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
         private struct MemoryStatus
         private struct MemoryStatus
         {
         {

+ 1 - 0
PixiEditor/Helpers/RelayCommand.cs

@@ -3,6 +3,7 @@ using System.Windows.Input;
 
 
 namespace PixiEditor.Helpers
 namespace PixiEditor.Helpers
 {
 {
+    [Obsolete("Use GalaSoft.MvvmLight.CommandWpf.RelayCommand instead")]
     public class RelayCommand : ICommand
     public class RelayCommand : ICommand
     {
     {
         private readonly Action<object> execute;
         private readonly Action<object> execute;

+ 190 - 0
PixiEditor/Models/DataHolders/CrashReport.cs

@@ -0,0 +1,190 @@
+using PixiEditor.Helpers;
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Parser;
+using PixiEditor.ViewModels;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace PixiEditor.Models.DataHolders
+{
+    public class CrashReport : IDisposable
+    {
+        public static CrashReport Generate(Exception exception)
+        {
+            StringBuilder builder = new();
+            DateTime currentTime = DateTime.Now;
+
+            builder
+                .AppendLine($"PixiEditor crashed on {currentTime:yyyy.MM.dd} at {currentTime:HH:mm:ss}\n")
+                .AppendLine("-----System Information----")
+                .AppendLine("General:")
+                .AppendLine($"  OS: {Environment.OSVersion.VersionString}")
+                .AppendLine();
+
+            try
+            {
+                CrashHelper.GetCPUInformation(builder);
+            }
+            catch (Exception cpuE)
+            {
+                builder.AppendLine($"Error ({cpuE.GetType().FullName}: {cpuE.Message}) while gathering CPU information, skipping...");
+            }
+
+            try
+            {
+                CrashHelper.GetGPUInformation(builder);
+            }
+            catch (Exception gpuE)
+            {
+                builder.AppendLine($"Error ({gpuE.GetType().FullName}: {gpuE.Message}) while gathering GPU information, skipping...");
+            }
+
+            try
+            {
+                CrashHelper.GetMemoryInformation(builder);
+            }
+            catch (Exception memE)
+            {
+                builder.AppendLine($"Error ({memE.GetType().FullName}: {memE.Message}) while gathering memory information, skipping...");
+            }
+
+            CrashHelper.AddExceptionMessage(builder, exception);
+
+            string filename = $"crash-{currentTime:yyyy-MM-dd_HH-mm-ss_fff}.zip";
+            string path = Path.Combine(
+                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+                "PixiEditor",
+                "crash_logs");
+            Directory.CreateDirectory(path);
+
+            CrashReport report = new();
+            report.FilePath = Path.Combine(path, filename);
+            report.ReportText = builder.ToString();
+
+            return report;
+        }
+
+        public static CrashReport Parse(string path)
+        {
+            CrashReport report = new();
+            report.FilePath = path;
+
+            report.ZipFile = System.IO.Compression.ZipFile.Open(path, ZipArchiveMode.Read);
+            report.ExtractReport();
+
+            return report;
+        }
+
+        public string FilePath { get; set; }
+
+        public string ReportText { get; set; }
+
+        private ZipArchive ZipFile { get; set; }
+
+        public int GetDocumentCount() => ZipFile.Entries.Where(x => x.FullName.EndsWith(".pixi")).Count();
+
+        public IEnumerable<Document> RecoverDocuments()
+        {
+            foreach (ZipArchiveEntry entry in ZipFile.Entries.Where(x => x.FullName.EndsWith(".pixi")))
+            {
+                using Stream stream = entry.Open();
+
+                Document document;
+
+                try
+                {
+                    document = PixiParser.Deserialize(stream).ToDocument();
+                    document.ChangesSaved = false;
+                }
+                catch
+                {
+                    continue;
+                }
+
+                yield return document;
+            }
+        }
+
+        public void Dispose()
+        {
+            ZipFile.Dispose();
+        }
+
+        public void RestartToCrashReport()
+        {
+            Process process = new();
+
+            process.StartInfo = new()
+            {
+                FileName = Path.ChangeExtension(Assembly.GetExecutingAssembly().Location, "exe"),
+                Arguments = $"--crash \"{Path.GetFullPath(FilePath)}\""
+            };
+
+            process.Start();
+        }
+
+        public bool TrySave()
+        {
+            try
+            {
+                Save();
+                return true;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
+        public void Save()
+        {
+            using FileStream zipStream = new(FilePath, FileMode.Create, FileAccess.Write);
+            using ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create);
+
+            using (Stream reportStream = archive.CreateEntry("report.txt").Open())
+            {
+                reportStream.Write(Encoding.UTF8.GetBytes(ReportText));
+            }
+
+            foreach (Document document in ViewModelMain.Current.BitmapManager.Documents)
+            {
+                try
+                {
+                    string documentPath =
+                        $"{(string.IsNullOrWhiteSpace(document.DocumentFilePath) ? "Unsaved" : Path.GetFileNameWithoutExtension(document.DocumentFilePath))}-{document.OpenedUTC}.pixi";
+
+                    byte[] serialized = PixiParser.Serialize(document.ToSerializable());
+
+                    using Stream documentStream = archive.CreateEntry($"Documents/{documentPath}").Open();
+                    documentStream.Write(serialized);
+                }
+                catch
+                { }
+            }
+        }
+
+        private void ExtractReport()
+        {
+            ZipArchiveEntry entry = ZipFile.GetEntry("report.txt");
+            using Stream stream = entry.Open();
+
+            byte[] encodedReport = new byte[entry.Length];
+            stream.Read(encodedReport);
+
+            ReportText = Encoding.UTF8.GetString(encodedReport);
+        }
+
+        public class CrashReportUserMessage
+        {
+            public string Message { get; set; }
+
+            public string Mail { get; set; }
+        }
+    }
+}

+ 55 - 0
PixiEditor/ViewModels/CrashReportViewModel.cs

@@ -0,0 +1,55 @@
+using GalaSoft.MvvmLight.CommandWpf;
+using PixiEditor.Models.DataHolders;
+using System.Diagnostics;
+using System.Windows;
+
+namespace PixiEditor.ViewModels
+{
+    public class CrashReportViewModel : ViewModelBase
+    {
+        public CrashReport CrashReport { get; }
+
+        public string ReportText { get; }
+
+        public int DocumentCount { get; }
+
+        public RelayCommand RecoverDocumentsCommand { get; }
+
+        public RelayCommand AttachDebuggerCommand { get; }
+
+        public bool IsDebugBuild { get; set; }
+
+        public CrashReportViewModel(CrashReport report)
+        {
+            SetIsDebug();
+
+            CrashReport = report;
+            ReportText = report.ReportText;
+            DocumentCount = report.GetDocumentCount();
+            RecoverDocumentsCommand = new(RecoverDocuments);
+            AttachDebuggerCommand = new(AttachDebugger);
+        }
+
+        public void RecoverDocuments()
+        {
+            MainWindow window = MainWindow.CreateWithDocuments(CrashReport.RecoverDocuments());
+
+            Application.Current.MainWindow = window;
+            window.Show();
+        }
+
+        [Conditional("DEBUG")]
+        private void SetIsDebug()
+        {
+            IsDebugBuild = true;
+        }
+
+        private void AttachDebugger()
+        {
+            if (!Debugger.Launch())
+            {
+                MessageBox.Show("Starting debugger failed", "Starting debugger failed", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+    }
+}

+ 5 - 11
PixiEditor/ViewModels/SubViewModels/Main/WindowViewModel.cs

@@ -1,5 +1,5 @@
 using AvalonDock.Layout;
 using AvalonDock.Layout;
-using PixiEditor.Helpers;
+using GalaSoft.MvvmLight.CommandWpf;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 
 
@@ -7,9 +7,7 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
 {
 {
     public class WindowViewModel : SubViewModel<ViewModelMain>, ISettableOwner<ViewModelMain>
     public class WindowViewModel : SubViewModel<ViewModelMain>, ISettableOwner<ViewModelMain>
     {
     {
-        public MainWindow MainWindow { get; private set; }
-
-        public RelayCommand ShowAvalonDockWindowCommand { get; set; }
+        public RelayCommand<string> ShowAvalonDockWindowCommand { get; set; }
 
 
         public WindowViewModel()
         public WindowViewModel()
             : this(null)
             : this(null)
@@ -19,9 +17,7 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
         public WindowViewModel(ViewModelMain owner)
         public WindowViewModel(ViewModelMain owner)
             : base(owner)
             : base(owner)
         {
         {
-            ShowAvalonDockWindowCommand = new RelayCommand(ShowAvalonDockWindow);
-
-            MainWindow = (MainWindow)System.Windows.Application.Current?.MainWindow;
+            ShowAvalonDockWindowCommand = new(ShowAvalonDockWindow);
         }
         }
 
 
         public void SetOwner(ViewModelMain owner)
         public void SetOwner(ViewModelMain owner)
@@ -29,11 +25,9 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
             Owner = owner;
             Owner = owner;
         }
         }
 
 
-        private void ShowAvalonDockWindow(object parameter)
+        private void ShowAvalonDockWindow(string id)
         {
         {
-            string id = (string)parameter;
-
-            var anchorables = new List<LayoutAnchorable>(MainWindow.LayoutRoot.Manager.Layout
+            var anchorables = new List<LayoutAnchorable>(MainWindow.Current.LayoutRoot.Manager.Layout
                     .Descendents()
                     .Descendents()
                     .OfType<LayoutAnchorable>());
                     .OfType<LayoutAnchorable>());
 
 

+ 65 - 0
PixiEditor/Views/Dialogs/CrashReportDialog.xaml

@@ -0,0 +1,65 @@
+<Window x:Class="PixiEditor.Views.Dialogs.CrashReportDialog"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:vm="clr-namespace:PixiEditor.ViewModels"
+        xmlns:local="clr-namespace:PixiEditor.Views.Dialogs"
+        d:DataContext="{d:DesignInstance vm:CrashReportViewModel}"
+        mc:Ignorable="d" Background="{StaticResource AccentColor}"
+        Title="Oh no!" WindowStyle="None"
+        MinWidth="400" MinHeight="250"
+        Width="500" Height="300">
+
+    <Window.Resources>
+        <Style TargetType="TextBlock">
+            <Setter Property="Foreground" Value="White"/>
+            <Setter Property="FontSize" Value="16"/>
+        </Style>
+
+    </Window.Resources>
+
+    <WindowChrome.WindowChrome>
+        <WindowChrome CaptionHeight="35"  GlassFrameThickness="0.1"
+                      ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}"/>
+    </WindowChrome.WindowChrome>
+
+    <Window.CommandBindings>
+        <CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_CanExecute"
+                        Executed="CommandBinding_Executed_Close" />
+    </Window.CommandBindings>
+
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="50"/>
+            <RowDefinition/>
+        </Grid.RowDefinitions>
+        <DockPanel Grid.Row="0" Background="{StaticResource MainColor}">
+            <Button DockPanel.Dock="Right" HorizontalAlignment="Right" Style="{StaticResource CloseButtonStyle}"
+                    WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="Close"
+                    Command="{x:Static SystemCommands.CloseWindowCommand}" />
+        </DockPanel>
+        <StackPanel Grid.Row="1" Margin="5">
+
+            <TextBlock>PixiEditor has crashed!</TextBlock>
+            <TextBlock Text="{Binding DocumentCount, StringFormat={}{0} file(s) can be recovered}"
+                   d:Text="2 file(s) can be recovered"/>
+            <TextBlock TextWrapping="Wrap">You can help the developers fixing this bug by sending a crash report that was generated</TextBlock>
+
+            <Grid Margin="0,20,0,5">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition/>
+                    <ColumnDefinition/>
+                </Grid.ColumnDefinitions>
+                <Button Margin="0,0,5,0"
+                        Style="{StaticResource DarkRoundButton}">Send report</Button>
+                <Button Grid.Column="1" Margin="5,0,0,0"
+                        Command="{Binding RecoverDocumentsCommand}"
+                        Style="{StaticResource DarkRoundButton}">Recover files</Button>
+            </Grid>
+            <Button Visibility="{Binding IsDebugBuild, Converter={BoolToVisibilityConverter}}"
+                    Style="{StaticResource DarkRoundButton}"
+                    Command="{Binding AttachDebuggerCommand}">(Re)Attach debugger</Button>
+        </StackPanel>
+    </Grid>
+</Window>

+ 18 - 0
PixiEditor/Views/Dialogs/CrashReportDialog.xaml.cs

@@ -0,0 +1,18 @@
+using PixiEditor.Models.DataHolders;
+using PixiEditor.ViewModels;
+using System.Windows;
+
+namespace PixiEditor.Views.Dialogs
+{
+    /// <summary>
+    /// Interaction logic for CrashReportDialog.xaml
+    /// </summary>
+    public partial class CrashReportDialog : Window
+    {
+        public CrashReportDialog(CrashReport report)
+        {
+            DataContext = new CrashReportViewModel(report);
+            InitializeComponent();
+        }
+    }
+}

+ 44 - 0
PixiEditor/Views/Dialogs/SendCrashReportWindow.xaml

@@ -0,0 +1,44 @@
+<Window x:Class="PixiEditor.Views.Dialogs.SendCrashReportWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:PixiEditor.Views.Dialogs"
+        mc:Ignorable="d" Background="{StaticResource AccentColor}"
+        Title="SendCrashReportWindow" Height="450" Width="800">
+    <Grid Margin="5">
+        <Grid.RowDefinitions>
+            <RowDefinition/>
+            <RowDefinition/>
+            <RowDefinition Height="30"/>
+        </Grid.RowDefinitions>
+        <Grid>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto"/>
+                <RowDefinition Height="Auto"/>
+                <RowDefinition/>
+            </Grid.RowDefinitions>
+            <Grid>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="Auto"/>
+                    <ColumnDefinition/>
+                </Grid.ColumnDefinitions>
+                <TextBlock Text="E-Mail:" ToolTip="In case we could use more information from you"/>
+                <TextBox Grid.Column="1" />
+            </Grid>
+            <TextBlock ToolTip="You can use this box to send us additional information"
+                       Grid.Row="1">Additional Information</TextBlock>
+            <TextBox Grid.Row="2"/>
+        </Grid>
+        <ScrollViewer Grid.Row="1" Margin="50,0">
+            <StackPanel>
+                <StackPanel>
+                    <TextBlock>Documents</TextBlock>
+                    <TextBlock>report.txt</TextBlock>
+                </StackPanel>
+                <Grid Height="5" Background="{StaticResource BrighterAccentColor}"/>
+            </StackPanel>
+        </ScrollViewer>
+        <Button Grid.Row="2" Width="250" Style="{StaticResource AccentDarkRoundButton}">Send</Button>
+    </Grid>
+</Window>

+ 27 - 0
PixiEditor/Views/Dialogs/SendCrashReportWindow.xaml.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace PixiEditor.Views.Dialogs
+{
+    /// <summary>
+    /// Interaction logic for SendCrashReportWindow.xaml
+    /// </summary>
+    public partial class SendCrashReportWindow : Window
+    {
+        public SendCrashReportWindow()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 13 - 0
PixiEditor/Views/MainWindow.xaml.cs

@@ -24,6 +24,8 @@ namespace PixiEditor
 
 
         private readonly IPreferences preferences;
         private readonly IPreferences preferences;
 
 
+        public static MainWindow Current { get; private set; }
+
         public new ViewModelMain DataContext { get => (ViewModelMain)base.DataContext; set => base.DataContext = value; }
         public new ViewModelMain DataContext { get => (ViewModelMain)base.DataContext; set => base.DataContext = value; }
 
 
         public MainWindow()
         public MainWindow()
@@ -63,6 +65,17 @@ namespace PixiEditor
             OnReleaseBuild();
             OnReleaseBuild();
         }
         }
 
 
+        public static MainWindow CreateWithDocuments(IEnumerable<Document> documents)
+        {
+            MainWindow window = new();
+
+            BitmapManager bitmapManager = window.DataContext.BitmapManager;
+            bitmapManager.Documents.AddRange(documents);
+            bitmapManager.ActiveDocument = bitmapManager.Documents.FirstOrDefault();
+
+            return window;
+        }
+
         protected override void OnClosing(CancelEventArgs e)
         protected override void OnClosing(CancelEventArgs e)
         {
         {
             DataContext.CloseWindow(e);
             DataContext.CloseWindow(e);