Editor IO exception handling (#1491)

* Close input stream
Show MessageBox with exception message
Remove unused arguments
Guard all of the Editor input/output code parts and show MessageBox
with appropriate message and issue reporting link

* Extract showing messageBox into method
This commit is contained in:
stefansjfw 2020-03-09 10:41:06 +01:00 committed by GitHub
parent 52e08a2784
commit 5581e25a21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 274 additions and 232 deletions

View file

@ -16,7 +16,7 @@ namespace FancyZonesEditor
EditorOverlay mainEditor = EditorOverlay.Current;
if (mainEditor.DataContext is LayoutModel model)
{
model.Persist(mainEditor.GetZoneRects());
model.Persist();
}
_choosing = true;

View file

@ -150,11 +150,11 @@ namespace FancyZonesEditor
{
if (model is GridLayoutModel)
{
model.Apply(mainEditor.GetZoneRects());
model.Apply();
}
else
{
model.Apply((model as CanvasLayoutModel).Zones.ToArray());
model.Apply();
}
Close();

View file

@ -117,46 +117,53 @@ namespace FancyZonesEditor.Models
// Implements the LayoutModel.PersistData abstract method
protected override void PersistData()
{
FileStream outputStream = File.Open(Settings.AppliedZoneSetTmpFile, FileMode.Create);
JsonWriterOptions writerOptions = new JsonWriterOptions
try
{
SkipValidation = true,
};
using (var writer = new Utf8JsonWriter(outputStream, writerOptions))
{
writer.WriteStartObject();
writer.WriteString("uuid", "{" + Guid.ToString().ToUpper() + "}");
writer.WriteString("name", Name);
writer.WriteString("type", "canvas");
writer.WriteStartObject("info");
writer.WriteNumber("ref-width", _referenceWidth);
writer.WriteNumber("ref-height", _referenceHeight);
writer.WriteStartArray("zones");
foreach (Int32Rect rect in Zones)
FileStream outputStream = File.Open(Settings.AppliedZoneSetTmpFile, FileMode.Create);
JsonWriterOptions writerOptions = new JsonWriterOptions
{
SkipValidation = true,
};
using (var writer = new Utf8JsonWriter(outputStream, writerOptions))
{
writer.WriteStartObject();
writer.WriteNumber("X", rect.X);
writer.WriteNumber("Y", rect.Y);
writer.WriteNumber("width", rect.Width);
writer.WriteNumber("height", rect.Height);
writer.WriteString("uuid", "{" + Guid.ToString().ToUpper() + "}");
writer.WriteString("name", Name);
writer.WriteString("type", "canvas");
writer.WriteStartObject("info");
writer.WriteNumber("ref-width", _referenceWidth);
writer.WriteNumber("ref-height", _referenceHeight);
writer.WriteStartArray("zones");
foreach (Int32Rect rect in Zones)
{
writer.WriteStartObject();
writer.WriteNumber("X", rect.X);
writer.WriteNumber("Y", rect.Y);
writer.WriteNumber("width", rect.Width);
writer.WriteNumber("height", rect.Height);
writer.WriteEndObject();
}
writer.WriteEndArray();
// end info object
writer.WriteEndObject();
// end root object
writer.WriteEndObject();
writer.Flush();
}
writer.WriteEndArray();
// end info object
writer.WriteEndObject();
// end root object
writer.WriteEndObject();
writer.Flush();
outputStream.Close();
}
catch (Exception ex)
{
ShowExceptionMessageBox("Error persisting canvas layout", ex);
}
outputStream.Close();
}
}
}

View file

