bookmark-manager-r4/MainForm.cs
Ray c90a34904d Fixed folder paths when saving
Fixed update-icon close button
2024-07-21 18:44:05 +01:00

1041 lines
31 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using BookmarkManager;
using BookmarkManager.Models;
using bzit.bomg.Models;
using FizzyLauncher.Models;
using RyzStudio;
using RyzStudio.Windows.Forms;
using RyzStudio.Windows.ThemedForms;
namespace FizzyLauncher
{
public partial class MainForm : Form
{
private readonly FileSessionManager _fileSessionManager;
private bool _isBusy = false;
public MainForm()
{
InitializeComponent();
this.Text = Application.ProductName;
_fileSessionManager = new FileSessionManager();
_fileSessionManager.OpenFileDialog = openFileDialog1;
_fileSessionManager.SaveFileDialog = saveFileDialog1;
_fileSessionManager.OnNewing += fileSessionManager_OnNewSession;
_fileSessionManager.OnLoading += fileSessionManager_OnLoadSession;
_fileSessionManager.OnSaving += fileSessionManager_OnSaveSession;
_fileSessionManager.OnClearing += fileSessionManager_OnClearSession;
_fileSessionManager.OnFilenameChanged += fileSessionManager_OnFilenameChanged;
this.AutoScaleMode = AutoScaleMode.None;
this.StartPosition = FormStartPosition.WindowsDefaultLocation;
treeView1.RootContextMenu = rootContextMenu;
treeView1.FolderContextMenu = folderContextMenu;
treeView1.PageContextMenu = pageContextMenu;
treeView1.NodeMouseDoubleClick += treeView1_NodeMouseDoubleClick;
treeView1.PreviewKeyDown += treeView1_PreviewKeyDown;
}
protected async override void OnShown(EventArgs e)
{
base.OnShown(e);
var args = WinApplication.GetCommandLine();
string jsonfigFilename = args.Where(x => (x.Key.Equals("o") || x.Key.Equals("open"))).Select(x => x.Value).FirstOrDefault();
//if (string.IsNullOrWhiteSpace(jsonfigFilename))
//{
// jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig");
//}
if (!string.IsNullOrWhiteSpace(jsonfigFilename) && File.Exists(jsonfigFilename))
{
await _fileSessionManager.OpenSession(jsonfigFilename);
}
else
{
this.CurrentSession = new AppOptions();
InvalidateOptions();
}
}
protected async override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
await _fileSessionManager.CloseSession();
}
public AppOptions CurrentSession { get; set; } = null;
public bool IsBusy
{
get => _isBusy;
set
{
treeView1.Enabled = !value;
}
}
private void InvalidateOptions()
{
UIControl.SetTopMost(this, this.CurrentSession.AlwaysOnTop);
}
private void menuStrip1_MenuActivate(object sender, EventArgs e)
{
closeToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close);
saveToolStripMenuItem.Enabled = (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Open) && treeView1.HasChanged;
saveAsToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close);
findToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close);
collapseAllToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close);
expandAllToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close);
alwaysOnTopToolStripMenuItem.Checked = this.CurrentSession?.AlwaysOnTop ?? false;
toolStripMenuItem9.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close);
}
#region Main Menu
/// <summary>
/// New
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void newToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
await _fileSessionManager.NewSession();
}
/// <summary>
/// Open file
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void openToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
await _fileSessionManager.OpenSession();
}
/// <summary>
/// Close
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void closeToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
await _fileSessionManager.CloseSession();
}
/// <summary>
/// Save
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
await _fileSessionManager.SaveSession();
}
/// <summary>
/// Save As
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
await _fileSessionManager.SaveAsSession();
}
/// <summary>
/// Exit
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
this.Close();
}
/// <summary>
/// Find
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void findToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
var form = new FindForm(treeView1);
form.ShowDialog();
}
/// <summary>
/// Expand all
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void expandAllToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
if (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Close)
{
return;
}
if (treeView1.SelectedNode == null)
{
treeView1.ExpandAll();
}
else
{
treeView1.SelectedNode.ExpandAll();
}
}
/// <summary>
/// Collapse all
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
if (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Close)
{
return;
}
if (treeView1.SelectedNode == null)
{
treeView1.CollapseAll();
}
else
{
treeView1.SelectedNode.Collapse(false);
}
}
/// <summary>
/// Always on top
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.CurrentSession == null)
{
return;
}
this.CurrentSession.AlwaysOnTop = !this.CurrentSession.AlwaysOnTop;
this.TopMost = this.CurrentSession.AlwaysOnTop;
}
/// <summary>
/// Update icons
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void toolStripMenuItem9_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
var form = new UpdateIconsForm(treeView1);
form.ShowDialog();
}
/// <summary>
/// Options
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
var form = new OptionsForm(this.CurrentSession);
if (form.ShowDialog() == DialogResult.OK)
{
this.CurrentSession = form.Result;
InvalidateOptions();
}
}
/// <summary>
/// View help
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e)
{
RyzStudio.Diagnostics.Process.Execute(AppResource.AppHelpURL);
}
/// <summary>
/// About
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
{
var form = new RyzStudio.Windows.ThemedForms.AboutForm();
form.ProductURL = AppResource.AppProductURL;
form.AuthorURL = AppResource.AppAuthorURL;
form.CompanyURL = AppResource.AppCompanyURL;
form.ProductCopyrightStartYear = 2012;
form.ProductLogo = AppResource.icon_64;
form.ShowDialog();
}
#endregion
#region Context Menu - Root
/// <summary>
/// Add page
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void addPageToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
var nodeType = treeView1.GetNodeType();
if ((nodeType == BookmarkTreeView.NodeType.Root) || (nodeType == BookmarkTreeView.NodeType.Folder))
{
treeView1.AddNode();
}
}
/// <summary>
/// Add folder
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void addFolderToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
var nodeType = treeView1.GetNodeType();
if ((nodeType == BookmarkTreeView.NodeType.Root) || (nodeType == BookmarkTreeView.NodeType.Folder))
{
treeView1.AddFolder();
}
}
/// <summary>
/// Edit root node
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void editToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
treeView1.EditNode();
}
/// <summary>
/// Sort
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void sortToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
treeView1.Sort();
}
#endregion
#region Context Menu - Folder
/// <summary>
/// Add page
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void addPageToolStripMenuItem1_Click(object sender, EventArgs e)
{
addPageToolStripMenuItem_Click(sender, e);
}
/// <summary>
/// Add folder
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void addFolderToolStripMenuItem1_Click(object sender, EventArgs e)
{
addFolderToolStripMenuItem_Click(sender, e);
}
/// <summary>
/// Open all pages
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void openAllToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
if (treeView1.SelectedNode == null)
{
return;
}
if (treeView1.SelectedNode.Nodes.Count <= 0)
{
return;
}
foreach (TreeNode item in treeView1.SelectedNode.Nodes)
{
await OpenBookmark(item);
}
}
/// <summary>
/// Edit folder name
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void editToolStripMenuItem1_Click(object sender, EventArgs e)
{
editToolStripMenuItem_Click(sender, e);
}
/// <summary>
/// Delete folder
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
if (MessageBox.Show("Delete?", "Delete?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes)
{
treeView1.DeleteNode();
}
}
/// <summary>
/// Sort children
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void sortToolStripMenuItem1_Click(object sender, EventArgs e)
{
sortToolStripMenuItem_Click(sender, e);
}
/// <summary>
/// Move up
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void moveUpToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
treeView1.MoveUp();
}
/// <summary>
/// Move down
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void moveDownToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.IsBusy)
{
return;
}
treeView1.MoveDown();
}
#endregion
#region Context Menu - Bookmark
/// <summary>
/// Open page
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void openToolStripMenuItem1_Click(object sender, EventArgs e)
{
await OpenBookmark(treeView1.SelectedNode);
}
/// <summary>
/// Edit page
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void editToolStripMenuItem2_Click(object sender, EventArgs e)
{
editToolStripMenuItem_Click(sender, e);
}
/// <summary>
/// Delete page
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void deleteToolStripMenuItem1_Click(object sender, EventArgs e)
{
deleteToolStripMenuItem_Click(sender, e);
}
/// <summary>
/// Move up
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void moveUpToolStripMenuItem1_Click(object sender, EventArgs e)
{
moveUpToolStripMenuItem_Click(sender, e);
}
/// <summary>
/// Move down
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void moveDownToolStripMenuItem1_Click(object sender, EventArgs e)
{
moveDownToolStripMenuItem_Click(sender, e);
}
#endregion
#region File Session Manager
private async Task<bool> fileSessionManager_OnNewSession(FileSessionManager sender)
{
return await Task.Run(() =>
{
treeView1.Clear("New Session");
if (treeView1.Nodes.Count >= 0)
{
UIControl.Invoke(treeView1, (x) =>
{
treeView1.Nodes[0].Expand();
treeView1.SelectedNode = treeView1.Nodes[0];
});
}
UIControl.SetFocus(treeView1);
return true;
});
}
private async Task<bool> fileSessionManager_OnLoadSession(FileSessionManager sender, string filename, int formatType)
{
return await Task.Run(async () =>
{
var result = GenericResult.Create();
switch (Path.GetExtension(filename?.ToLower()?.Trim() ?? string.Empty))
{
case ".json":
this.CurrentSession = RyzStudio.Text.Json.JsonSerialiser.DeserialiseFile<AppOptions>(filename);
if (this.CurrentSession == null)
{
this.CurrentSession = LoadR4SaveFile(filename);
}
break;
case ".jsnx":
this.CurrentSession = await RyzStudio.IO.Compression.ZFile.ReadFile<AppOptions>(filename, "Document.json");
if (this.CurrentSession == null)
{
this.CurrentSession = new AppOptions();
}
// Load icons
this.CurrentSession = await LoadIconsFromZipFile(filename, this.CurrentSession);
break;
default:
this.CurrentSession = null;
break;
}
if (this.CurrentSession == null)
{
ThMessageBox.Show(this, "Unable to read session", "Load session", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
if (this.CurrentSession == null)
{
this.CurrentSession = new AppOptions();
}
// Reposition + resize
if (!this.CurrentSession.StartPosition.IsEmpty)
{
UIControl.SetLocation(this, this.CurrentSession.StartPosition);
}
if (this.CurrentSession.Height > 0)
{
UIControl.SetHeight(this, this.CurrentSession.Height);
}
if (this.CurrentSession.Width > 0)
{
UIControl.SetWidth(this, this.CurrentSession.Width);
}
InvalidateOptions();
// Load items
treeView1.Clear("New Session");
foreach (var item in this.CurrentSession.Items ?? new List<BookmarkModel>())
{
treeView1.AddNode(item);
}
if (treeView1.Nodes.Count >= 0)
{
UIControl.Invoke(treeView1, (x) =>
{
treeView1.Nodes[0].Expand();
treeView1.SelectedNode = treeView1.Nodes[0];
});
}
UIControl.SetFocus(treeView1);
return true;
});
}
private async Task<bool> fileSessionManager_OnSaveSession(FileSessionManager sender, string filename, int formatType, bool showNotices)
{
if (string.IsNullOrWhiteSpace(filename))
{
return false;
}
return await Task.Run(async () =>
{
if (_isBusy)
{
return false;
}
_isBusy = true;
// update session
if (this.CurrentSession == null)
{
this.CurrentSession = new AppOptions();
}
this.CurrentSession.StartPosition = this.Location;
this.CurrentSession.Width = this.Width;
this.CurrentSession.Height = this.Height;
var nodeList = treeView1.ToNodeList<BookmarkModel>() ?? new List<KeyValuePair<TreeNode, BookmarkModel>>();
foreach (var node in nodeList)
{
node.Value.Path = treeView1.GetNodePath(node.Key);
if (node.Value.Path.Contains('\n'))
{
node.Value.Path = node.Value.Path.Substring(0, node.Value.Path.LastIndexOf('\n'));
}
}
this.CurrentSession.Items = nodeList.Select(x => x.Value).ToList();
var result = GenericResult.Create();
switch (Path.GetExtension(filename?.ToLower()?.Trim() ?? string.Empty))
{
case ".json":
case ".jsonfig":
result = RyzStudio.Text.Json.JsonSerialiser.SerialiseFile(filename, this.CurrentSession);
break;
case ".jsnx":
result = await RyzStudio.IO.Compression.ZFile.WriteFile(filename, "Document.json", this.CurrentSession);
if (result.IsSuccess)
{
// Add icons to save file
var result2 = AddImagesToZipFile(filename, this.CurrentSession.Items);
if (!result2.IsSuccess)
{
if (showNotices)
{
ThMessageBox.Show(this, "Unable to save icons", "Save session", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
break;
default:
result = GenericResult.Fault("Format not supported");
break;
}
if (result.IsSuccess)
{
if (showNotices)
{
ThMessageBox.Show(this, "Session saved!", "Save session", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
else
{
if (showNotices)
{
ThMessageBox.Show(this, result.Message, "Save session");
}
}
_isBusy = false;
return result.IsSuccess;
});
}
private async Task<bool> fileSessionManager_OnClearSession(FileSessionManager sender)
{
return await Task.Run(() =>
{
UIControl.Clear(treeView1);
return true;
});
}
private async Task fileSessionManager_OnFilenameChanged(FileSessionManager sender, string filename)
{
await Task.Run(() =>
{
switch (sender.SessionState)
{
case FileSessionManager.SessionStateEnum.New:
UIControl.SetText(this, "New Session - " + Application.ProductName);
break;
case FileSessionManager.SessionStateEnum.Open:
UIControl.SetText(this, Path.GetFileNameWithoutExtension(filename) + " - " + Application.ProductName);
break;
case FileSessionManager.SessionStateEnum.Close:
UIControl.SetText(this, Application.ProductName);
break;
default:
break;
}
treeView1.HasChanged = false;
});
}
#endregion
private async void treeView1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
TreeNode node = treeView1.SelectedNode;
if (node == null)
{
return;
}
BookmarkTreeView.NodeType nodeType = treeView1.GetNodeType();
switch (e.KeyCode)
{
case Keys.Enter:
await OpenBookmark(node);
break;
default:
break;
}
}
private async void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
await OpenBookmark(e.Node);
}
private AppOptions LoadR4SaveFile(string filename)
{
var session = RyzStudio.Text.Json.JsonSerialiser.DeserialiseFile<List<R4SaveFileModel>>(filename);
if (session == null)
{
return null;
}
var result = new AppOptions();
result.Items = new List<BookmarkModel>();
foreach (var item in session)
{
result.Items.Add(new BookmarkModel()
{
Title = item.SiteName,
Address = item.SiteAddress,
Description = item.SiteDescription,
Notes = item.Notes,
Path = item.Path
});
}
return result;
}
private async Task<AppOptions> LoadIconsFromZipFile(string filename, AppOptions session)
{
if (string.IsNullOrWhiteSpace(filename))
{
return session;
}
return await Task.Run(() =>
{
try
{
using (var archive = ZipFile.Open(filename, ZipArchiveMode.Read))
{
foreach (var item in session.Items)
{
if (item.Id == Guid.Empty)
{
continue;
}
var key = "icon\\" + item.Id.ToString() + ".png";
var zipEntry = archive.GetEntry(key);
if (zipEntry == null)
{
continue;
}
using (Stream entryStream = zipEntry.Open())
{
item.Icon = Image.FromStream(entryStream);
}
}
}
}
catch (Exception)
{
// do nothing
}
return session;
});
}
private async Task OpenBookmark(TreeNode node)
{
await Task.Run(() =>
{
if (treeView1.GetNodeType(node) != BookmarkTreeView.NodeType.Page)
{
return;
}
var model = UIControl.GetTag<BookmarkModel>(node);
if (model == null)
{
return;
}
if (string.IsNullOrWhiteSpace(model.Address))
{
return;
}
string cmd = (string.IsNullOrWhiteSpace(CurrentSession.RunCommand) ? model.Address : CurrentSession.RunCommand.Replace("{0}", model.Address));
RyzStudio.Diagnostics.Process.Execute(cmd);
});
}
private GenericResult AddImagesToZipFile(string zipFilename, List<BookmarkModel> items)
{
if (string.IsNullOrWhiteSpace(zipFilename))
{
return GenericResult.Fault("Filename is blank");
}
var path = Path.GetDirectoryName(zipFilename);
if (!System.IO.Directory.Exists(path))
{
try
{
System.IO.Directory.CreateDirectory(path);
}
catch (Exception exc)
{
return GenericResult.Fault(exc.Message);
}
}
var options = RyzStudio.Text.Json.JsonSerialiser.GetPreferredOptions();
try
{
using (var archive = ZipFile.Open(zipFilename, ZipArchiveMode.Update))
{
foreach (var item in items)
{
var key = "icon\\" + item.Id.ToString() + ".png";
var zipEntry = archive.GetEntry(key);
if (zipEntry != null)
{
zipEntry.Delete();
}
if (item.Icon == null)
{
continue;
}
zipEntry = archive.CreateEntry(key, CompressionLevel.SmallestSize);
try
{
using (Stream entryStream = zipEntry.Open())
{
using (Image image = item.Icon)
{
image.Save(entryStream, ImageFormat.Png);
}
}
}
catch (Exception)
{
continue;
}
}
}
}
catch (Exception exc)
{
return GenericResult.Fault(exc.Message);
}
return GenericResult.Create();
}
}
}