diff --git a/Controllers/NodeTreeController.cs b/Controllers/NodeTreeController.cs index fbfc160..ce8a2a4 100644 --- a/Controllers/NodeTreeController.cs +++ b/Controllers/NodeTreeController.cs @@ -120,10 +120,12 @@ namespace NBTExplorer.Controllers OnSelectionInvalidated(); } - public void OpenPaths (string[] paths) + public int OpenPaths (string[] paths) { _nodeTree.Nodes.Clear(); + int failCount = 0; + foreach (string path in paths) { if (Directory.Exists(path)) { DirectoryDataNode node = new DirectoryDataNode(path); @@ -136,9 +138,10 @@ namespace NBTExplorer.Controllers node = item.Value.NodeCreate(path); } - if (node != null) { + if (node != null) _nodeTree.Nodes.Add(CreateUnexpandedNode(node)); - } + else + failCount++; } } @@ -147,6 +150,8 @@ namespace NBTExplorer.Controllers } OnSelectionInvalidated(); + + return failCount; } #endregion @@ -452,8 +457,10 @@ namespace NBTExplorer.Controllers node.Nodes.Clear(); DataNode backNode = node.Tag as DataNode; - if (!backNode.IsExpanded) + if (!backNode.IsExpanded) { backNode.Expand(); + node.Text = backNode.NodeDisplay; + } foreach (DataNode child in backNode.Nodes) node.Nodes.Add(CreateUnexpandedNode(child)); @@ -476,6 +483,7 @@ namespace NBTExplorer.Controllers return; backNode.Collapse(); + node.Name = backNode.NodeDisplay; node.Nodes.Clear(); if (backNode.HasUnexpandedChildren) @@ -613,8 +621,8 @@ namespace NBTExplorer.Controllers node.Nodes.Add(currentNodes[child]); } - //foreach (TreeNode child in node.Nodes) - // child.ContextMenuStrip = BuildNodeContextMenu(child.Tag as DataNode); + foreach (TreeNode child in node.Nodes) + child.ContextMenuStrip = BuildNodeContextMenu(child, child.Tag as DataNode); if (node.Nodes.Count == 0 && dataNode.HasUnexpandedChildren) { ExpandNode(node); @@ -686,6 +694,84 @@ namespace NBTExplorer.Controllers return frontNode; } + public ContextMenuStrip BuildNodeContextMenu (TreeNode frontNode, DataNode node) + { + if (node == null) + return null; + + ContextMenuStrip menu = new ContextMenuStrip(); + + if (node.HasUnexpandedChildren || node.Nodes.Count > 0) { + if (frontNode.IsExpanded) { + ToolStripMenuItem itemCollapse = new ToolStripMenuItem("&Collapse", null, _contextCollapse_Click); + itemCollapse.Font = new System.Drawing.Font(itemCollapse.Font, System.Drawing.FontStyle.Bold); + + ToolStripMenuItem itemExpandChildren = new ToolStripMenuItem("Expand C&hildren", null, _contextExpandChildren_Click); + ToolStripMenuItem itemExpandTree = new ToolStripMenuItem("Expand &Tree", null, _contextExpandTree_Click); + + menu.Items.AddRange(new ToolStripItem[] { + itemCollapse, new ToolStripSeparator(), itemExpandChildren, itemExpandTree, + }); + } + else { + ToolStripMenuItem itemExpand = new ToolStripMenuItem("&Expand", null, _contextExpand_Click); + itemExpand.Font = new System.Drawing.Font(itemExpand.Font, System.Drawing.FontStyle.Bold); + + menu.Items.Add(itemExpand); + } + } + + if (node.CanReoderNode) { + ToolStripMenuItem itemUp = new ToolStripMenuItem("Move &Up", Properties.Resources.ArrowUp, _contextMoveUp_Click); + ToolStripMenuItem itemDn = new ToolStripMenuItem("Move &Down", Properties.Resources.ArrowDown, _contextMoveDown_Click); + + itemUp.Enabled = node.CanMoveNodeUp; + itemDn.Enabled = node.CanMoveNodeDown; + + menu.Items.Add(itemUp); + menu.Items.Add(itemDn); + } + + return (menu.Items.Count > 0) ? menu : null; + } + + private void _contextCollapse_Click (object sender, EventArgs e) + { + if (_multiTree.SelectedNode != null) + _multiTree.SelectedNode.Collapse(); + } + + private void _contextExpand_Click (object sender, EventArgs e) + { + if (_multiTree.SelectedNode != null) + _multiTree.SelectedNode.Expand(); + } + + private void _contextExpandChildren_Click (object sender, EventArgs e) + { + if (_multiTree.SelectedNode != null) { + foreach (TreeNode node in _multiTree.SelectedNode.Nodes) + node.Expand(); + } + } + + private void _contextExpandTree_Click (object sender, EventArgs e) + { + if (_multiTree.SelectedNode != null) { + _multiTree.SelectedNode.ExpandAll(); + } + } + + private void _contextMoveUp_Click (object sender, EventArgs e) + { + MoveSelectionUp(); + } + + private void _contextMoveDown_Click (object sender, EventArgs e) + { + MoveSelectionDown(); + } + #region Capability Checking #region Capability Predicates diff --git a/FormRegistry.cs b/FormRegistry.cs index eab7a84..9475493 100644 --- a/FormRegistry.cs +++ b/FormRegistry.cs @@ -39,6 +39,7 @@ namespace NBTExplorer } public String Value { get; set; } + public bool AllowEmpty { get; set; } } public class RestrictedStringFormData : StringFormData diff --git a/Model/NbtFileDataNode.cs b/Model/NbtFileDataNode.cs index af1ced2..edf10dc 100644 --- a/Model/NbtFileDataNode.cs +++ b/Model/NbtFileDataNode.cs @@ -3,6 +3,7 @@ using System.Text.RegularExpressions; using Substrate.Core; using Substrate.Nbt; using System.Collections.Generic; +using System; namespace NBTExplorer.Model { @@ -59,7 +60,8 @@ namespace NBTExplorer.Model return NodeCapabilities.CreateTag | NodeCapabilities.PasteInto | NodeCapabilities.Search - | NodeCapabilities.Refresh; + | NodeCapabilities.Refresh + | NodeCapabilities.Rename; } } @@ -70,7 +72,17 @@ namespace NBTExplorer.Model public override string NodeDisplay { - get { return NodeName; } + get + { + if (_tree != null && _tree.Root != null) { + if (!string.IsNullOrEmpty(_tree.Name)) + return NodeName + " [" + _tree.Name + ": " + _tree.Root.Count + " entries]"; + else + return NodeName + " [" + _tree.Root.Count + " entries]"; + } + else + return NodeName; + } } public override bool HasUnexpandedChildren @@ -85,11 +97,17 @@ namespace NBTExplorer.Model _tree = new NbtTree(); _tree.ReadFrom(file.GetDataInputStream(_compressionType)); - if (_tree.Root != null) + if (_tree.Root != null) { _container = new CompoundTagContainer(_tree.Root); + } } - foreach (TagNode tag in _tree.Root.Values) { + var list = new SortedList(); + foreach (var item in _tree.Root) { + list.Add(new TagKey(item.Key, item.Value.GetTagType()), item.Value); + } + + foreach (TagNode tag in list.Values) { TagDataNode node = TagDataNode.CreateFromTag(tag); if (node != null) Nodes.Add(node); @@ -119,6 +137,78 @@ namespace NBTExplorer.Model return true; } + public override bool CanRenameNode + { + get { return _tree != null; } + } + + public override bool RenameNode () + { + if (CanRenameNode && FormRegistry.EditString != null) { + RestrictedStringFormData data = new RestrictedStringFormData(_tree.Name ?? "") { + AllowEmpty = true, + }; + + if (FormRegistry.RenameTag(data)) { + if (_tree.Name != data.Value) { + _tree.Name = data.Value; + IsDataModified = true; + return true; + } + } + } + + return false; + } + + public override bool CanCreateTag (TagType type) + { + return _tree != null && _tree.Root != null && Enum.IsDefined(typeof(TagType), type) && type != TagType.TAG_END; + } + + public override bool CanPasteIntoNode + { + get { return _tree != null && _tree.Root != null && NbtClipboardController.ContainsData; } + } + + public override bool CreateNode (TagType type) + { + if (!CanCreateTag(type)) + return false; + + if (FormRegistry.CreateNode != null) { + CreateTagFormData data = new CreateTagFormData() { + TagType = type, + HasName = true, + }; + data.RestrictedNames.AddRange(_container.TagNamesInUse); + + if (FormRegistry.CreateNode(data)) { + AddTag(data.TagNode, data.TagName); + return true; + } + } + + return false; + } + + public override bool PasteNode () + { + if (!CanPasteIntoNode) + return false; + + NbtClipboardData clipboard = NbtClipboardController.CopyFromClipboard(); + if (clipboard == null || clipboard.Node == null) + return false; + + string name = clipboard.Name; + if (String.IsNullOrEmpty(name)) + name = "UNNAMED"; + + AddTag(clipboard.Node, MakeUniqueName(name)); + return true; + } + public bool IsNamedContainer { get { return true; } @@ -148,5 +238,35 @@ namespace NBTExplorer.Model { return _container.DeleteTag(tag); } + + private void AddTag (TagNode tag, string name) + { + _container.AddTag(tag, name); + IsDataModified = true; + + if (IsExpanded) { + TagDataNode node = TagDataNode.CreateFromTag(tag); + if (node != null) + Nodes.Add(node); + } + } + + private string MakeUniqueName (string name) + { + List names = new List(_container.TagNamesInUse); + if (!names.Contains(name)) + return name; + + int index = 1; + while (names.Contains(MakeCandidateName(name, index))) + index++; + + return MakeCandidateName(name, index); + } + + private string MakeCandidateName (string name, int index) + { + return name + " (Copy " + index + ")"; + } } } diff --git a/Model/TagDataNode.cs b/Model/TagDataNode.cs index 8124aa2..8c52ff5 100644 --- a/Model/TagDataNode.cs +++ b/Model/TagDataNode.cs @@ -319,7 +319,8 @@ namespace NBTExplorer.Model }; if (FormRegistry.EditByteArray(data)) { - Array.Copy(data.Data, tag.ToTagByteArray().Data, tag.ToTagByteArray().Length); + tag.ToTagByteArray().Data = data.Data; + //Array.Copy(data.Data, tag.ToTagByteArray().Data, tag.ToTagByteArray().Length); IsDataModified = true; return true; } @@ -345,6 +346,7 @@ namespace NBTExplorer.Model }; if (FormRegistry.EditByteArray(data)) { + iatag.Data = new int[data.Data.Length / 4]; for (int i = 0; i < iatag.Length; i++) { iatag.Data[i] = BitConverter.ToInt32(data.Data, i * 4); } diff --git a/NBTExplorer.csproj b/NBTExplorer.csproj index 9b94b1a..e4742fe 100644 --- a/NBTExplorer.csproj +++ b/NBTExplorer.csproj @@ -70,14 +70,15 @@ 4 + + False + References\Substrate.dll + - - ..\Substrate\SubstrateCS\bin\Release\NET2\Substrate.dll - diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index b55c05a..c2bbd9a 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.2.0.0")] -[assembly: AssemblyFileVersion("2.2.0.0")] +[assembly: AssemblyVersion("2.4.0.0")] +[assembly: AssemblyFileVersion("2.4.0.0")] diff --git a/References/Substrate.dll b/References/Substrate.dll new file mode 100644 index 0000000..1e77d6c Binary files /dev/null and b/References/Substrate.dll differ diff --git a/Vendor/MultiSelectTreeView/MultiSelectTreeview.cs b/Vendor/MultiSelectTreeView/MultiSelectTreeview.cs index c9a1651..db22de9 100644 --- a/Vendor/MultiSelectTreeView/MultiSelectTreeview.cs +++ b/Vendor/MultiSelectTreeView/MultiSelectTreeview.cs @@ -23,6 +23,8 @@ namespace NBTExplorer.Vendor.MultiSelectTreeView } set { + BeginUpdate(); + ClearSelectedNodes(); if( value != null ) { @@ -31,6 +33,8 @@ namespace NBTExplorer.Vendor.MultiSelectTreeView ToggleNode( node, true ); } } + + EndUpdate(); } } @@ -53,6 +57,8 @@ namespace NBTExplorer.Vendor.MultiSelectTreeView public MultiSelectTreeView() { + SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); + m_SelectedNodes = new List(); base.SelectedNode = null; } @@ -583,5 +589,17 @@ namespace NBTExplorer.Vendor.MultiSelectTreeView } #endregion + + private const int WM_ERASEBKGND = 0x14; + + protected override void WndProc (ref Message m) + { + if (m.Msg == WM_ERASEBKGND) //if message is is erase background + { + return; + } + + base.WndProc(ref m); + } } } diff --git a/Windows/EditHex.Designer.cs b/Windows/EditHex.Designer.cs index a971eab..1df36d4 100644 --- a/Windows/EditHex.Designer.cs +++ b/Windows/EditHex.Designer.cs @@ -27,36 +27,26 @@ /// private void InitializeComponent () { - this.hexBox1 = new Be.Windows.Forms.HexBox(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this._curPositionLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this._curElementLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this._space = new System.Windows.Forms.ToolStripStatusLabel(); + this._insertStateLabel = new System.Windows.Forms.ToolStripStatusLabel(); this._buttonCancel = new System.Windows.Forms.Button(); this._buttonOK = new System.Windows.Forms.Button(); - this._curElementLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.hexBox1 = new Be.Windows.Forms.HexBox(); + this._buttonImport = new System.Windows.Forms.Button(); + this._buttonExport = new System.Windows.Forms.Button(); this.statusStrip1.SuspendLayout(); this.SuspendLayout(); // - // hexBox1 - // - this.hexBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.hexBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.hexBox1.LineInfoForeColor = System.Drawing.Color.Empty; - this.hexBox1.LineInfoVisible = true; - this.hexBox1.Location = new System.Drawing.Point(12, 12); - this.hexBox1.Name = "hexBox1"; - this.hexBox1.ReadOnly = true; - this.hexBox1.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255))))); - this.hexBox1.Size = new System.Drawing.Size(492, 289); - this.hexBox1.TabIndex = 0; - this.hexBox1.VScrollBarVisible = true; - // // statusStrip1 // this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this._curPositionLabel, - this._curElementLabel}); + this._curElementLabel, + this._space, + this._insertStateLabel}); this.statusStrip1.Location = new System.Drawing.Point(0, 333); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(516, 22); @@ -70,6 +60,25 @@ this._curPositionLabel.Size = new System.Drawing.Size(100, 17); this._curPositionLabel.Text = "0000"; // + // _curElementLabel + // + this._curElementLabel.Name = "_curElementLabel"; + this._curElementLabel.Size = new System.Drawing.Size(59, 17); + this._curElementLabel.Text = "Element 0"; + this._curElementLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // _space + // + this._space.Name = "_space"; + this._space.Size = new System.Drawing.Size(284, 17); + this._space.Spring = true; + // + // _insertStateLabel + // + this._insertStateLabel.Name = "_insertStateLabel"; + this._insertStateLabel.Size = new System.Drawing.Size(58, 17); + this._insertStateLabel.Text = "Overwrite"; + // // _buttonCancel // this._buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -92,12 +101,41 @@ this._buttonOK.UseVisualStyleBackColor = true; this._buttonOK.Click += new System.EventHandler(this._buttonOK_Click); // - // _curElementLabel + // hexBox1 // - this._curElementLabel.Name = "_curElementLabel"; - this._curElementLabel.Size = new System.Drawing.Size(59, 17); - this._curElementLabel.Text = "Element 0"; - this._curElementLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.hexBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.hexBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.hexBox1.LineInfoForeColor = System.Drawing.Color.Empty; + this.hexBox1.LineInfoVisible = true; + this.hexBox1.Location = new System.Drawing.Point(12, 12); + this.hexBox1.Name = "hexBox1"; + this.hexBox1.ReadOnly = true; + this.hexBox1.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255))))); + this.hexBox1.Size = new System.Drawing.Size(492, 289); + this.hexBox1.TabIndex = 0; + this.hexBox1.VScrollBarVisible = true; + // + // _buttonImport + // + this._buttonImport.Location = new System.Drawing.Point(12, 307); + this._buttonImport.Name = "_buttonImport"; + this._buttonImport.Size = new System.Drawing.Size(75, 23); + this._buttonImport.TabIndex = 14; + this._buttonImport.Text = "Import"; + this._buttonImport.UseVisualStyleBackColor = true; + this._buttonImport.Click += new System.EventHandler(this._buttonImport_Click); + // + // _buttonExport + // + this._buttonExport.Location = new System.Drawing.Point(93, 307); + this._buttonExport.Name = "_buttonExport"; + this._buttonExport.Size = new System.Drawing.Size(75, 23); + this._buttonExport.TabIndex = 15; + this._buttonExport.Text = "Export"; + this._buttonExport.UseVisualStyleBackColor = true; + this._buttonExport.Click += new System.EventHandler(this._buttonExport_Click); // // HexEditor // @@ -105,6 +143,8 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this._buttonCancel; this.ClientSize = new System.Drawing.Size(516, 355); + this.Controls.Add(this._buttonExport); + this.Controls.Add(this._buttonImport); this.Controls.Add(this._buttonCancel); this.Controls.Add(this._buttonOK); this.Controls.Add(this.statusStrip1); @@ -126,5 +166,9 @@ private System.Windows.Forms.Button _buttonCancel; private System.Windows.Forms.Button _buttonOK; private System.Windows.Forms.ToolStripStatusLabel _curElementLabel; + private System.Windows.Forms.ToolStripStatusLabel _space; + private System.Windows.Forms.ToolStripStatusLabel _insertStateLabel; + private System.Windows.Forms.Button _buttonImport; + private System.Windows.Forms.Button _buttonExport; } } \ No newline at end of file diff --git a/Windows/EditHex.cs b/Windows/EditHex.cs index 55eef29..9adce63 100644 --- a/Windows/EditHex.cs +++ b/Windows/EditHex.cs @@ -1,6 +1,10 @@ using System; using System.Windows.Forms; using Be.Windows.Forms; +using System.IO; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; namespace NBTExplorer.Windows { @@ -36,7 +40,7 @@ namespace NBTExplorer.Windows _data = new byte[data.Length]; Array.Copy(data, _data, data.Length); - _byteProvider = new FixedByteProvider(_data); + _byteProvider = new DynamicByteProvider(_data); _byteProvider.Changed += (o, e) => { _modified = true; }; hexBox1.ByteProvider = _byteProvider; @@ -44,6 +48,7 @@ namespace NBTExplorer.Windows hexBox1.HorizontalByteCountChanged += HexBox_HorizontalByteCountChanged; hexBox1.CurrentLineChanged += HexBox_CurrentLineChanged; hexBox1.CurrentPositionInLineChanged += HexBox_CurrentPositionInLineChanged; + hexBox1.InsertActiveChanged += HexBox_InsertActiveChanged; hexBox1.ReadOnly = false; } @@ -73,6 +78,14 @@ namespace NBTExplorer.Windows UpdatePosition(); } + private void HexBox_InsertActiveChanged (object sender, EventArgs e) + { + if (hexBox1.InsertActive) + _insertStateLabel.Text = "Insert"; + else + _insertStateLabel.Text = "Overwrite"; + } + private void UpdatePosition () { long pos = (hexBox1.CurrentLine - 1) * hexBox1.HorizontalByteCount + hexBox1.CurrentPositionInLine - 1; @@ -83,9 +96,10 @@ namespace NBTExplorer.Windows private void Apply () { - long len = Math.Min(_data.Length, _byteProvider.Length); + if (_data.Length != _byteProvider.Length) + _data = new byte[_byteProvider.Length]; - for (int i = 0; i < len; i++) { + for (int i = 0; i < _data.Length; i++) { _data[i] = _byteProvider.Bytes[i]; } @@ -93,9 +107,185 @@ namespace NBTExplorer.Windows Close(); } + private String RawToText (byte[] data) + { + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < data.Length; i += _bytesPerElem) { + if (data.Length - i < _bytesPerElem) + break; + + switch (_bytesPerElem) { + case 1: + builder.AppendLine(((sbyte)data[i]).ToString()); + break; + + case 2: + builder.AppendLine(BitConverter.ToInt16(data, i).ToString()); + break; + + case 4: + builder.AppendLine(BitConverter.ToInt32(data, i).ToString()); + break; + + case 8: + builder.AppendLine(BitConverter.ToInt64(data, i).ToString()); + break; + } + } + + return builder.ToString(); + } + + private byte[] TextToRaw (string text) + { + string[] items = text.Split(null as char[], StringSplitOptions.RemoveEmptyEntries); + byte[] data = new byte[_bytesPerElem * items.Length]; + + for (int i = 0; i < items.Length; i++) { + int index = i * _bytesPerElem; + + switch (_bytesPerElem) { + case 1: + sbyte val1; + if (sbyte.TryParse(items[i], out val1)) + data[index] = (byte)val1; + break; + + case 2: + short val2; + if (short.TryParse(items[i], out val2)) { + byte[] buffer = BitConverter.GetBytes(val2); + Array.Copy(buffer, 0, data, index, 2); + } + break; + + case 4: + int val4; + if (int.TryParse(items[i], out val4)) { + byte[] buffer = BitConverter.GetBytes(val4); + Array.Copy(buffer, 0, data, index, 4); + } + break; + + case 8: + long val8; + if (long.TryParse(items[i], out val8)) { + byte[] buffer = BitConverter.GetBytes(val8); + Array.Copy(buffer, 0, data, index, 8); + } + break; + } + } + + return data; + } + + private void ImportRaw (string path) + { + try { + using (FileStream fstr = File.OpenRead(path)) { + _data = new byte[fstr.Length]; + fstr.Read(_data, 0, (int)fstr.Length); + + _byteProvider = new DynamicByteProvider(_data); + _byteProvider.Changed += (o, e) => { _modified = true; }; + + hexBox1.ByteProvider = _byteProvider; + _modified = true; + } + } + catch (Exception e) { + MessageBox.Show("Failed to import data from \"" + path + "\"\n\nException: " + e.Message); + } + } + + private void ImportText (string path) + { + try { + using (FileStream fstr = File.OpenRead(path)) { + byte[] raw = new byte[fstr.Length]; + fstr.Read(raw, 0, (int)fstr.Length); + + string text = System.Text.Encoding.UTF8.GetString(raw, 0, raw.Length); + _data = TextToRaw(text); + + _byteProvider = new DynamicByteProvider(_data); + _byteProvider.Changed += (o, e) => { _modified = true; }; + + hexBox1.ByteProvider = _byteProvider; + _modified = true; + } + } + catch (Exception e) { + MessageBox.Show("Failed to import data from \"" + path + "\"\n\nException: " + e.Message); + } + } + + private void ExportRaw (string path) + { + try { + using (FileStream fstr = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) { + byte[] data = _byteProvider.Bytes.ToArray(); + fstr.Write(data, 0, data.Length); + } + } + catch (Exception e) { + MessageBox.Show("Failed to export data to \"" + path + "\"\n\nException: " + e.Message); + } + } + + private void ExportText (string path) + { + try { + using (FileStream fstr = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) { + string text = RawToText(_byteProvider.Bytes.ToArray()); + byte[] data = System.Text.Encoding.UTF8.GetBytes(text); + fstr.Write(data, 0, data.Length); + } + } + catch (Exception e) { + MessageBox.Show("Failed to export data to \"" + path + "\"\n\nException: " + e.Message); + } + } + private void _buttonOK_Click (object sender, EventArgs e) { Apply(); } + + private void _buttonImport_Click (object sender, EventArgs e) + { + using (OpenFileDialog ofd = new OpenFileDialog()) { + ofd.RestoreDirectory = true; + ofd.Multiselect = false; + ofd.Filter = "Binary Data|*|Text Data (*.txt)|*.txt"; + ofd.FilterIndex = 0; + + if (ofd.ShowDialog() == DialogResult.OK) { + if (Path.GetExtension(ofd.FileName) == ".txt") + ImportText(ofd.FileName); + else + ImportRaw(ofd.FileName); + } + } + } + + private void _buttonExport_Click (object sender, EventArgs e) + { + using (SaveFileDialog sfd = new SaveFileDialog()) { + sfd.RestoreDirectory = true; + sfd.Filter = "Binary Data|*|Text Data (*.txt)|*.txt"; + sfd.FilterIndex = 0; + sfd.OverwritePrompt = true; + + if (sfd.ShowDialog() == DialogResult.OK) { + if (Path.GetExtension(sfd.FileName) == ".txt") + ExportText(sfd.FileName); + else + ExportRaw(sfd.FileName); + } + } + } } } diff --git a/Windows/EditName.cs b/Windows/EditName.cs index e76cf0c..deb8fad 100644 --- a/Windows/EditName.cs +++ b/Windows/EditName.cs @@ -31,6 +31,8 @@ namespace NBTExplorer.Windows get { return _invalidNames; } } + public bool AllowEmpty { get; set; } + public bool IsModified { get { return _name != _originalName; } @@ -52,7 +54,7 @@ namespace NBTExplorer.Windows private bool ValidateNameInput () { string text = _nameField.Text.Trim(); - if (String.IsNullOrEmpty(text)) { + if (String.IsNullOrEmpty(text) && !AllowEmpty) { MessageBox.Show("You must provide a nonempty name."); return false; } diff --git a/Windows/FormHandlers.cs b/Windows/FormHandlers.cs index 7f22c63..d554808 100644 --- a/Windows/FormHandlers.cs +++ b/Windows/FormHandlers.cs @@ -34,7 +34,9 @@ namespace NBTExplorer.Windows public static bool RenameTagHandler (RestrictedStringFormData data) { - EditName form = new EditName(data.Value); + EditName form = new EditName(data.Value) { + AllowEmpty = data.AllowEmpty, + }; form.InvalidNames.AddRange(data.RestrictedValues); if (form.ShowDialog() == DialogResult.OK && form.IsModified) { @@ -58,6 +60,7 @@ namespace NBTExplorer.Windows { HexEditor form = new HexEditor(data.NodeName, data.Data, data.BytesPerElement); if (form.ShowDialog() == DialogResult.OK && form.Modified) { + data.Data = new byte[form.Data.Length]; Array.Copy(form.Data, data.Data, data.Data.Length); return true; } diff --git a/Windows/MainForm.cs b/Windows/MainForm.cs index d3e596c..8969055 100644 --- a/Windows/MainForm.cs +++ b/Windows/MainForm.cs @@ -143,12 +143,15 @@ namespace NBTExplorer.Windows if (!ConfirmAction("Open new file anyway?")) return; - OpenFileDialog ofd = new OpenFileDialog(); - ofd.RestoreDirectory = true; - ofd.Multiselect = true; - - if (ofd.ShowDialog() == DialogResult.OK) { - OpenPaths(ofd.FileNames); + using (OpenFileDialog ofd = new OpenFileDialog() { + RestoreDirectory = true, + Multiselect = true, + Filter = "All Files|*|NBT Files (*.dat, *.schematic)|*.dat;*.nbt;*.schematic|Region Files (*.mca, *.mcr)|*.mca;*.mcr", + FilterIndex = 0, + }) { + if (ofd.ShowDialog() == DialogResult.OK) { + OpenPaths(ofd.FileNames); + } } UpdateUI(); @@ -159,13 +162,14 @@ namespace NBTExplorer.Windows if (!ConfirmAction("Open new folder anyway?")) return; - FolderBrowserDialog ofd = new FolderBrowserDialog(); - if (_openFolderPath != null) - ofd.SelectedPath = _openFolderPath; + using (FolderBrowserDialog ofd = new FolderBrowserDialog()) { + if (_openFolderPath != null) + ofd.SelectedPath = _openFolderPath; - if (ofd.ShowDialog() == DialogResult.OK) { - _openFolderPath = ofd.SelectedPath; - OpenPaths(new string[] { ofd.SelectedPath }); + if (ofd.ShowDialog() == DialogResult.OK) { + _openFolderPath = ofd.SelectedPath; + OpenPaths(new string[] { ofd.SelectedPath }); + } } UpdateUI(); @@ -173,17 +177,41 @@ namespace NBTExplorer.Windows private void OpenPaths (string[] paths) { - _controller.OpenPaths(paths); + int failCount = _controller.OpenPaths(paths); foreach (string path in paths) { if (Directory.Exists(path)) - AddPathToHistory(Settings.Default.RecentDirectories, path); + AddPathToHistory(GetRecentDirectories(), path); else if (File.Exists(path)) - AddPathToHistory(Settings.Default.RecentFiles, path); + AddPathToHistory(GetRecentFiles(), path); } UpdateUI(); UpdateOpenMenu(); + + if (failCount > 0) { + MessageBox.Show("One or more selected files failed to open."); + } + } + + private StringCollection GetRecentFiles () + { + try { + return Settings.Default.RecentFiles; + } + catch { + return null; + } + } + + private StringCollection GetRecentDirectories () + { + try { + return Settings.Default.RecentDirectories; + } + catch { + return null; + } } private void OpenMinecraftDirectory () @@ -192,7 +220,11 @@ namespace NBTExplorer.Windows return; try { - string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + string path = Environment.ExpandEnvironmentVariables("%APPDATA%"); + if (!Directory.Exists(path)) { + path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + } + path = Path.Combine(path, ".minecraft"); path = Path.Combine(path, "saves"); @@ -225,7 +257,7 @@ namespace NBTExplorer.Windows frontNode.ImageIndex = _iconRegistry.Lookup(node.GetType()); frontNode.SelectedImageIndex = frontNode.ImageIndex; frontNode.Tag = node; - frontNode.ContextMenuStrip = BuildNodeContextMenu(node); + //frontNode.ContextMenuStrip = BuildNodeContextMenu(node); if (node.HasUnexpandedChildren || node.Nodes.Count > 0) frontNode.Nodes.Add(new TreeNode()); @@ -233,45 +265,16 @@ namespace NBTExplorer.Windows return frontNode; } - private ContextMenuStrip BuildNodeContextMenu (DataNode node) - { - if (node == null) - return null; - - ContextMenuStrip menu = new ContextMenuStrip(); - - if (node.CanReoderNode) { - ToolStripMenuItem itemUp = new ToolStripMenuItem("Move &Up", Properties.Resources.ArrowUp, _contextMoveUp_Click); - ToolStripMenuItem itemDn = new ToolStripMenuItem("Move &Down", Properties.Resources.ArrowDown, _contextMoveDown_Click); - - itemUp.Enabled = node.CanMoveNodeUp; - itemDn.Enabled = node.CanMoveNodeDown; - - menu.Items.Add(itemUp); - menu.Items.Add(itemDn); - } - - return (menu.Items.Count > 0) ? menu : null; - } - - private void _contextMoveUp_Click (object sender, EventArgs e) - { - _controller.MoveSelectionUp(); - } - - private void _contextMoveDown_Click (object sender, EventArgs e) - { - _controller.MoveSelectionDown(); - } - private void ExpandNode (TreeNode node) { _controller.ExpandNode(node); + UpdateUI(node.Tag as DataNode); } private void CollapseNode (TreeNode node) { _controller.CollapseNode(node); + UpdateUI(node.Tag as DataNode); } private bool ConfirmExit () @@ -540,6 +543,9 @@ namespace NBTExplorer.Windows private void AddPathToHistory (StringCollection list, string entry) { + if (list == null) + return; + foreach (string item in list) { if (item == entry) { list.Remove(item); @@ -596,8 +602,10 @@ namespace NBTExplorer.Windows private void _nodeTree_NodeMouseClick (object sender, TreeNodeMouseClickEventArgs e) { - if (e.Button == MouseButtons.Right) + if (e.Button == MouseButtons.Right) { + e.Node.ContextMenuStrip = _controller.BuildNodeContextMenu(e.Node, e.Node.Tag as DataNode); _nodeTree.SelectedNode = e.Node; + } } private void _nodeTree_DragDrop (object sender, DragEventArgs e)