@ -2,10 +2,11 @@
// 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.IO;
using System.Text;
using System.Text.Json;
using System.Windows;
namespace FancyZonesEditor.Models
{
@ -170,59 +171,66 @@ namespace FancyZonesEditor.Models
// Implements the LayoutModel.PersistData abstract method
protected override void PersistData()
{
FileStream outputStream = File.Open(Settings.AppliedZoneSetTmpFile, FileMode.Create);
using (var writer = new Utf8JsonWriter(outputStream, options: default))
try
{
writer.WriteStartObject();
writer.WriteString("uuid", "{" + Guid.ToString().ToUpper() + "}");
writer.WriteString("name", Name);
writer.WriteString("type", "grid");
writer.WriteStartObject("info");
writer.WriteNumber("rows", Rows);
writer.WriteNumber("columns", Columns);
writer.WriteStartArray("rows-percentage");
for (int row = 0; row < Rows; row++)
FileStream outputStream = File.Open(Settings.AppliedZoneSetTmpFile, FileMode.Create);
using (var writer = new Utf8JsonWriter(outputStream, options: default))
{
writer.WriteNumberValue(RowPercents[row]);
}
writer.WriteStartObject();
writer.WriteString("uuid", "{" + Guid.ToString().ToUpper() + "}");
writer.WriteString("name", Name);
writer.WriteEndArray();
writer.WriteString("type", "grid");
writer.WriteStartArray("columns-percentage");
for (int col = 0; col < Columns; col++)
{
writer.WriteNumberValue(ColumnPercents[col]);
}
writer.WriteStartObject("info");
writer.WriteEndArray();
writer.WriteNumber("rows", Rows);
writer.WriteNumber("columns", Columns);
writer.WriteStartArray("cell-child-map");
for (int row = 0; row < Rows; row++)
{
writer.WriteStartArray();
for (int col = 0; col < Columns; col++)
writer.WriteStartArray("rows-percentage");
for (int row = 0; row < Rows; row++)
{
writer.WriteNumberValue(CellChildMap[row, col]);
writer.WriteNumberValue(RowPercents[row]);
}
writer.WriteEndArray();
writer.WriteStartArray("columns-percentage");
for (int col = 0; col < Columns; col++)
{
writer.WriteNumberValue(ColumnPercents[col]);
}
writer.WriteEndArray();
writer.WriteStartArray("cell-child-map");
for (int row = 0; row < Rows; row++)
{
writer.WriteStartArray();
for (int col = 0; col < Columns; col++)
{
writer.WriteNumberValue(CellChildMap[row, col]);
}
writer.WriteEndArray();
}
writer.WriteEndArray();
// end info object
writer.WriteEndObject();
// end root object
writer.WriteEndObject();
writer.Flush();
}
writer.WriteEndArray();
// end info object
writer.WriteEndObject();
// end root object
writer.WriteEndObject();
writer.Flush();
outputStream.Close();
}
catch (Exception ex)
{
ShowExceptionMessageBox("Error persisting grid layout", ex);
}
outputStream.Close();
}
}
}

View file

@ -27,8 +27,12 @@ namespace FancyZonesEditor.Models
// Manages common properties and base persistence
public abstract class LayoutModel : INotifyPropertyChanged
{
private static readonly string _registryPath = Settings.RegistryPath + "\\Layouts";
private static readonly string _fullRegistryPath = Settings.FullRegistryPath + "\\Layouts";
public static void ShowExceptionMessageBox(string message, Exception ex)
{
string title = "FancyZones Editor Exception Handler";
string fullMessage = "Please report the bug to https://github.com/microsoft/PowerToys/issues \n" + message + ": " + ex.Message;
MessageBox.Show(fullMessage, title);
}
protected LayoutModel()
{
@ -133,19 +137,26 @@ namespace FancyZonesEditor.Models
public static void SerializeDeletedCustomZoneSets()
{
FileStream outputStream = File.Open(Settings.CustomZoneSetsTmpFile, FileMode.Create);
var writer = new Utf8JsonWriter(outputStream, options: default);
writer.WriteStartObject();
writer.WriteStartArray("deleted-custom-zone-sets");
foreach (string zoneSet in _deletedCustomModels)
try
{
writer.WriteStringValue(zoneSet);
}
FileStream outputStream = File.Open(Settings.CustomZoneSetsTmpFile, FileMode.Create);
var writer = new Utf8JsonWriter(outputStream, options: default);
writer.WriteStartObject();
writer.WriteStartArray("deleted-custom-zone-sets");
foreach (string zoneSet in _deletedCustomModels)
{
writer.WriteStringValue(zoneSet);
}
writer.WriteEndArray();
writer.WriteEndObject();
writer.Flush();
outputStream.Close();
writer.WriteEndArray();
writer.WriteEndObject();
writer.Flush();
outputStream.Close();
}
catch (Exception ex)
{
ShowExceptionMessageBox("Error serializing deleted layouts", ex);
}
}
// Loads all the custom Layouts from tmp file passed by FancuZonesLib
@ -153,79 +164,81 @@ namespace FancyZonesEditor.Models
{
_customModels = new ObservableCollection<LayoutModel>();
FileStream inputStream = File.Open(Settings.CustomZoneSetsTmpFile, FileMode.Open);
JsonDocument jsonObject;
try
{
jsonObject = JsonDocument.Parse(inputStream, options: default);
}
catch
{
return _customModels;
}
FileStream inputStream = File.Open(Settings.CustomZoneSetsTmpFile, FileMode.Open);
JsonDocument jsonObject = JsonDocument.Parse(inputStream, options: default);
JsonElement.ArrayEnumerator customZoneSetsEnumerator = jsonObject.RootElement.GetProperty("custom-zone-sets").EnumerateArray();
JsonElement.ArrayEnumerator customZoneSetsEnumerator = jsonObject.RootElement.GetProperty("custom-zone-sets").EnumerateArray();
while (customZoneSetsEnumerator.MoveNext())
{
var current = customZoneSetsEnumerator.Current;
string name = current.GetProperty("name").GetString();
string type = current.GetProperty("type").GetString();
string uuid = current.GetProperty("uuid").GetString();
var info = current.GetProperty("info");
if (type.Equals("grid"))
while (customZoneSetsEnumerator.MoveNext())
{
int rows = info.GetProperty("rows").GetInt32();
int columns = info.GetProperty("columns").GetInt32();
int[] rowsPercentage = new int[rows];
JsonElement.ArrayEnumerator rowsPercentageEnumerator = info.GetProperty("rows-percentage").EnumerateArray();
int i = 0;
while (rowsPercentageEnumerator.MoveNext())
var current = customZoneSetsEnumerator.Current;
string name = current.GetProperty("name").GetString();
string type = current.GetProperty("type").GetString();
string uuid = current.GetProperty("uuid").GetString();
var info = current.GetProperty("info");
if (type.Equals("grid"))
{
rowsPercentage[i++] = rowsPercentageEnumerator.Current.GetInt32();
}
i = 0;
int[] columnsPercentage = new int[columns];
JsonElement.ArrayEnumerator columnsPercentageEnumerator = info.GetProperty("columns-percentage").EnumerateArray();
while (columnsPercentageEnumerator.MoveNext())
{
columnsPercentage[i++] = columnsPercentageEnumerator.Current.GetInt32();
}
i = 0;
JsonElement.ArrayEnumerator cellChildMapRows = info.GetProperty("cell-child-map").EnumerateArray();
int[,] cellChildMap = new int[rows, columns];
while (cellChildMapRows.MoveNext())
{
int j = 0;
JsonElement.ArrayEnumerator cellChildMapRowElems = cellChildMapRows.Current.EnumerateArray();
while (cellChildMapRowElems.MoveNext())
int rows = info.GetProperty("rows").GetInt32();
int columns = info.GetProperty("columns").GetInt32();
int[] rowsPercentage = new int[rows];
JsonElement.ArrayEnumerator rowsPercentageEnumerator = info.GetProperty("rows-percentage").EnumerateArray();
int i = 0;
while (rowsPercentageEnumerator.MoveNext())
{
cellChildMap[i, j++] = cellChildMapRowElems.Current.GetInt32();
rowsPercentage[i++] = rowsPercentageEnumerator.Current.GetInt32();
}
i++;
}
i = 0;
int[] columnsPercentage = new int[columns];
JsonElement.ArrayEnumerator columnsPercentageEnumerator = info.GetProperty("columns-percentage").EnumerateArray();
while (columnsPercentageEnumerator.MoveNext())
{
columnsPercentage[i++] = columnsPercentageEnumerator.Current.GetInt32();
}
_customModels.Add(new GridLayoutModel(uuid, name, LayoutType.Custom, rows, columns, rowsPercentage, columnsPercentage, cellChildMap));
}
else if (type.Equals("canvas"))
{
int referenceWidth = info.GetProperty("ref-width").GetInt32();
int referenceHeight = info.GetProperty("ref-height").GetInt32();
JsonElement.ArrayEnumerator zonesEnumerator = info.GetProperty("zones").EnumerateArray();
IList<Int32Rect> zones = new List<Int32Rect>();
while (zonesEnumerator.MoveNext())
i = 0;
JsonElement.ArrayEnumerator cellChildMapRows = info.GetProperty("cell-child-map").EnumerateArray();
int[,] cellChildMap = new int[rows, columns];
while (cellChildMapRows.MoveNext())
{
int j = 0;
JsonElement.ArrayEnumerator cellChildMapRowElems = cellChildMapRows.Current.EnumerateArray();
while (cellChildMapRowElems.MoveNext())
{
cellChildMap[i, j++] = cellChildMapRowElems.Current.GetInt32();
}
i++;
}
_customModels.Add(new GridLayoutModel(uuid, name, LayoutType.Custom, rows, columns, rowsPercentage, columnsPercentage, cellChildMap));
}
else if (type.Equals("canvas"))
{
int x = zonesEnumerator.Current.GetProperty("X").GetInt32();
int y = zonesEnumerator.Current.GetProperty("Y").GetInt32();
int width = zonesEnumerator.Current.GetProperty("width").GetInt32();
int height = zonesEnumerator.Current.GetProperty("height").GetInt32();
zones.Add(new Int32Rect(x, y, width, height));
}
int referenceWidth = info.GetProperty("ref-width").GetInt32();
int referenceHeight = info.GetProperty("ref-height").GetInt32();
JsonElement.ArrayEnumerator zonesEnumerator = info.GetProperty("zones").EnumerateArray();
IList<Int32Rect> zones = new List<Int32Rect>();
while (zonesEnumerator.MoveNext())
{
int x = zonesEnumerator.Current.GetProperty("X").GetInt32();
int y = zonesEnumerator.Current.GetProperty("Y").GetInt32();
int width = zonesEnumerator.Current.GetProperty("width").GetInt32();
int height = zonesEnumerator.Current.GetProperty("height").GetInt32();
zones.Add(new Int32Rect(x, y, width, height));
}
_customModels.Add(new CanvasLayoutModel(uuid, name, LayoutType.Custom, referenceWidth, referenceHeight, zones));
_customModels.Add(new CanvasLayoutModel(uuid, name, LayoutType.Custom, referenceWidth, referenceHeight, zones));
}
}
inputStream.Close();
}
catch (Exception ex)
{
ShowExceptionMessageBox("Error loading custom layouts", ex);
return new ObservableCollection<LayoutModel>();
}
return _customModels;
@ -239,56 +252,62 @@ namespace FancyZonesEditor.Models
public abstract LayoutModel Clone();
public void Persist(System.Windows.Int32Rect[] zones)
public void Persist()
{
PersistData();
Apply(zones);
Apply();
}
public void Apply(System.Windows.Int32Rect[] zones)
public void Apply()
{
int zoneCount = zones.Length;
FileStream outputStream = File.Open(Settings.ActiveZoneSetTmpFile, FileMode.Create);
var writer = new Utf8JsonWriter(outputStream, options: default);
writer.WriteStartObject();
writer.WriteString("device-id", Settings.UniqueKey);
writer.WriteStartObject("active-zoneset");
writer.WriteString("uuid", "{" + Guid.ToString().ToUpper() + "}");
switch (Type)
try
{
case LayoutType.Focus:
writer.WriteString("type", "focus");
break;
case LayoutType.Rows:
writer.WriteString("type", "rows");
break;
case LayoutType.Columns:
writer.WriteString("type", "columns");
break;
case LayoutType.Grid:
writer.WriteString("type", "grid");
break;
case LayoutType.PriorityGrid:
writer.WriteString("type", "priority-grid");
break;
case LayoutType.Custom:
writer.WriteString("type", "custom");
break;
FileStream outputStream = File.Open(Settings.ActiveZoneSetTmpFile, FileMode.Create);
var writer = new Utf8JsonWriter(outputStream, options: default);
writer.WriteStartObject();
writer.WriteString("device-id", Settings.UniqueKey);
writer.WriteStartObject("active-zoneset");
writer.WriteString("uuid", "{" + Guid.ToString().ToUpper() + "}");
switch (Type)
{
case LayoutType.Focus:
writer.WriteString("type", "focus");
break;
case LayoutType.Rows:
writer.WriteString("type", "rows");
break;
case LayoutType.Columns:
writer.WriteString("type", "columns");
break;
case LayoutType.Grid:
writer.WriteString("type", "grid");
break;
case LayoutType.PriorityGrid:
writer.WriteString("type", "priority-grid");
break;
case LayoutType.Custom:
writer.WriteString("type", "custom");
break;
}
writer.WriteEndObject();
Settings settings = ((App)Application.Current).ZoneSettings;
writer.WriteBoolean("editor-show-spacing", settings.ShowSpacing);
writer.WriteNumber("editor-spacing", settings.Spacing);
writer.WriteNumber("editor-zone-count", settings.ZoneCount);
writer.WriteEndObject();
writer.Flush();
outputStream.Close();
}
catch (Exception ex)
{
ShowExceptionMessageBox("Error applying layout", ex);
}
writer.WriteEndObject();
Settings settings = ((App)Application.Current).ZoneSettings;
writer.WriteBoolean("editor-show-spacing", settings.ShowSpacing);
writer.WriteNumber("editor-spacing", settings.Spacing);
writer.WriteNumber("editor-zone-count", settings.ZoneCount);
writer.WriteEndObject();
writer.Flush();
outputStream.Close();
}
}
}

