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 BukkuBuddy.DTOs.SaveFile; using BukkuBuddy.Forms; using BukkuBuddy.Resources; using RyzStudio; using RyzStudio.Windows.Forms; using RyzStudio.Windows.ThemedForms; using static RyzStudio.Windows.Forms.BookmarkTreeView; namespace BukkuBuddy { public partial class MainForm : Form { private readonly IFileSessionManager _fileSessionManager; private App6Options currentSession = null; private bool isBusy = false; public MainForm() { InitializeComponent(); this.AutoScaleMode = AutoScaleMode.None; this.StartPosition = FormStartPosition.WindowsDefaultLocation; 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; treeView1.RootContextMenu = rootContextMenu; treeView1.FolderContextMenu = folderContextMenu; treeView1.PageContextMenu = pageContextMenu; treeView1.OnEditNode += treeView1_OnEditNode; treeView1.NodeMouseDoubleClick += treeView1_NodeMouseDoubleClick; treeView1.PreviewKeyDown += treeView1_PreviewKeyDown; treeView1.OnChanged += treeView1_OnChanged; } 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(); } UIControl.SetFocus(this); } protected async override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); await _fileSessionManager.CloseSession(); } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public App6Options CurrentSession { get { if (currentSession == null) { currentSession = new App6Options(); } return currentSession; } set => currentSession = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsBusy { get => isBusy; set { isBusy = value; UIControl.SetEnable(treeView1, !isBusy); } } private void InvalidateOptions(bool resize) { UIControl.SetTopMost(this, this.CurrentSession.AlwaysOnTop); if (resize) { if (!this.CurrentSession.StartPosition.IsEmpty) { UIControl.SetLocation(this, this.CurrentSession.StartPosition); } if (this.CurrentSession.Width > 0) { UIControl.SetClientWidth(this, this.CurrentSession.Width); } if (this.CurrentSession.Height > 0) { UIControl.SetClientHeight(this, this.CurrentSession.Height); } } } private void menuStrip1_MenuActivate(object sender, EventArgs e) { closeToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close); //saveToolStripMenuItem.Enabled = (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Open) && treeView1.HasChanged; saveToolStripMenuItem.Enabled = (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Open) && _fileSessionManager.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); updateAllToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close); clearToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close); } #region Main Menu /// /// New /// /// /// private async void newToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } await _fileSessionManager.NewSession(); } /// /// Open file /// /// /// private async void openToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } await _fileSessionManager.OpenSession(); } /// /// Close /// /// /// private async void closeToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } await _fileSessionManager.CloseSession(); } /// /// Save /// /// /// private async void saveToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } await _fileSessionManager.SaveSession(); } /// /// Save As /// /// /// private async void saveAsToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } await _fileSessionManager.SaveAsSession(); } /// /// Exit /// /// /// private void exitToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } this.Close(); } /// /// Find /// /// /// private void findToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } var form = new FindForm(treeView1); form.ShowDialog(); } /// /// Expand all /// /// /// private async void expandAllToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } if (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Close) { return; } await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { if (treeView1.SelectedNode == null) { treeView1.ExpandAll(); } else { treeView1.SelectedNode.ExpandAll(); } }); }); } /// /// Collapse all /// /// /// private async void collapseAllToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } if (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Close) { return; } await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { if (treeView1.SelectedNode == null) { treeView1.CollapseAll(); } else { treeView1.SelectedNode.Collapse(false); } }); }); } /// /// Always on top /// /// /// private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e) { if (this.CurrentSession == null) { return; } this.CurrentSession.AlwaysOnTop = !this.CurrentSession.AlwaysOnTop; this.TopMost = this.CurrentSession.AlwaysOnTop; } /// /// Update icons /// /// /// private async void toolStripMenuItem9_Click_1(object sender, EventArgs e) { if (this.IsBusy) { return; } this.IsBusy = true; await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { if (treeView1.GetNodeCount(true) <= 0) { return; } if (MessageBox.Show("Are you sure you want to update (missing) icons?", "Update Icons", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes) { var form = new UpdateIconsForm(treeView1, this.CurrentSession, true); form.ShowDialog(); } }); }); this.IsBusy = false; } /// /// Update all icons. /// /// /// private async void updateAllToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } this.IsBusy = true; await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { if (treeView1.GetNodeCount(true) <= 0) { return; } if (MessageBox.Show("Are you sure you want to update all icons?", "Update Icons", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes) { var form = new UpdateIconsForm(treeView1, this.CurrentSession, false); form.ShowDialog(); } }); }); this.IsBusy = false; } /// /// Clear All Icons /// /// /// private async void clearToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } this.IsBusy = true; await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { if (treeView1.GetNodeCount(true) <= 0) { return; } if (MessageBox.Show("Are you sure you want to clear all icons?", "Clear Icons", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes) { var form = new ClearIconsForm(treeView1); form.ShowDialog(); } }); }); this.IsBusy = false; } /// /// Update icons /// /// /// private async void toolStripMenuItem9_Click(object sender, EventArgs e) { //if (this.IsBusy) //{ // return; //} //var form = new UpdateIconsForm(treeView1); //form.ShowDialog(); } /// /// Options /// /// /// 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.StartPosition = form.Result.StartPosition; this.CurrentSession.RunCommand = form.Result.RunCommand; this.CurrentSession.AlwaysOnTop = form.Result.AlwaysOnTop; this.CurrentSession.AllowUnsafeSSL = form.Result.AllowUnsafeSSL; this.CurrentSession.Timeout = form.Result.Timeout; this.CurrentSession.AllowCookies = form.Result.AllowCookies; this.CurrentSession.AllowRedirects = form.Result.AllowRedirects; InvalidateOptions(false); } } /// /// View help /// /// /// private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e) { RyzStudio.Diagnostics.Process.Execute(MainMenuResource.AppHelpURL); } /// /// About /// /// /// private void aboutToolStripMenuItem1_Click(object sender, EventArgs e) { var form = new RyzStudio.Windows.ThemedForms.AboutForm(); form.ProductURL = MainMenuResource.AppProductURL; form.AuthorURL = MainMenuResource.AppAuthorURL; form.CompanyURL = MainMenuResource.AppCompanyURL; form.ProductCopyrightStartYear = 2012; form.ProductLogo = MainMenuResource.icon_64; form.ShowDialog(); } #endregion #region Context Menu - Root /// /// Add page /// /// /// private async void addPageToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } var nodeType = treeView1.GetNodeType(); if ((nodeType == BookmarkTreeView.NodeType.Root) || (nodeType == BookmarkTreeView.NodeType.Folder)) { await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { treeView1.AddNode(); }); }); } } /// /// Add multiple pages /// /// /// private async void toolStripMenuItem11_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } var nodeType = treeView1.GetNodeType(); if ((nodeType != NodeType.Root) && (nodeType != NodeType.Folder)) { return; } var nodePath = treeView1.GetNodePath(); var form = new AddMultiPageForm(nodePath, this.CurrentSession); if (form.ShowDialog() == DialogResult.OK) { await Task.Run(async () => { foreach (var item in form.Result) { UIControl.Invoke(treeView1, (x) => { treeView1.AddNode(item); }); } }); } } /// /// Add folder /// /// /// private async void addFolderToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } var nodeType = treeView1.GetNodeType(); if ((nodeType == BookmarkTreeView.NodeType.Root) || (nodeType == BookmarkTreeView.NodeType.Folder)) { await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { treeView1.AddFolder(); }); }); } } /// /// Edit root node /// /// /// private void editToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } treeView1.EditNode(); } /// /// Sort /// /// /// private async void sortToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } this.IsBusy = true; await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { treeView1.Sort(); }); }); this.IsBusy = false; } #endregion #region Context Menu - Folder /// /// Add page /// /// /// private void addPageToolStripMenuItem1_Click(object sender, EventArgs e) { addPageToolStripMenuItem_Click(sender, e); } /// /// Add page (batch) /// /// /// private void toolStripMenuItem10_Click(object sender, EventArgs e) { toolStripMenuItem11_Click(this, e); } /// /// Add folder /// /// /// private void addFolderToolStripMenuItem1_Click(object sender, EventArgs e) { addFolderToolStripMenuItem_Click(sender, e); } /// /// Open all pages /// /// /// 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); } } /// /// Edit folder name /// /// /// private void editToolStripMenuItem1_Click(object sender, EventArgs e) { editToolStripMenuItem_Click(sender, e); } /// /// Delete folder /// /// /// private async void deleteToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } if (MessageBox.Show("Delete?", "Delete?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes) { await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { treeView1.DeleteNode(); }); }); } } /// /// Sort children /// /// /// private void sortToolStripMenuItem1_Click(object sender, EventArgs e) { sortToolStripMenuItem_Click(sender, e); } /// /// Move up /// /// /// private void moveUpToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } treeView1.MoveUp(); } /// /// Move down /// /// /// private void moveDownToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } treeView1.MoveDown(); } #endregion #region Context Menu - Bookmark /// /// Open page /// /// /// private async void openToolStripMenuItem1_Click(object sender, EventArgs e) { await OpenBookmark(treeView1.SelectedNode); } /// /// Edit page /// /// /// private void editToolStripMenuItem2_Click(object sender, EventArgs e) { editToolStripMenuItem_Click(sender, e); } /// /// Delete page /// /// /// private void deleteToolStripMenuItem1_Click(object sender, EventArgs e) { deleteToolStripMenuItem_Click(sender, e); } /// /// Move up /// /// /// private void moveUpToolStripMenuItem1_Click(object sender, EventArgs e) { moveUpToolStripMenuItem_Click(sender, e); } /// /// Move down /// /// /// private void moveDownToolStripMenuItem1_Click(object sender, EventArgs e) { moveDownToolStripMenuItem_Click(sender, e); } #endregion #region File Session Manager private async Task fileSessionManager_OnNewSession(FileSessionManager sender) { return await Task.Run(() => { UIControl.Invoke(treeView1, (x) => { treeView1.Clear(true, true, "New Session"); if (treeView1.Nodes.Count >= 0) { treeView1.Nodes[0].Expand(); treeView1.SelectedNode = treeView1.Nodes[0]; } }); UIControl.SetFocus(treeView1); sender.HasChanged = true; return true; }); } private async Task fileSessionManager_OnLoadSession(FileSessionManager sender, string filename, int formatType) { var loadingForm = new LoadingForm(); var result = await loadingForm.ShowDialog(filename, treeView1); if (result != DialogResult.OK) { return false; } await Task.Run(() => { this.CurrentSession = loadingForm.Result; this.InvalidateOptions(true); }); UIControl.SetFocus(treeView1); sender.HasChanged = false; return true; } private async Task 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 App6Options(); } this.CurrentSession.StartPosition = this.Location; this.CurrentSession.Width = this.Width; this.CurrentSession.Height = this.Height; var directoryList = treeView1.GetAllNodePaths(); var bookmarkList = treeView1.GetAllItems(); this.CurrentSession.Directories = directoryList ?? new List(); this.CurrentSession.Items = bookmarkList.Select(x => x.Value)?.ToList() ?? new List(); 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, bookmarkList); 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; if (result.IsSuccess) { sender.HasChanged = false; } return result.IsSuccess; }); } private async Task fileSessionManager_OnClearSession(FileSessionManager sender) { UIControl.Clear(treeView1); sender.HasChanged = false; 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; } }); } #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 bool treeView1_OnEditNode(BookmarkTreeView sender, TreeNode node, App6Options.Item model) { if (this.IsBusy) { return false; } var form = new EditBookmarkForm(model, this.CurrentSession); if (form.ShowDialog() == DialogResult.OK) { sender.UpdateNode(node, form.Result); return true; } return false; } private void treeView1_OnChanged(BookmarkTreeView sender, bool hasChanged) { if (hasChanged) { _fileSessionManager.HasChanged = hasChanged; } } private async Task OpenBookmark(TreeNode node) { await Task.Run(() => { if (treeView1.GetNodeType(node) != BookmarkTreeView.NodeType.Page) { return; } var model = UIControl.GetTag(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> 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.Value.Id.ToString() + ".png"; var zipEntry = archive.GetEntry(key); if (zipEntry != null) { zipEntry.Delete(); } if (item.Key.ImageIndex == (int)NodeIcon.Default) { continue; } if (!treeView1.ImageList.Images.ContainsKey(item.Value.Id.ToString())) { continue; } var icon = treeView1.ImageList.Images[item.Value.Id.ToString()]; if (icon == null) { continue; } try { if (icon.Width <= 0) { continue; } } catch (Exception) { continue; } zipEntry = archive.CreateEntry(key, CompressionLevel.SmallestSize); try { using (Stream entryStream = zipEntry.Open()) { using (Image image = icon) { image.Save(entryStream, ImageFormat.Png); } } } catch (Exception) { zipEntry.Delete(); continue; } } } } catch (Exception exc) { return GenericResult.Fault(exc.Message); } return GenericResult.Create(); } } }