Update layout management system to use JSON

This commit is contained in:
Anton Kasyanov
2016-06-05 01:34:44 +03:00
parent a30834db6c
commit 4949c17065
11 changed files with 162 additions and 352 deletions

View File

@@ -2,9 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Threading;
using System.Xml.Linq;
using EveOPreview.Configuration;
namespace EveOPreview.UI
@@ -18,6 +16,7 @@ namespace EveOPreview.UI
#region Private fields
private readonly IApplicationConfiguration _configuration;
private readonly IConfigurationStorage _configurationStorage;
private readonly DispatcherTimer _thumbnailUpdateTimer;
private readonly IThumbnailViewFactory _thumbnailViewFactory;
private readonly Dictionary<IntPtr, IThumbnailView> _thumbnailViews;
@@ -29,20 +28,12 @@ namespace EveOPreview.UI
private bool _isHoverEffectActive;
private Size _thumbnailBaseSize;
private Point _thumbnailBaseLocation;
// TODO To be moved into a separate class
private readonly Dictionary<string, Dictionary<string, Point>> _uniqueLayouts;
private readonly Dictionary<string, Point> _flatLayout;
private readonly Dictionary<string, string> _flatLayoutShortcuts;
private readonly Dictionary<string, WindowProperties> _clientLayout;
// TODO To be removed
private readonly Dictionary<string, string> _xmlBadToOkChars;
#endregion
public ThumbnailManager(IApplicationConfiguration configuration, IThumbnailViewFactory factory)
public ThumbnailManager(IApplicationConfiguration configuration, IConfigurationStorage configurationStorage, IThumbnailViewFactory factory)
{
this._configuration = configuration;
this._configurationStorage = configurationStorage;
this._thumbnailViewFactory = factory;
this._activeClientHandle = (IntPtr)0;
@@ -56,23 +47,7 @@ namespace EveOPreview.UI
// DispatcherTimer setup
this._thumbnailUpdateTimer = new DispatcherTimer();
this._thumbnailUpdateTimer.Tick += ThumbnailUpdateTimerTick;
this._thumbnailUpdateTimer.Interval = new TimeSpan(0, 0, 0, 0, 500); // TODO Make it configurable
// TODO Move mayouts stuff out
_uniqueLayouts = new Dictionary<string, Dictionary<string, Point>>();
_flatLayout = new Dictionary<string, Point>();
_flatLayoutShortcuts = new Dictionary<string, string>();
_clientLayout = new Dictionary<string, WindowProperties>();
// TODO To be removed
_xmlBadToOkChars = new Dictionary<string, string>();
_xmlBadToOkChars["<"] = "---lt---";
_xmlBadToOkChars["&"] = "---amp---";
_xmlBadToOkChars[">"] = "---gt---";
_xmlBadToOkChars["\""] = "---quot---";
_xmlBadToOkChars["\'"] = "---apos---";
_xmlBadToOkChars[","] = "---comma---";
_xmlBadToOkChars["."] = "---dot---";
this._thumbnailUpdateTimer.Interval = new TimeSpan(0, 0, 0, 0, configuration.ThumbnailRefreshPeriod);
}
public event Action<IList<IThumbnailView>> ThumbnailsAdded;
@@ -82,8 +57,6 @@ namespace EveOPreview.UI
public void Activate()
{
this.LoadLayout();
this._thumbnailUpdateTimer.Start();
this.RefreshThumbnails();
@@ -150,15 +123,7 @@ namespace EveOPreview.UI
continue;
}
if (this._configuration.EnablePerClientThumbnailsLayouts)
{
this.ApplyPerClientLayout(view, this._activeClientTitle);
}
else
{
this.ApplyFlatLayout(view);
}
view.Location = this._configuration.GetThumbnailLocation(view.Title, this._activeClientTitle, view.Location);
view.IsOverlayEnabled = this._configuration.ShowThumbnailOverlays;
if (!this._isHoverEffectActive)
{
@@ -176,7 +141,6 @@ namespace EveOPreview.UI
public void SetupThumbnailFrames()
{
// TODO Drop config dependency
this.DisableViewEvents();
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in this._thumbnailViews)
@@ -203,14 +167,14 @@ namespace EveOPreview.UI
this._ignoreViewEvents = true;
}
private Process[] GetClientProcesses()
private static Process[] GetClientProcesses()
{
return Process.GetProcessesByName(ThumbnailManager.ClientProcessName);
}
private void UpdateThumbnailsList()
{
Process[] clientProcesses = this.GetClientProcesses();
Process[] clientProcesses = ThumbnailManager.GetClientProcesses();
List<IntPtr> processHandles = new List<IntPtr>(clientProcesses.Length);
IntPtr foregroundWindowHandle = DwmApiNativeMethods.GetForegroundWindow();
@@ -248,7 +212,7 @@ namespace EveOPreview.UI
this._thumbnailViews.Add(processHandle, view);
this.SetupClientWindow(processHandle, processTitle);
this.ApplyClientLayout(processHandle, processTitle);
viewsAdded.Add(view);
}
@@ -263,7 +227,7 @@ namespace EveOPreview.UI
// view.RegisterShortcut(value);
//}
this.SetupClientWindow(processHandle, processTitle);
this.ApplyClientLayout(processHandle, processTitle);
viewsUpdated.Add(view);
}
@@ -352,9 +316,12 @@ namespace EveOPreview.UI
DwmApiNativeMethods.ShowWindowAsync(id, DwmApiNativeMethods.SW_SHOWNORMAL);
}
this.UpdateClientLocation();
if (this._configuration.EnableClientLayoutTracking)
{
this.UpdateClientLayouts();
}
this.SaveLayout(); // Stores info about client window locations
this._configurationStorage.Save();
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in this._thumbnailViews)
{
@@ -386,27 +353,11 @@ namespace EveOPreview.UI
IThumbnailView view = this._thumbnailViews[id];
this.UpdateThumbnailPosition(view.Title, view.Location);
this._configuration.SetThumbnailLocation(view.Title, this._activeClientTitle, view.Location);
view.Refresh();
}
private void SetupClientWindow(IntPtr clientHandle, string clientTitle)
{
if (!this._configuration.EnableClientsLocationTracking)
{
return;
}
WindowProperties windowProperties;
if (!this._clientLayout.TryGetValue(clientTitle, out windowProperties))
{
return;
}
DwmApiNativeMethods.MoveWindow(clientHandle, windowProperties.X, windowProperties.Y, windowProperties.Width, windowProperties.Height, true);
}
private bool IsClientWindowActive(IntPtr windowHandle)
{
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in _thumbnailViews)
@@ -420,26 +371,6 @@ namespace EveOPreview.UI
return false;
}
private void UpdateThumbnailPosition(string title, Point position)
{
if (!this._configuration.EnablePerClientThumbnailsLayouts)
{
_flatLayout[title] = position;
return;
}
Dictionary<string, Point> layout;
if (_uniqueLayouts.TryGetValue(_activeClientTitle, out layout))
{
layout[title] = position;
}
else if (_activeClientTitle == "")
{
_uniqueLayouts[_activeClientTitle] = new Dictionary<string, Point>();
_uniqueLayouts[_activeClientTitle][title] = position;
}
}
private void ThumbnailZoomIn(IThumbnailView view)
{
int zoomFactor = this._configuration.ThumbnailZoomFactor;
@@ -449,7 +380,7 @@ namespace EveOPreview.UI
this.DisableViewEvents();
view.Size = new Size((int)(zoomFactor * view.Size.Width), (int)(zoomFactor * view.Size.Height));
view.Size = new Size(zoomFactor * view.Size.Width, zoomFactor * view.Size.Height);
int locationX = view.Location.X;
int locationY = view.Location.Y;
@@ -509,250 +440,42 @@ namespace EveOPreview.UI
this.EnableViewEvents();
}
// ************************************************************************
// ************************************************************************
// ************************************************************************
// ************************************************************************
// ************************************************************************
// ************************************************************************
// TODO Reenable this method
private void UpdateClientLocation()
private void ApplyClientLayout(IntPtr clientHandle, string clientTitle)
{
Process[] processes = Process.GetProcessesByName("ExeFile");
List<IntPtr> processHandles = new List<IntPtr>();
ClientLayout clientLayout = this._configuration.GetClientLayout(clientTitle);
foreach (Process process in processes)
if (clientLayout == null)
{
RECT rect = new RECT();
return;
}
DwmApiNativeMethods.MoveWindow(clientHandle, clientLayout.X, clientLayout.Y, clientLayout.Width, clientLayout.Height, true);
}
private void UpdateClientLayouts()
{
Process[] clientProcesses = ThumbnailManager.GetClientProcesses();
foreach (Process process in clientProcesses)
{
RECT rect;
DwmApiNativeMethods.GetWindowRect(process.MainWindowHandle, out rect);
int left = Math.Abs(rect.Left);
int right = Math.Abs(rect.Right);
int client_width = Math.Abs(left - right);
int clientWidth = Math.Abs(left - right);
int top = Math.Abs(rect.Top);
int bottom = Math.Abs(rect.Bottom);
int client_height = Math.Abs(top - bottom);
int clientHeight = Math.Abs(top - bottom);
WindowProperties location = new WindowProperties();
location.X = rect.Left;
location.Y = rect.Top;
location.Width = client_width;
location.Height = client_height;
ClientLayout clientLayout = new ClientLayout();
clientLayout.X = rect.Left;
clientLayout.Y = rect.Top;
clientLayout.Width = clientWidth;
clientLayout.Height = clientHeight;
_clientLayout[process.MainWindowTitle] = location;
}
}
// TODO Layouting and stuff should be renewed later
private string remove_nonconform_xml_characters(string entry)
{
foreach (var kv in _xmlBadToOkChars)
{
entry = entry.Replace(kv.Key, kv.Value);
}
return entry;
}
private string restore_nonconform_xml_characters(string entry)
{
foreach (var kv in _xmlBadToOkChars)
{
entry = entry.Replace(kv.Value, kv.Key);
}
return entry;
}
private XElement MakeXElement(string input)
{
string clean = remove_nonconform_xml_characters(input).Replace(" ", "_");
return new XElement(clean);
}
private string ParseXElement(XElement input)
{
return restore_nonconform_xml_characters(input.Name.ToString()).Replace("_", " ");
}
private void LoadLayout()
{
if (File.Exists("layout.xml"))
{
XElement rootElement = XElement.Load("layout.xml");
foreach (var el in rootElement.Elements())
{
Dictionary<string, Point> inner = new Dictionary<string, Point>();
foreach (var inner_el in el.Elements())
{
inner[ParseXElement(inner_el)] = new Point(Convert.ToInt32(inner_el.Element("x")?.Value), Convert.ToInt32(inner_el.Element("y")?.Value));
}
_uniqueLayouts[ParseXElement(el)] = inner;
}
}
if (File.Exists("flat_layout.xml"))
{
XElement rootElement = XElement.Load("flat_layout.xml");
foreach (var el in rootElement.Elements())
{
_flatLayout[ParseXElement(el)] = new Point(Convert.ToInt32(el.Element("x").Value), Convert.ToInt32(el.Element("y").Value));
_flatLayoutShortcuts[ParseXElement(el)] = "";
if (el.Element("shortcut") != null)
{
_flatLayoutShortcuts[ParseXElement(el)] = el.Element("shortcut").Value;
}
}
}
if (File.Exists("client_layout.xml"))
{
XElement rootElement = XElement.Load("client_layout.xml");
foreach (var el in rootElement.Elements())
{
WindowProperties location = new WindowProperties();
location.X = Convert.ToInt32(el.Element("x").Value);
location.Y = Convert.ToInt32(el.Element("y").Value);
location.Width = Convert.ToInt32(el.Element("width").Value);
location.Height = Convert.ToInt32(el.Element("height").Value);
_clientLayout[ParseXElement(el)] = location;
}
}
}
private void SaveLayout()
{
XElement el = new XElement("layouts");
foreach (var client in _uniqueLayouts.Keys)
{
if (client == "")
{
continue;
}
XElement layout = MakeXElement(client);
foreach (var thumbnail_ in _uniqueLayouts[client])
{
string thumbnail = thumbnail_.Key;
if (thumbnail == "" || thumbnail == "...")
{
continue;
}
XElement position = MakeXElement(thumbnail);
position.Add(new XElement("x", thumbnail_.Value.X));
position.Add(new XElement("y", thumbnail_.Value.Y));
layout.Add(position);
}
el.Add(layout);
}
el.Save("layout.xml");
XElement el2 = new XElement("flat_layout");
foreach (var clientKV in _flatLayout)
{
if (clientKV.Key == "" || clientKV.Key == "...")
{
continue;
}
XElement layout = MakeXElement(clientKV.Key);
layout.Add(new XElement("x", clientKV.Value.X));
layout.Add(new XElement("y", clientKV.Value.Y));
string shortcut;
if (_flatLayoutShortcuts.TryGetValue(clientKV.Key, out shortcut))
{
layout.Add(new XElement("shortcut", shortcut));
}
el2.Add(layout);
}
el2.Save("flat_layout.xml");
XElement el3 = new XElement("client_layout");
foreach (var clientKV in _clientLayout)
{
if (clientKV.Key == "" || clientKV.Key == "...")
{
continue;
}
XElement layout = MakeXElement(clientKV.Key);
layout.Add(new XElement("x", clientKV.Value.X));
layout.Add(new XElement("y", clientKV.Value.Y));
layout.Add(new XElement("width", clientKV.Value.Width));
layout.Add(new XElement("height", clientKV.Value.Height));
el3.Add(layout);
}
el3.Save("client_layout.xml");
}
private void ApplyPerClientLayout(IThumbnailView thumbnailWindow, string last_known_active_window)
{
Dictionary<string, Point> layout;
if (_uniqueLayouts.TryGetValue(last_known_active_window, out layout))
{
Point new_loc;
if (this._configuration.EnablePerClientThumbnailsLayouts && layout.TryGetValue(thumbnailWindow.Title, out new_loc))
{
thumbnailWindow.Location = new_loc;
}
else
{
// create inner dict
layout[thumbnailWindow.Title] = thumbnailWindow.Location;
}
}
else if (last_known_active_window != "")
{
// create outer dict
_uniqueLayouts[last_known_active_window] = new Dictionary<string, Point>();
_uniqueLayouts[last_known_active_window][thumbnailWindow.Title] = thumbnailWindow.Location;
}
}
private void ApplyFlatLayout(IThumbnailView thumbnailWindow)
{
Point layout;
if (_flatLayout.TryGetValue(thumbnailWindow.Title, out layout))
{
thumbnailWindow.Location = layout;
}
else if (thumbnailWindow.Title != "")
{
_flatLayout[thumbnailWindow.Title] = thumbnailWindow.Location;
this._configuration.SetClientLayout(process.MainWindowTitle, clientLayout);
}
}
}