View file

@ -360,48 +360,56 @@ namespace FancyZonesEditor
private void ParseDeviceInfoData()
{
FileStream inputStream = File.Open(Settings.ActiveZoneSetTmpFile, FileMode.Open);
var jsonObject = JsonDocument.Parse(inputStream, options: default).RootElement;
UniqueKey = jsonObject.GetProperty("device-id").GetString();
ActiveZoneSetUUid = jsonObject.GetProperty("active-zoneset").GetProperty("uuid").GetString();
string layoutType = jsonObject.GetProperty("active-zoneset").GetProperty("type").GetString();
if (ActiveZoneSetUUid == "null" || layoutType == "blank")
try
{
// Default selection is Focus
ActiveZoneSetLayoutType = LayoutType.Focus;
_showSpacing = true;
_spacing = 16;
_zoneCount = 3;
}
else
{
switch (layoutType)
FileStream inputStream = File.Open(Settings.ActiveZoneSetTmpFile, FileMode.Open);
var jsonObject = JsonDocument.Parse(inputStream, options: default).RootElement;
UniqueKey = jsonObject.GetProperty("device-id").GetString();
ActiveZoneSetUUid = jsonObject.GetProperty("active-zoneset").GetProperty("uuid").GetString();
string layoutType = jsonObject.GetProperty("active-zoneset").GetProperty("type").GetString();
if (ActiveZoneSetUUid == "null" || layoutType == "blank")
{
case "focus":
ActiveZoneSetLayoutType = LayoutType.Focus;
break;
case "columns":
ActiveZoneSetLayoutType = LayoutType.Columns;
break;
case "rows":
ActiveZoneSetLayoutType = LayoutType.Rows;
break;
case "grid":
ActiveZoneSetLayoutType = LayoutType.Grid;
break;
case "priority-grid":
ActiveZoneSetLayoutType = LayoutType.PriorityGrid;
break;
case "custom":
ActiveZoneSetLayoutType = LayoutType.Custom;
break;
// Default selection is Focus
ActiveZoneSetLayoutType = LayoutType.Focus;
_showSpacing = true;
_spacing = 16;
_zoneCount = 3;
}
else
{
switch (layoutType)
{
case "focus":
ActiveZoneSetLayoutType = LayoutType.Focus;
break;
case "columns":
ActiveZoneSetLayoutType = LayoutType.Columns;
break;
case "rows":
ActiveZoneSetLayoutType = LayoutType.Rows;
break;
case "grid":
ActiveZoneSetLayoutType = LayoutType.Grid;
break;
case "priority-grid":
ActiveZoneSetLayoutType = LayoutType.PriorityGrid;
break;
case "custom":
ActiveZoneSetLayoutType = LayoutType.Custom;
break;
}
_showSpacing = jsonObject.GetProperty("editor-show-spacing").GetBoolean();
_spacing = jsonObject.GetProperty("editor-spacing").GetInt32();
_zoneCount = jsonObject.GetProperty("editor-zone-count").GetInt32();
}
_showSpacing = jsonObject.GetProperty("editor-show-spacing").GetBoolean();
_spacing = jsonObject.GetProperty("editor-spacing").GetInt32();
_zoneCount = jsonObject.GetProperty("editor-zone-count").GetInt32();
inputStream.Close();
} catch (Exception ex)
{
LayoutModel.ShowExceptionMessageBox("Error parsing device info data", ex);
}
}