From 3e7e05bda941b02e241c1b02d7b1d148e7722a0f Mon Sep 17 00:00:00 2001 From: Justin Aquadro Date: Sat, 1 Sep 2012 19:27:50 -0400 Subject: [PATCH] Feature parity --- MainForm.Designer.cs | 76 ++--- MainForm.cs | 506 ++++++++++++++++++++++++++--- Model/DataNode.cs | 14 + Model/NbtFileDataNode.cs | 8 + Model/RegionChunkDataNode.cs | 8 + Model/TagDataNode.cs | 10 + NBTExplorer.csproj | 9 + forms/CancelSearchForm.Designer.cs | 63 ++++ forms/CancelSearchForm.cs | 19 ++ forms/CancelSearchForm.resx | 120 +++++++ forms/EditValue.cs | 2 +- 11 files changed, 755 insertions(+), 80 deletions(-) create mode 100644 forms/CancelSearchForm.Designer.cs create mode 100644 forms/CancelSearchForm.cs create mode 100644 forms/CancelSearchForm.resx diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index b2bd556..b9bc44b 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -31,11 +31,11 @@ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.openFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.openMinecraftSaveFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this._menuItemOpen = new System.Windows.Forms.ToolStripMenuItem(); + this._menuItemOpenFolder = new System.Windows.Forms.ToolStripMenuItem(); + this._menuItemOpenMinecraftSaveFolder = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this._menuItemSave = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); this._menuItemExit = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -48,7 +48,7 @@ this._menuItemDelete = new System.Windows.Forms.ToolStripMenuItem(); this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this._menuItemFind = new System.Windows.Forms.ToolStripMenuItem(); - this.findNextToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this._menuItemFindNext = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this._menuItemAbout = new System.Windows.Forms.ToolStripMenuItem(); this._nodeTree = new System.Windows.Forms.TreeView(); @@ -107,11 +107,11 @@ // fileToolStripMenuItem // this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.openToolStripMenuItem, - this.openFolderToolStripMenuItem, - this.openMinecraftSaveFolderToolStripMenuItem, + this._menuItemOpen, + this._menuItemOpenFolder, + this._menuItemOpenMinecraftSaveFolder, this.toolStripSeparator3, - this.saveToolStripMenuItem, + this._menuItemSave, this.toolStripSeparator4, this._menuItemExit}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; @@ -120,26 +120,26 @@ // // openToolStripMenuItem // - this.openToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image"))); - this.openToolStripMenuItem.Name = "openToolStripMenuItem"; - this.openToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.openToolStripMenuItem.Size = new System.Drawing.Size(223, 22); - this.openToolStripMenuItem.Text = "&Open..."; + this._menuItemOpen.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image"))); + this._menuItemOpen.Name = "openToolStripMenuItem"; + this._menuItemOpen.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); + this._menuItemOpen.Size = new System.Drawing.Size(223, 22); + this._menuItemOpen.Text = "&Open..."; // // openFolderToolStripMenuItem // - this.openFolderToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openFolderToolStripMenuItem.Image"))); - this.openFolderToolStripMenuItem.Name = "openFolderToolStripMenuItem"; - this.openFolderToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) + this._menuItemOpenFolder.Image = ((System.Drawing.Image)(resources.GetObject("openFolderToolStripMenuItem.Image"))); + this._menuItemOpenFolder.Name = "openFolderToolStripMenuItem"; + this._menuItemOpenFolder.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) | System.Windows.Forms.Keys.O))); - this.openFolderToolStripMenuItem.Size = new System.Drawing.Size(223, 22); - this.openFolderToolStripMenuItem.Text = "Open &Folder..."; + this._menuItemOpenFolder.Size = new System.Drawing.Size(223, 22); + this._menuItemOpenFolder.Text = "Open &Folder..."; // // openMinecraftSaveFolderToolStripMenuItem // - this.openMinecraftSaveFolderToolStripMenuItem.Name = "openMinecraftSaveFolderToolStripMenuItem"; - this.openMinecraftSaveFolderToolStripMenuItem.Size = new System.Drawing.Size(223, 22); - this.openMinecraftSaveFolderToolStripMenuItem.Text = "Open &Minecraft Save Folder"; + this._menuItemOpenMinecraftSaveFolder.Name = "openMinecraftSaveFolderToolStripMenuItem"; + this._menuItemOpenMinecraftSaveFolder.Size = new System.Drawing.Size(223, 22); + this._menuItemOpenMinecraftSaveFolder.Text = "Open &Minecraft Save Folder"; // // toolStripSeparator3 // @@ -148,11 +148,11 @@ // // saveToolStripMenuItem // - this.saveToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image"))); - this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; - this.saveToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.saveToolStripMenuItem.Size = new System.Drawing.Size(223, 22); - this.saveToolStripMenuItem.Text = "&Save"; + this._menuItemSave.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image"))); + this._menuItemSave.Name = "saveToolStripMenuItem"; + this._menuItemSave.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); + this._menuItemSave.Size = new System.Drawing.Size(223, 22); + this._menuItemSave.Text = "&Save"; // // toolStripSeparator4 // @@ -238,7 +238,7 @@ // this.searchToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this._menuItemFind, - this.findNextToolStripMenuItem}); + this._menuItemFindNext}); this.searchToolStripMenuItem.Name = "searchToolStripMenuItem"; this.searchToolStripMenuItem.Size = new System.Drawing.Size(54, 20); this.searchToolStripMenuItem.Text = "&Search"; @@ -253,11 +253,11 @@ // // findNextToolStripMenuItem // - this.findNextToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("findNextToolStripMenuItem.Image"))); - this.findNextToolStripMenuItem.Name = "findNextToolStripMenuItem"; - this.findNextToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F3; - this.findNextToolStripMenuItem.Size = new System.Drawing.Size(146, 22); - this.findNextToolStripMenuItem.Text = "Find Next"; + this._menuItemFindNext.Image = ((System.Drawing.Image)(resources.GetObject("findNextToolStripMenuItem.Image"))); + this._menuItemFindNext.Name = "findNextToolStripMenuItem"; + this._menuItemFindNext.ShortcutKeys = System.Windows.Forms.Keys.F3; + this._menuItemFindNext.Size = new System.Drawing.Size(146, 22); + this._menuItemFindNext.Text = "Find Next"; // // helpToolStripMenuItem // @@ -661,18 +661,18 @@ private System.Windows.Forms.ImageList imageList1; private System.Windows.Forms.ToolStripButton _buttonAddTagString; private System.Windows.Forms.ToolStripMenuItem _menuItemAbout; - private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem openFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem _menuItemOpen; + private System.Windows.Forms.ToolStripMenuItem _menuItemOpenFolder; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; - private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem _menuItemSave; private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; private System.Windows.Forms.ToolStripMenuItem _menuItemExit; private System.Windows.Forms.ToolStripMenuItem _menuItemFind; - private System.Windows.Forms.ToolStripMenuItem findNextToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem _menuItemFindNext; private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; private System.Windows.Forms.ToolStripButton _buttonFindNext; private System.Windows.Forms.ToolStripButton _buttonOpenFolder; - private System.Windows.Forms.ToolStripMenuItem openMinecraftSaveFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem _menuItemOpenMinecraftSaveFolder; private System.Windows.Forms.ToolStripPanel BottomToolStripPanel; private System.Windows.Forms.ToolStripPanel TopToolStripPanel; private System.Windows.Forms.ToolStripPanel RightToolStripPanel; diff --git a/MainForm.cs b/MainForm.cs index 6953fb4..1780b0f 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; +using System.Threading; using System.Windows.Forms; -using Substrate; -using Substrate.Core; -using Substrate.Nbt; +using NBTExplorer.Forms; using NBTExplorer.Model; +using Substrate.Nbt; namespace NBTExplorer { @@ -15,6 +16,8 @@ namespace NBTExplorer private IconRegistry _iconRegistry; + private string _openFolderPath = null; + static MainForm () { _tagIconIndex = new Dictionary(); @@ -36,10 +39,18 @@ namespace NBTExplorer InitializeComponent(); InitializeIconRegistry(); + FormClosing += MainForm_Closing; + _nodeTree.BeforeExpand += _nodeTree_BeforeExpand; + _nodeTree.AfterCollapse += _nodeTree_AfterCollapse; _nodeTree.AfterSelect += _nodeTree_AfterSelect; _nodeTree.NodeMouseDoubleClick += _nodeTree_NodeMouseDoubleClick; + _nodeTree.DragEnter += _nodeTree_DragEnter; + _nodeTree.DragDrop += _nodeTree_DragDrop; + _buttonOpen.Click += _buttonOpen_Click; + _buttonOpenFolder.Click += _buttonOpenFolder_Click; + _buttonSave.Click += _buttonSave_Click; _buttonEdit.Click += _buttonEdit_Click; _buttonRename.Click += _buttonRename_Click; _buttonDelete.Click += _buttonDelete_Click; @@ -57,7 +68,12 @@ namespace NBTExplorer _buttonAddTagLong.Click += _buttonAddTagLong_Click; _buttonAddTagShort.Click += _buttonAddTagShort_Click; _buttonAddTagString.Click += _buttonAddTagString_Click; + _buttonFindNext.Click += _buttonFindNext_Click; + _menuItemOpen.Click += _menuItemOpen_Click; + _menuItemOpenFolder.Click += _menuItemOpenFolder_Click; + _menuItemOpenMinecraftSaveFolder.Click += _menuItemOpenMinecraftSaveFolder_Click; + _menuItemSave.Click += _menuItemSave_Click; _menuItemExit.Click += _menuItemExit_Click; _menuItemEditValue.Click += _menuItemEditValue_Click; _menuItemRename.Click += _menuItemRename_Click; @@ -65,27 +81,15 @@ namespace NBTExplorer _menuItemCopy.Click += _menuItemCopy_Click; _menuItemCut.Click += _menuItemCut_Click; _menuItemPaste.Click += _menuItemPaste_Click; + _menuItemFind.Click += _menuItemFind_Click; + _menuItemFindNext.Click += _menuItemFindNext_Click; _menuItemAbout.Click += _menuItemAbout_Click; - /*_nodeTree.BeforeExpand += NodeExpand; - _nodeTree.AfterCollapse += NodeCollapse; - _nodeTree.AfterSelect += NodeSelected; - _nodeTree.NodeMouseClick += NodeClicked; - _nodeTree.NodeMouseDoubleClick += NodeDoubleClicked; - string[] args = Environment.GetCommandLineArgs(); if (args.Length > 1) { - OpenFile(args[1]); - } - else { - OpenMinecraftDir(); - }*/ - - //OpenDirectory(@"F:\Minecraft\tps"); - - string[] args = Environment.GetCommandLineArgs(); - if (args.Length > 1) { - OpenFile(args[1]); + string[] paths = new string[args.Length - 1]; + Array.Copy(args, 1, paths, 0, paths.Length); + OpenPaths(paths); } else { OpenMinecraftDirectory(); @@ -114,26 +118,47 @@ namespace NBTExplorer _iconRegistry.Register(typeof(TagIntArrayDataNode), 14); } - private void OpenFile (string path) + public void OpenFile () { - _nodeTree.Nodes.Clear(); + OpenFileDialog ofd = new OpenFileDialog(); + ofd.RestoreDirectory = true; + ofd.Multiselect = true; - NbtFileDataNode node = NbtFileDataNode.TryCreateFrom(path); - - _nodeTree.Nodes.Add(CreateUnexpandedNode(node)); + if (ofd.ShowDialog() == DialogResult.OK) { + OpenPaths(ofd.FileNames); + } } - private void OpenDirectory (string path) + private void OpenFolder () + { + FolderBrowserDialog ofd = new FolderBrowserDialog(); + if (_openFolderPath != null) + ofd.SelectedPath = _openFolderPath; + + if (ofd.ShowDialog() == DialogResult.OK) { + _openFolderPath = ofd.SelectedPath; + OpenPaths(new string[] { ofd.SelectedPath }); + } + } + + public void OpenPaths (string[] paths) { _nodeTree.Nodes.Clear(); - DirectoryDataNode node = new DirectoryDataNode(path); + foreach (string path in paths) { + if (Directory.Exists(path)) { + DirectoryDataNode node = new DirectoryDataNode(path); + _nodeTree.Nodes.Add(CreateUnexpandedNode(node)); + } + else if (File.Exists(path)) { + NbtFileDataNode node = NbtFileDataNode.TryCreateFrom(path); + _nodeTree.Nodes.Add(CreateUnexpandedNode(node)); + } + } - TreeNode frontNode = CreateUnexpandedNode(node); - _nodeTree.Nodes.Add(frontNode); - - ExpandNode(frontNode); - frontNode.Expand(); + if (_nodeTree.Nodes.Count > 0) { + _nodeTree.Nodes[0].Expand(); + } } private void OpenMinecraftDirectory () @@ -147,12 +172,12 @@ namespace NBTExplorer path = Environment.GetFolderPath(Environment.SpecialFolder.MyComputer); } - OpenDirectory(path); + OpenPaths(new string[] { path }); } catch (Exception) { MessageBox.Show("Could not open default Minecraft save directory"); try { - OpenDirectory(Directory.GetCurrentDirectory()); + OpenPaths(new string[] { Directory.GetCurrentDirectory() }); } catch (Exception) { MessageBox.Show("Could not open current directory, this tool is probably not compatible with your platform."); @@ -179,12 +204,12 @@ namespace NBTExplorer if (node == null || !(node.Tag is DataNode)) return; - DataNode backNode = node.Tag as DataNode; - if (!backNode.HasUnexpandedChildren) + if (node.IsExpanded) return; node.Nodes.Clear(); + DataNode backNode = node.Tag as DataNode; if (!backNode.IsExpanded) backNode.Expand(); @@ -192,6 +217,22 @@ namespace NBTExplorer node.Nodes.Add(CreateUnexpandedNode(child)); } + private void CollapseNode (TreeNode node) + { + if (node == null || !(node.Tag is DataNode)) + return; + + DataNode backNode = node.Tag as DataNode; + if (backNode.IsModified) + return; + + backNode.Collapse(); + + node.Nodes.Clear(); + if (backNode.HasUnexpandedChildren) + node.Nodes.Add(new TreeNode()); + } + private void CreateNode (TreeNode node, TagType type) { if (node == null || !(node.Tag is DataNode)) @@ -244,6 +285,7 @@ namespace NBTExplorer if (dataNode.EditNode()) { node.Text = dataNode.NodeDisplay; + UpdateUI(dataNode); } } @@ -321,6 +363,167 @@ namespace NBTExplorer } } + private void Save () + { + foreach (TreeNode node in _nodeTree.Nodes) { + DataNode dataNode = node.Tag as DataNode; + if (dataNode != null) + dataNode.Save(); + } + + UpdateUI(); + } + + private bool ConfirmExit () + { + if (CheckModifications()) { + if (MessageBox.Show("You currently have unsaved changes. Close anyway?", "Unsaved Changes", MessageBoxButtons.OKCancel) != DialogResult.OK) + return false; + } + + return true; + } + + private CancelSearchForm _searchForm; + private SearchState _searchState; + + private void SearchNode (TreeNode node) + { + if (node == null || !(node.Tag is DataNode)) + return; + + DataNode dataNode = node.Tag as DataNode; + if (!dataNode.CanSearchNode) + return; + + Find form = new Find(); + if (form.ShowDialog() != DialogResult.OK) + return; + + _searchState = new SearchState() { + RootNode = dataNode, + SearchName = form.NameToken, + SearchValue = form.ValueToken, + DiscoverCallback = SearchDiscoveryCallback, + CollapseCallback = SearchCollapseCallback, + EndCallback = SearchEndCallback, + }; + + SearchNextNode(); + } + + private void SearchNextNode () + { + if (_searchState == null) + return; + + SearchWorker worker = new SearchWorker(_searchState, this); + + Thread t = new Thread(new ThreadStart(worker.Run)); + t.IsBackground = true; + t.Start(); + + _searchForm = new CancelSearchForm(); + if (_searchForm.ShowDialog(this) == DialogResult.Cancel) { + worker.Cancel(); + _searchState = null; + } + + t.Join(); + } + + private void SearchDiscoveryCallback (DataNode node) + { + _nodeTree.SelectedNode = FindFrontNode(node); + + if (_searchForm != null) { + _searchForm.DialogResult = DialogResult.OK; + _searchForm = null; + } + } + + private void SearchCollapseCallback (DataNode node) + { + CollapseBelow(node); + } + + private void SearchEndCallback () + { + _searchForm.DialogResult = DialogResult.OK; + _searchForm = null; + + MessageBox.Show("End of results"); + } + + private TreeNode GetRootFromDataNodePath (DataNode node, out Stack hierarchy) + { + hierarchy = new Stack(); + while (node != null) { + hierarchy.Push(node); + node = node.Parent; + } + + DataNode rootDataNode = hierarchy.Pop(); + TreeNode frontNode = null; + foreach (TreeNode child in _nodeTree.Nodes) { + if (child.Tag == rootDataNode) + frontNode = child; + } + + return frontNode; + } + + private TreeNode FindFrontNode (DataNode node) + { + Stack hierarchy; + TreeNode frontNode = GetRootFromDataNodePath(node, out hierarchy); + + if (frontNode == null) + return null; + + while (hierarchy.Count > 0) { + if (!frontNode.IsExpanded) { + frontNode.Nodes.Add(new TreeNode()); + frontNode.Expand(); + } + + DataNode childData = hierarchy.Pop(); + foreach (TreeNode childFront in frontNode.Nodes) { + if (childFront.Tag == childData) { + frontNode = childFront; + break; + } + } + } + + return frontNode; + } + + private void CollapseBelow (DataNode node) + { + Stack hierarchy; + TreeNode frontNode = GetRootFromDataNodePath(node, out hierarchy); + + if (frontNode == null) + return; + + while (hierarchy.Count > 0) { + if (!frontNode.IsExpanded) + return; + + DataNode childData = hierarchy.Pop(); + foreach (TreeNode childFront in frontNode.Nodes) { + if (childFront.Tag == childData) { + frontNode = childFront; + break; + } + } + } + + if (frontNode.IsExpanded) + frontNode.Collapse(); + } + private void UpdateNodeText (TreeNode node) { if (node == null || !(node.Tag is DataNode)) @@ -330,6 +533,33 @@ namespace NBTExplorer node.Text = dataNode.NodeDisplay; } + private bool CheckModifications () + { + foreach (TreeNode node in _nodeTree.Nodes) { + DataNode dataNode = node.Tag as DataNode; + if (dataNode != null && dataNode.IsModified) + return true; + } + + return false; + } + + private void UpdateUI () + { + TreeNode selected = _nodeTree.SelectedNode; + if (selected != null && selected.Tag is DataNode) { + UpdateUI(selected.Tag as DataNode); + } + else { + _buttonSave.Enabled = CheckModifications(); + _buttonFindNext.Enabled = false; + + _menuItemSave.Enabled = _buttonSave.Enabled; + _menuItemFind.Enabled = false; + _menuItemFindNext.Enabled = _searchState != null; + } + } + private void UpdateUI (DataNode node) { if (node == null) @@ -347,25 +577,35 @@ namespace NBTExplorer _buttonAddTagShort.Enabled = node.CanCreateTag(TagType.TAG_SHORT); _buttonAddTagString.Enabled = node.CanCreateTag(TagType.TAG_STRING); + _buttonSave.Enabled = CheckModifications(); _buttonCopy.Enabled = node.CanCopyNode; _buttonCut.Enabled = node.CanCutNode; _buttonDelete.Enabled = node.CanDeleteNode; _buttonEdit.Enabled = node.CanEditNode; - _buttonFindNext.Enabled = node.CanSearchNode; // Not entirely - _buttonPaste.Enabled = node.CanPasteIntoNode; // Not entirely + _buttonFindNext.Enabled = node.CanSearchNode || _searchState != null; + _buttonPaste.Enabled = node.CanPasteIntoNode; _buttonRename.Enabled = node.CanRenameNode; + _menuItemSave.Enabled = _buttonSave.Enabled; _menuItemCopy.Enabled = node.CanCopyNode; _menuItemCut.Enabled = node.CanCutNode; _menuItemDelete.Enabled = node.CanDeleteNode; _menuItemEditValue.Enabled = node.CanEditNode; _menuItemFind.Enabled = node.CanSearchNode; - _menuItemPaste.Enabled = node.CanPasteIntoNode; // Not entirely + _menuItemPaste.Enabled = node.CanPasteIntoNode; _menuItemRename.Enabled = node.CanRenameNode; + _menuItemFind.Enabled = node.CanSearchNode; + _menuItemFindNext.Enabled = _searchState != null; } #region Event Handlers + private void MainForm_Closing (object sender, CancelEventArgs e) + { + if (!ConfirmExit()) + e.Cancel = true; + } + #region TreeView Event Handlers private void _nodeTree_BeforeExpand (object sender, TreeViewCancelEventArgs e) @@ -373,9 +613,15 @@ namespace NBTExplorer ExpandNode(e.Node); } + private void _nodeTree_AfterCollapse (object sender, TreeViewEventArgs e) + { + CollapseNode(e.Node); + } + private void _nodeTree_AfterSelect (object sender, TreeViewEventArgs e) { - UpdateUI(e.Node.Tag as DataNode); + if (e.Node != null) + UpdateUI(e.Node.Tag as DataNode); } private void _nodeTree_NodeMouseDoubleClick (object sender, TreeNodeMouseClickEventArgs e) @@ -383,10 +629,36 @@ namespace NBTExplorer EditNode(e.Node); } + private void _nodeTree_DragDrop (object sender, DragEventArgs e) + { + OpenPaths((string[])e.Data.GetData(DataFormats.FileDrop)); + } + + private void _nodeTree_DragEnter (object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + e.Effect = DragDropEffects.Copy; + } + #endregion #region Toolstrip Event Handlers + private void _buttonOpen_Click (object sender, EventArgs e) + { + OpenFile(); + } + + private void _buttonOpenFolder_Click (object sender, EventArgs e) + { + OpenFolder(); + } + + private void _buttonSave_Click (object sender, EventArgs e) + { + Save(); + } + private void _buttonEdit_Click (object sender, EventArgs e) { EditNode(_nodeTree.SelectedNode); @@ -472,10 +744,38 @@ namespace NBTExplorer CreateNode(_nodeTree.SelectedNode, TagType.TAG_STRING); } + private void _buttonFindNext_Click (object sender, EventArgs e) + { + if (_searchState != null) + SearchNextNode(); + else + SearchNode(_nodeTree.SelectedNode); + } + #endregion #region Menu Event Handlers + private void _menuItemOpen_Click (object sender, EventArgs e) + { + OpenFile(); + } + + private void _menuItemOpenFolder_Click (object sender, EventArgs e) + { + OpenFolder(); + } + + private void _menuItemOpenMinecraftSaveFolder_Click (object sender, EventArgs e) + { + OpenMinecraftDirectory(); + } + + private void _menuItemSave_Click (object sender, EventArgs e) + { + Save(); + } + private void _menuItemExit_Click (object sender, EventArgs e) { Close(); @@ -508,7 +808,17 @@ namespace NBTExplorer private void _menuItemPaste_Click (object sender, EventArgs e) { - PasteNode(_nodeTree.SelectedNode); + PasteNode(_nodeTree.SelectedNode); + } + + private void _menuItemFind_Click (object sender, EventArgs e) + { + SearchNode(_nodeTree.SelectedNode); + } + + private void _menuItemFindNext_Click (object sender, EventArgs e) + { + SearchNextNode(); } private void _menuItemAbout_Click (object sender, EventArgs e) @@ -520,4 +830,118 @@ namespace NBTExplorer #endregion } + + internal class SearchState + { + public DataNode RootNode { get; set; } + public string SearchName { get; set; } + public string SearchValue { get; set; } + + public IEnumerator State { get; set; } + + public Action DiscoverCallback { get; set; } + public Action ProgressCallback { get; set; } + public Action CollapseCallback { get; set; } + public Action EndCallback { get; set; } + } + + internal class SearchWorker + { + private ContainerControl _sender; + private SearchState _state; + private bool _cancel; + private object _lock; + + public SearchWorker (SearchState state, ContainerControl sender) + { + _state = state; + _sender = sender; + _lock = new object(); + } + + public void Cancel () + { + lock (_lock) { + _cancel = true; + } + } + + public void Run () + { + if (_state.State == null) + _state.State = FindNode(_state.RootNode).GetEnumerator(); + + if (!_state.State.MoveNext()) + InvokeEndCallback(); + } + + private IEnumerable FindNode (DataNode node) + { + lock (_lock) { + if (_cancel) + yield break; + } + + if (node == null) + yield break; + + bool searchExpanded = false; + if (!node.IsExpanded) { + node.Expand(); + searchExpanded = true; + } + + TagDataNode tagNode = node as TagDataNode; + if (tagNode != null) { + bool mName = _state.SearchName == null; + bool mValue = _state.SearchValue == null; + + if (_state.SearchName != null) { + string tagName = node.NodeName; + if (tagName != null) + mName = tagName.Contains(_state.SearchName); + } + if (_state.SearchValue != null) { + string tagValue = node.NodeDisplay; + if (tagValue != null) + mValue = tagValue.Contains(_state.SearchValue); + } + + if (mName && mValue) { + InvokeDiscoverCallback(node); + yield return node; + } + } + + foreach (DataNode sub in node.Nodes) { + foreach (DataNode s in FindNode(sub)) + yield return s; + } + + if (searchExpanded) { + if (!node.IsModified) { + node.Collapse(); + InvokeCollapseCallback(node); + } + } + } + + private void InvokeDiscoverCallback (DataNode node) + { + if (_sender != null && _state.DiscoverCallback != null) + _sender.BeginInvoke(_state.DiscoverCallback, new object[] { node }); + } + + private void InvokeCollapseCallback (DataNode node) + { + if (_sender != null && _state.CollapseCallback != null) + _sender.BeginInvoke(_state.CollapseCallback, new object[] { node }); + } + + private void InvokeEndCallback () + { + if (_sender != null && _state.EndCallback != null) + _sender.BeginInvoke(_state.EndCallback); + } + } } diff --git a/Model/DataNode.cs b/Model/DataNode.cs index 0495047..3aac21a 100644 --- a/Model/DataNode.cs +++ b/Model/DataNode.cs @@ -75,6 +75,20 @@ namespace NBTExplorer.Model Nodes.Clear(); } + public void Save () + { + foreach (DataNode node in Nodes) + if (node.IsModified) + node.Save(); + + SaveCore(); + IsModified = false; + } + + protected virtual void SaveCore () + { + } + public virtual string NodeName { get { return ""; } diff --git a/Model/NbtFileDataNode.cs b/Model/NbtFileDataNode.cs index 3fe0e9e..177c79a 100644 --- a/Model/NbtFileDataNode.cs +++ b/Model/NbtFileDataNode.cs @@ -91,6 +91,14 @@ namespace NBTExplorer.Model Nodes.Clear(); } + protected override void SaveCore () + { + NBTFile file = new NBTFile(_path); + using (Stream str = file.GetDataOutputStream(_compressionType)) { + _tree.WriteTo(str); + } + } + public bool IsNamedContainer { get { return true; } diff --git a/Model/RegionChunkDataNode.cs b/Model/RegionChunkDataNode.cs index da56b7c..02be164 100644 --- a/Model/RegionChunkDataNode.cs +++ b/Model/RegionChunkDataNode.cs @@ -1,5 +1,6 @@ using Substrate.Core; using Substrate.Nbt; +using System.IO; namespace NBTExplorer.Model { @@ -63,6 +64,13 @@ namespace NBTExplorer.Model Nodes.Clear(); } + protected override void SaveCore () + { + using (Stream str = _regionFile.GetChunkDataOutputStream(_x, _z)) { + _tree.WriteTo(str); + } + } + public bool IsNamedContainer { get { return true; } diff --git a/Model/TagDataNode.cs b/Model/TagDataNode.cs index c4e8799..6efaa07 100644 --- a/Model/TagDataNode.cs +++ b/Model/TagDataNode.cs @@ -304,10 +304,20 @@ namespace NBTExplorer.Model : base(tag) { } + protected new TagNodeByte Tag + { + get { return base.Tag as TagNodeByte; } + } + public override bool EditNode () { return EditScalarValue(Tag); } + + public override string NodeDisplay + { + get { return NodeDisplayPrefix + unchecked((sbyte)Tag.Data).ToString(); } + } } public class TagShortDataNode : TagDataNode diff --git a/NBTExplorer.csproj b/NBTExplorer.csproj index d122582..d503765 100644 --- a/NBTExplorer.csproj +++ b/NBTExplorer.csproj @@ -48,6 +48,12 @@ + + Form + + + CancelSearchForm.cs + Form @@ -141,6 +147,9 @@ + + CancelSearchForm.cs + MainForm.cs Designer diff --git a/forms/CancelSearchForm.Designer.cs b/forms/CancelSearchForm.Designer.cs new file mode 100644 index 0000000..8a8c5de --- /dev/null +++ b/forms/CancelSearchForm.Designer.cs @@ -0,0 +1,63 @@ +namespace NBTExplorer.Forms +{ + partial class CancelSearchForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose (bool disposing) + { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent () + { + this._buttonCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // _buttonCancel + // + this._buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this._buttonCancel.Location = new System.Drawing.Point(124, 57); + this._buttonCancel.Name = "_buttonCancel"; + this._buttonCancel.Size = new System.Drawing.Size(75, 23); + this._buttonCancel.TabIndex = 0; + this._buttonCancel.Text = "Cancel"; + this._buttonCancel.UseVisualStyleBackColor = true; + // + // CancelSearchForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this._buttonCancel; + this.ClientSize = new System.Drawing.Size(322, 92); + this.Controls.Add(this._buttonCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CancelSearchForm"; + this.Text = "Searching..."; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button _buttonCancel; + } +} \ No newline at end of file diff --git a/forms/CancelSearchForm.cs b/forms/CancelSearchForm.cs new file mode 100644 index 0000000..794d393 --- /dev/null +++ b/forms/CancelSearchForm.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace NBTExplorer.Forms +{ + public partial class CancelSearchForm : Form + { + public CancelSearchForm () + { + InitializeComponent(); + } + } +} diff --git a/forms/CancelSearchForm.resx b/forms/CancelSearchForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/forms/CancelSearchForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/forms/EditValue.cs b/forms/EditValue.cs index f41cb2f..8d61064 100644 --- a/forms/EditValue.cs +++ b/forms/EditValue.cs @@ -50,7 +50,7 @@ namespace NBTExplorer try { switch (_tag.GetTagType()) { case TagType.TAG_BYTE: - _tag.ToTagByte().Data = byte.Parse(textBox1.Text); + _tag.ToTagByte().Data = unchecked((byte)sbyte.Parse(textBox1.Text)); break; case TagType.TAG_SHORT: