From 1c2da8cc925b78687b87d3168322bc1088ae10cd Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bruyère Date: Sun, 11 Mar 2018 13:20:27 +0100 Subject: split ProjectNode classes in separate files --- CrowIDE/src/ProjectTree/ProjectFile.cs | 290 +++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 CrowIDE/src/ProjectTree/ProjectFile.cs (limited to 'CrowIDE/src/ProjectTree/ProjectFile.cs') diff --git a/CrowIDE/src/ProjectTree/ProjectFile.cs b/CrowIDE/src/ProjectTree/ProjectFile.cs new file mode 100644 index 00000000..2c3dbbe4 --- /dev/null +++ b/CrowIDE/src/ProjectTree/ProjectFile.cs @@ -0,0 +1,290 @@ +// +// ProjectNodes.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2013-2017 Jean-Philippe Bruyère +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.IO; +using Crow; +using System.Threading; + +namespace Crow.Coding +{ + public class ProjectFile : ProjectItem { + protected bool isOpened = false; + DateTime accessTime; + string source; + string origSource; + object selectedItem; + int curLine, curColumn; + + internal ReaderWriterLockSlim srcEditMtx = new ReaderWriterLockSlim(); + + public Dictionary RegisteredEditors = new Dictionary(); + List undoStack = new List(); + List redoStack = new List(); + + public Crow.Command cmdSave, cmdSaveAs, cmdOpen, cmdUndo, cmdRedo; + + void initCommands (){ + cmdSave = new Crow.Command (new Action (() => Save ())) + { Caption = "Save", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false }; + cmdSaveAs = new Crow.Command (new Action (() => SaveAs ())) + { Caption = "Save As ..", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false }; + cmdOpen = new Crow.Command (new Action (() => Open ())) + { Caption = "Open", Icon = new SvgPicture ("#Crow.Coding.ui.icons.outbox.svg"), CanExecute = false }; + cmdUndo = new Crow.Command (new Action (() => Undo (null))) + { Caption = "Undo", Icon = new SvgPicture ("#Crow.Coding.icons.undo.svg"), CanExecute = false }; + cmdRedo = new Crow.Command (new Action (() => Redo (null))) + { Caption = "Redo", Icon = new SvgPicture ("#Crow.Coding.icons.redo.svg"), CanExecute = false }; + + Commands.Insert (0, cmdOpen); + Commands.Insert (1, cmdSave); + } + public ProjectFile () { + initCommands(); + } + public ProjectFile (ProjectItem pi) + : base (pi.Project, pi.node) { + initCommands (); + } + + public string ResourceID { + get { + return Type != ItemType.EmbeddedResource ? null : + node.SelectSingleNode ("LogicalName") == null ? + Project.Name + "." + Path.Replace ('/', '.') : + LogicalName; + } + } + public string LogicalName { + get { + return node.SelectSingleNode ("LogicalName")?.InnerText; + } + } + + public void UnregisterEditor (object editor){ + lock(RegisteredEditors){ + RegisteredEditors.Remove (editor); + } + } + public void RegisterEditor (object editor) { + lock(RegisteredEditors){ + RegisteredEditors.Add (editor, false); + } + } + public void UpdateSource (object sender, string newSrc){ + System.Diagnostics.Debug.WriteLine ("update source by {0}", sender); + Source = newSrc; + signalOtherRegisteredEditors (sender); + } + void signalOtherRegisteredEditors (object sender) { + lock (RegisteredEditors) { + object[] keys = RegisteredEditors.Keys.ToArray (); + foreach (object editor in keys) { + if (editor != sender) + RegisteredEditors [editor] = false; + } + } + } + public string Source { + get { + if (!isOpened) + Open (); + else { + if (DateTime.Compare ( + accessTime, + System.IO.File.GetLastWriteTime (AbsolutePath)) < 0) + Console.WriteLine ("File has been modified outside CrowIDE"); + } + return source; + } + set { + if (source == value) + return; + + srcEditMtx.EnterWriteLock (); + + undoStack.Add (source); + cmdUndo.CanExecute = true; + redoStack.Clear (); + cmdRedo.CanExecute = false; + source = value; + + NotifyValueChanged ("Source", source); + NotifyValueChanged ("IsDirty", IsDirty); + + cmdSave.CanExecute = cmdSaveAs.CanExecute = IsDirty; + + srcEditMtx.ExitWriteLock (); + } + } + public bool IsDirty { + get { return source != origSource; } + } + public int CurrentColumn{ + get { return curColumn; } + set { + if (curColumn == value) + return; + curColumn = value; + NotifyValueChanged ("CurrentColumn", curColumn); + } + } + public int CurrentLine{ + get { return curLine; } + set { + if (curLine == value) + return; + curLine = value; + NotifyValueChanged ("CurrentLine", curLine); + } + } + + public object SelectedItem { + get { return selectedItem; } + set { + if (selectedItem == value) + return; + selectedItem= value; + Project.solution.SelectedItemElement = value; + NotifyValueChanged ("SelectedItem", selectedItem); + } + } + + public CopyToOutputState CopyToOutputDirectory { + get { + XmlNode xn = node.SelectSingleNode ("CopyToOutputDirectory"); + return xn == null ? CopyToOutputState.Never : + (CopyToOutputState)Enum.Parse (typeof(CopyToOutputState), xn.InnerText, true); + } + } + + public void Open () { + accessTime = System.IO.File.GetLastWriteTime (AbsolutePath); + using (StreamReader sr = new StreamReader (AbsolutePath)) { + source = sr.ReadToEnd (); + } + isOpened = true; + origSource = source; + NotifyValueChanged ("IsDirty", false); + } + public void Save () { + if (!IsDirty) + return; + using (StreamWriter sw = new StreamWriter (AbsolutePath)) { + sw.Write (source); + } + origSource = source; + NotifyValueChanged ("IsDirty", false); + } + public void SaveAs () { + if (!IsDirty) + return; + using (StreamWriter sw = new StreamWriter (AbsolutePath)) { + sw.Write (source); + } + origSource = source; + NotifyValueChanged ("IsDirty", false); + } + public void Close () { + origSource = null; + isOpened = false; + Project.solution.CloseItem (this); + } + public void Undo(object sender){ + undo(); + signalOtherRegisteredEditors (sender); + } + public void Redo(object sender){ + redo(); + signalOtherRegisteredEditors (sender); + } + + void undo () { + if (undoStack.Count == 0) + return; + + srcEditMtx.EnterWriteLock (); + string step = undoStack [undoStack.Count -1]; + redoStack.Add (source); + cmdRedo.CanExecute = true; + undoStack.RemoveAt(undoStack.Count -1); + + source = step; + + NotifyValueChanged ("Source", source); + NotifyValueChanged ("IsDirty", IsDirty); + cmdSave.CanExecute = IsDirty; + + if (undoStack.Count == 0) + cmdUndo.CanExecute = false; + srcEditMtx.ExitWriteLock (); + } + + void redo () { + if (redoStack.Count == 0) + return; + srcEditMtx.EnterWriteLock (); + string step = redoStack [redoStack.Count -1]; + undoStack.Add (source); + cmdUndo.CanExecute = true; + redoStack.RemoveAt(redoStack.Count -1); + source = step; + NotifyValueChanged ("Source", source); + NotifyValueChanged ("IsDirty", IsDirty); + cmdSave.CanExecute = IsDirty; + + if (redoStack.Count == 0) + cmdRedo.CanExecute = false; + srcEditMtx.ExitWriteLock (); + + } + + + public void OnQueryClose (object sender, EventArgs e){ + if (IsDirty) { + MessageBox mb = MessageBox.ShowModal (CrowIDE.MainIFace, + MessageBox.Type.YesNoCancel, $"{DisplayName} has unsaved changes.\nSave it now?"); + mb.Yes += onClickSaveAndCloseNow; + mb.No += onClickCloseNow; + } else + Close (); + } + + void onClickCloseNow (object sender, EventArgs e) + { + Close (); + } + + void onClickSaveAndCloseNow (object sender, EventArgs e) + { + Save (); + Close (); + } + } +} + -- cgit v1.3.1-4-g156e