From 83d6c5efd723ae6820b5af7b7574d5b4b7a27638 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 3 Apr 2013 16:25:23 +0200 Subject: [PATCH] Separate NewFileDialog from the FileTemplate implementation (use only the abstract base class). --- .../PortSD4AddInToSD5/PortSD4AddInToSD5.addin | 3 +- .../LocalizedProperty.cs | 5 +- .../Project/Src/Gui/Dialogs/NewFileDialog.cs | 246 ++---------------- .../Src/Gui/Dialogs/NewProjectDialog.cs | 8 +- .../Internal/Templates/File/FileTemplate.cs | 242 +++++++++++++++-- .../Internal/Templates/File/ScriptRunner.cs | 4 +- .../Base/Project/Templates/FileTemplate.cs | 6 +- .../SharpDevelop/Project/ProjectService.cs | 6 +- src/Main/SharpDevelop/Services/UIService.cs | 26 +- src/Main/SharpDevelop/SharpDevelop.csproj | 6 +- .../Templates/TemplateFileDoozer.cs | 7 +- .../SharpDevelop/Templates/TemplateService.cs | 2 +- src/Main/SharpDevelop/app.config | 144 ++++++++++ src/Tools/UpdateAssemblyInfo/Main.cs | 2 +- 14 files changed, 423 insertions(+), 284 deletions(-) create mode 100644 src/Main/SharpDevelop/app.config diff --git a/samples/PortSD4AddInToSD5/PortSD4AddInToSD5.addin b/samples/PortSD4AddInToSD5/PortSD4AddInToSD5.addin index 311f184320..9b86f54130 100644 --- a/samples/PortSD4AddInToSD5/PortSD4AddInToSD5.addin +++ b/samples/PortSD4AddInToSD5/PortSD4AddInToSD5.addin @@ -1,6 +1,7 @@  + description = "Issue Providers that help porting SD4 AddIns to SD5" + addInManagerHidden="preinstalled"> diff --git a/src/Main/Base/Project/Src/Gui/Components/LocalizedPropertyGrid/LocalizedProperty.cs b/src/Main/Base/Project/Src/Gui/Components/LocalizedPropertyGrid/LocalizedProperty.cs index 387bddd7a7..9dc2424ca7 100644 --- a/src/Main/Base/Project/Src/Gui/Components/LocalizedPropertyGrid/LocalizedProperty.cs +++ b/src/Main/Base/Project/Src/Gui/Components/LocalizedPropertyGrid/LocalizedProperty.cs @@ -6,10 +6,11 @@ using System.Collections.Generic; using System.ComponentModel; using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; -namespace ICSharpCode.SharpDevelop.Gui +namespace ICSharpCode.SharpDevelop.Templates { - public class LocalizedProperty : PropertyDescriptor + internal class LocalizedProperty : PropertyDescriptor { string category; string description; diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs index b32fa00471..abe7a71a39 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs @@ -29,20 +29,14 @@ namespace ICSharpCode.SharpDevelop.Gui { ArrayList alltemplates = new ArrayList(); ArrayList categories = new ArrayList(); - Hashtable icons = new Hashtable(); + Dictionary icons = new Dictionary(); bool allowUntitledFiles; IProject project; DirectoryName basePath; - List> createdFiles = new List>(); internal FileTemplateOptions options; + internal FileTemplateResult result; - public List> CreatedFiles { - get { - return createdFiles; - } - } - - public NewFileDialog(IProject project, DirectoryName basePath) + public NewFileDialog(IProject project, DirectoryName basePath, IEnumerable fileTemplates) { StandardHeader.SetHeaders(); this.project = project; @@ -50,7 +44,7 @@ namespace ICSharpCode.SharpDevelop.Gui this.allowUntitledFiles = basePath == null; try { InitializeComponents(); - InitializeTemplates(); + InitializeTemplates(fileTemplates); InitializeView(); if (allowUntitledFiles) @@ -76,20 +70,18 @@ namespace ICSharpCode.SharpDevelop.Gui imglist.Images.Add(IconService.GetBitmap("Icons.32x32.EmptyFileIcon")); int i = 0; - Hashtable tmp = new Hashtable(icons); - foreach (DictionaryEntry entry in icons) { - Bitmap bitmap = IconService.GetBitmap(entry.Key.ToString()); + foreach (var image in icons.Keys.ToArray()) { + Bitmap bitmap = image.Bitmap; if (bitmap != null) { smalllist.Images.Add(bitmap); imglist.Images.Add(bitmap); - tmp[entry.Key] = ++i; + icons[image] = ++i; } else { - LoggingService.Warn("NewFileDialog: can't load bitmap " + entry.Key.ToString() + " using default"); + LoggingService.Warn("NewFileDialog: can't load bitmap " + image.ToString() + " using default"); } } - icons = tmp; foreach (TemplateItem item in alltemplates) { if (item.Template.Icon == null) { item.ImageIndex = 0; @@ -155,24 +147,18 @@ namespace ICSharpCode.SharpDevelop.Gui return newsubcategory; } - void InitializeTemplates() + void InitializeTemplates(IEnumerable fileTemplates) { - foreach (FileTemplate template in FileTemplate.FileTemplates) { + foreach (FileTemplate template in fileTemplates) { TemplateItem titem = new TemplateItem(template); if (titem.Template.Icon != null) { icons[titem.Template.Icon] = 0; // "create template icon" } - if (template.NewFileDialogVisible == true) { + if (template.IsVisible(project)) { Category cat = GetCategory(StringParser.Parse(titem.Template.Category), StringParser.Parse(titem.Template.Subcategory)); cat.Templates.Add(titem); cat.Selected = true; - if (!cat.HasSelectedTemplate && titem.Template.FileDescriptionTemplates.Count == 1) { - if (((FileDescriptionTemplate)titem.Template.FileDescriptionTemplates[0]).Name.StartsWith("Empty")) { - titem.Selected = true; - cat.HasSelectedTemplate = true; - } - } } alltemplates.Add(titem); } @@ -209,67 +195,15 @@ namespace ICSharpCode.SharpDevelop.Gui const int GridWidth = 256; const int GridMargin = 8; PropertyGrid propertyGrid = new PropertyGrid(); - LocalizedTypeDescriptor localizedTypeDescriptor = null; - - bool AllPropertiesHaveAValue { - get { - foreach (TemplateProperty property in SelectedTemplate.Properties) { - string val = StringParserPropertyContainer.LocalizedProperty["Properties." + property.Name]; - if (val == null || val.Length == 0) { - return false; - } - } - return true; - } - } + object localizedTypeDescriptor = null; void ShowPropertyGrid() { - if (localizedTypeDescriptor == null) { - localizedTypeDescriptor = new LocalizedTypeDescriptor(); - } - if (!Controls.Contains(propertyGrid)) { this.SuspendLayout(); propertyGrid.Location = new Point(Width - GridMargin, GridMargin); propertyGrid.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom; - localizedTypeDescriptor.Properties.Clear(); - foreach (TemplateProperty property in SelectedTemplate.Properties) { - LocalizedProperty localizedProperty; - if (property.Type.StartsWith("Types:")) { - localizedProperty = new LocalizedProperty(property.Name, "System.Enum", property.Category, property.Description); - TemplateType type = null; - foreach (TemplateType templateType in SelectedTemplate.CustomTypes) { - if (templateType.Name == property.Type.Substring("Types:".Length)) { - type = templateType; - break; - } - } - if (type == null) { - throw new Exception("type : " + property.Type + " not found."); - } - localizedProperty.TypeConverterObject = new CustomTypeConverter(type); - StringParserPropertyContainer.LocalizedProperty["Properties." + localizedProperty.Name] = property.DefaultValue; - localizedProperty.DefaultValue = property.DefaultValue; // localizedProperty.TypeConverterObject.ConvertFrom(); - } else { - localizedProperty = new LocalizedProperty(property.Name, property.Type, property.Category, property.Description); - if (property.Type == "System.Boolean") { - localizedProperty.TypeConverterObject = new BooleanTypeConverter(); - string defVal = property.DefaultValue == null ? null : property.DefaultValue.ToString(); - if (defVal == null || defVal.Length == 0) { - defVal = "True"; - } - StringParserPropertyContainer.LocalizedProperty["Properties." + localizedProperty.Name] = defVal; - localizedProperty.DefaultValue = Boolean.Parse(defVal); - } else { - string defVal = property.DefaultValue == null ? String.Empty : property.DefaultValue.ToString(); - StringParserPropertyContainer.LocalizedProperty["Properties." + localizedProperty.Name] = defVal; - localizedProperty.DefaultValue = defVal; - } - } - localizedProperty.LocalizedName = property.LocalizedName; - localizedTypeDescriptor.Properties.Add(localizedProperty); - } + propertyGrid.ToolbarVisible = false; propertyGrid.SelectedObject = localizedTypeDescriptor; propertyGrid.Size = new Size(GridWidth, Height - GridMargin * 4); @@ -300,32 +234,7 @@ namespace ICSharpCode.SharpDevelop.Gui } string GenerateCurrentFileName() { - if (SelectedTemplate.DefaultName.IndexOf("${Number}") >= 0) { - try { - int curNumber = 1; - - while (true) { - string fileName = StringParser.Parse(SelectedTemplate.DefaultName, new StringTagPair("Number", curNumber.ToString())); - if (allowUntitledFiles) { - bool found = false; - foreach (string openFile in FileService.GetOpenFiles()) { - if (Path.GetFileName(openFile) == fileName) { - found = true; - break; - } - } - if (found == false) - return fileName; - } else if (!File.Exists(Path.Combine(basePath, fileName))) { - return fileName; - } - ++curNumber; - } - } catch (Exception e) { - MessageService.ShowException(e); - } - } - return StringParser.Parse(SelectedTemplate.DefaultName); + return SelectedTemplate.SuggestFileName(basePath); } bool isNameModified = false; @@ -336,7 +245,8 @@ namespace ICSharpCode.SharpDevelop.Gui if (templateListView.SelectedItems.Count == 1) { ControlDictionary["descriptionLabel"].Text = StringParser.Parse(SelectedTemplate.Description); ControlDictionary["openButton"].Enabled = true; - if (SelectedTemplate.HasProperties) { + localizedTypeDescriptor = SelectedTemplate.CreateCustomizationObject(); + if (localizedTypeDescriptor != null) { ShowPropertyGrid(); } if (!this.allowUntitledFiles && !isNameModified) { @@ -362,59 +272,6 @@ namespace ICSharpCode.SharpDevelop.Gui templateListView.View = ((RadioButton)ControlDictionary["smallIconsRadioButton"]).Checked ? View.List : View.LargeIcon; } - public bool IsFilenameAvailable(string fileName) - { - if (Path.IsPathRooted(fileName)) { - return !File.Exists(fileName); - } - return true; - } - - public void SaveFile(FileDescriptionTemplate newfile, string content, string binaryFileName) - { - string unresolvedFileName = StringParser.Parse(newfile.Name); - // Parse twice so that tags used in included standard header are parsed - string parsedContent = StringParser.Parse(StringParser.Parse(content)); - - if (parsedContent != null) { - if (SD.EditorControlService.GlobalOptions.IndentationString != "\t") { - parsedContent = parsedContent.Replace("\t", SD.EditorControlService.GlobalOptions.IndentationString); - } - } - - - // when newFile.Name is "${Path}/${FileName}", there might be a useless '/' in front of the file name - // if the file is created when no project is opened. So we remove single '/' or '\', but not double - // '\\' (project is saved on network share). - if (unresolvedFileName.StartsWith("/") && !unresolvedFileName.StartsWith("//") - || unresolvedFileName.StartsWith("\\") && !unresolvedFileName.StartsWith("\\\\")) - { - unresolvedFileName = unresolvedFileName.Substring(1); - } - - if (newfile.IsDependentFile && Path.IsPathRooted(unresolvedFileName)) { - Directory.CreateDirectory(Path.GetDirectoryName(unresolvedFileName)); - if (!String.IsNullOrEmpty(binaryFileName)) - File.Copy(binaryFileName, unresolvedFileName); - else - File.WriteAllText(unresolvedFileName, parsedContent, SD.FileService.DefaultFileEncoding); - } else { - if (!String.IsNullOrEmpty(binaryFileName)) { - LoggingService.Warn("binary file was skipped"); - return; - } - IViewContent viewContent = FileService.NewFile(Path.GetFileName(unresolvedFileName), parsedContent); - if (viewContent == null) { - return; - } - if (Path.IsPathRooted(unresolvedFileName)) { - Directory.CreateDirectory(Path.GetDirectoryName(unresolvedFileName)); - viewContent.PrimaryFile.SaveToDisk(FileName.Create(unresolvedFileName)); - } - } - createdFiles.Add(new KeyValuePair(unresolvedFileName, newfile)); - } - internal static string GenerateValidClassOrNamespaceName(string className, bool allowDot) { if (className == null) @@ -444,18 +301,13 @@ namespace ICSharpCode.SharpDevelop.Gui PropertyService.Set("Dialogs.NewFileDialog.CategoryViewState", TreeViewHelper.GetViewStateString(categoryTreeView)); PropertyService.Set("Dialogs.NewFileDialog.LastSelectedCategory", TreeViewHelper.GetPath(categoryTreeView.SelectedNode)); } - createdFiles.Clear(); if (templateListView.SelectedItems.Count == 1) { - if (!AllPropertiesHaveAValue) { - MessageService.ShowMessage("${res:Dialog.NewFile.FillOutFirstMessage}", "${res:Dialog.NewFile.FillOutFirstCaption}"); - return; - } TemplateItem item = (TemplateItem)templateListView.SelectedItems[0]; PropertyService.Set("Dialogs.NewFileDialog.LastSelectedTemplate", item.Template.Name); string fileName; - StringParserPropertyContainer.FileCreation["StandardNamespace"] = "DefaultNamespace"; + string standardNamespace = "DefaultNamespace"; if (allowUntitledFiles) { fileName = GenerateCurrentFileName(); } else { @@ -468,12 +320,12 @@ namespace ICSharpCode.SharpDevelop.Gui return; } if (Path.GetExtension(fileName).Length == 0) { - fileName += Path.GetExtension(item.Template.DefaultName); + fileName += Path.GetExtension(item.Template.SuggestFileName(null)); } fileName = Path.Combine(basePath, fileName); fileName = FileUtility.NormalizePath(fileName); if (project != null) { - StringParserPropertyContainer.FileCreation["StandardNamespace"] = CustomToolsService.GetDefaultNamespace(project, fileName); + standardNamespace = CustomToolsService.GetDefaultNamespace(project, fileName); } } @@ -481,62 +333,14 @@ namespace ICSharpCode.SharpDevelop.Gui options.ClassName = GenerateValidClassOrNamespaceName(Path.GetFileNameWithoutExtension(fileName), false); options.FileName = FileName.Create(fileName); options.IsUntitled = allowUntitledFiles; - options.Namespace = StringParserPropertyContainer.FileCreation["StandardNamespace"]; - - StringParserPropertyContainer.FileCreation["FullName"] = fileName; - StringParserPropertyContainer.FileCreation["FileName"] = Path.GetFileName(fileName); - StringParserPropertyContainer.FileCreation["FileNameWithoutExtension"] = Path.GetFileNameWithoutExtension(fileName); - StringParserPropertyContainer.FileCreation["Extension"] = Path.GetExtension(fileName); - StringParserPropertyContainer.FileCreation["Path"] = Path.GetDirectoryName(fileName); - - StringParserPropertyContainer.FileCreation["ClassName"] = options.ClassName; - - // when adding a file to a project (but not when creating a standalone file while a project is open): - if (project != null && !this.allowUntitledFiles) { - options.Project = project; - // add required assembly references to the project - bool changes = false; - foreach (ReferenceProjectItem reference in item.Template.RequiredAssemblyReferences) { - IEnumerable refs = project.GetItemsOfType(ItemType.Reference); - if (!refs.Any(projItem => string.Equals(projItem.Include, reference.Include, StringComparison.OrdinalIgnoreCase))) { - ReferenceProjectItem projItem = (ReferenceProjectItem)reference.CloneFor(project); - ProjectService.AddProjectItem(project, projItem); - changes = true; - } - } - if (changes) { - project.Save(); - } - } - - foreach (FileDescriptionTemplate newfile in item.Template.FileDescriptionTemplates) { - if (!IsFilenameAvailable(StringParser.Parse(newfile.Name))) { - MessageService.ShowError(string.Format("Filename {0} is in use.\nChoose another one", StringParser.Parse(newfile.Name))); // TODO : translate - return; - } - } - ScriptRunner scriptRunner = new ScriptRunner(); - foreach (FileDescriptionTemplate newFile in item.Template.FileDescriptionTemplates) { - FileOperationResult result = FileUtility.ObservedSave( - () => { - if (!String.IsNullOrEmpty(newFile.BinaryFileName)) { - SaveFile(newFile, null, newFile.BinaryFileName); - } else { - SaveFile(newFile, scriptRunner.CompileScript(item.Template, newFile), null); - } - }, FileName.Create(StringParser.Parse(newFile.Name)) - ); - if (result != FileOperationResult.OK) - return; - } + options.Namespace = standardNamespace; + options.CustomizationObject = localizedTypeDescriptor; + options.Project = project; + result = SelectedTemplate.Create(options); DialogResult = DialogResult.OK; - - // raise FileCreated event for the new files. - foreach (KeyValuePair entry in createdFiles) { - FileService.FireFileCreated(entry.Key, false); - } - item.Template.RunActions(options); + if (result != null) + SelectedTemplate.RunActions(result); } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs index a03f0cf10b..b6dc7ee2a2 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs @@ -34,12 +34,12 @@ namespace ICSharpCode.SharpDevelop.Project.Dialogs set { locationTextBox.Text = value; } } - public NewProjectDialog(bool createNewSolution) + public NewProjectDialog(bool createNewSolution, IEnumerable projectTemplates) { this.createNewSolution = createNewSolution; MyInitializeComponents(); - InitializeTemplates(); + InitializeTemplates(projectTemplates); InitializeView(); locationTextBox.Text = PropertyService.Get("ICSharpCode.SharpDevelop.Gui.Dialogs.NewProjectDialog.DefaultPath", Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "SharpDevelop Projects")); @@ -135,9 +135,9 @@ namespace ICSharpCode.SharpDevelop.Project.Dialogs return newsubcategory; } - protected virtual void InitializeTemplates() + protected virtual void InitializeTemplates(IEnumerable projectTemplates) { - foreach (ProjectTemplate template in SD.Templates.ProjectTemplates) { + foreach (ProjectTemplate template in projectTemplates) { if (!template.IsVisible(SolutionFolder != null ? SolutionFolder.ParentSolution : null)) { // Do not show solution template when added a new project to existing solution continue; diff --git a/src/Main/Base/Project/Src/Internal/Templates/File/FileTemplate.cs b/src/Main/Base/Project/Src/Internal/Templates/File/FileTemplate.cs index 661840a35b..4e2615e674 100644 --- a/src/Main/Base/Project/Src/Internal/Templates/File/FileTemplate.cs +++ b/src/Main/Base/Project/Src/Internal/Templates/File/FileTemplate.cs @@ -9,8 +9,8 @@ using System.Linq; using System.Runtime.InteropServices; using System.Windows.Input; using System.Xml; - using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Templates; @@ -101,15 +101,13 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates /// /// This class defines and holds the new file templates. /// - internal class FileTemplate : IComparable + internal class FileTemplateImpl : FileTemplate { - public static List FileTemplates = new List(); - string author = null; string name = null; string category = null; string languagename = null; - string icon = null; + IImage icon = null; string description = null; string wizardpath = null; string defaultName = null; @@ -123,33 +121,24 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates List requiredAssemblyReferences = new List(); XmlElement fileoptions = null; - Action actions; - - int IComparable.CompareTo(object other) - { - FileTemplate pt = other as FileTemplate; - if (pt == null) return -1; - int res = category.CompareTo(pt.category); - if (res != 0) return res; - return name.CompareTo(pt.name); - } + Action actions; public string Author { get { return author; } } - public string Name { + public override string Name { get { return name; } } - public string Category { + public override string Category { get { return category; } } - public string Subcategory { + public override string Subcategory { get { return subcategory; } @@ -159,12 +148,12 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates return languagename; } } - public string Icon { + public override IImage Icon { get { return icon; } } - public string Description { + public override string Description { get { return description; } @@ -219,13 +208,13 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates } } - public FileTemplate(XmlDocument doc, IReadOnlyFileSystem fileSystem) + public FileTemplateImpl(XmlDocument doc, IReadOnlyFileSystem fileSystem) { author = doc.DocumentElement.GetAttribute("author"); XmlElement config = doc.DocumentElement["Config"]; name = config.GetAttribute("name"); - icon = config.GetAttribute("icon"); + icon = SD.ResourceService.GetImage(config.GetAttribute("icon")); category = config.GetAttribute("category"); defaultName = config.GetAttribute("defaultname"); languagename = config.GetAttribute("language"); @@ -279,7 +268,7 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates if (doc.DocumentElement["Actions"] != null) { foreach (XmlElement el in doc.DocumentElement["Actions"]) { - Action action = ReadAction(el); + Action action = ReadAction(el); if (action != null) actions += action; } @@ -297,7 +286,7 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates } } - static Action ReadAction(XmlElement el) + static Action ReadAction(XmlElement el) { switch (el.Name) { case "RunCommand": @@ -319,10 +308,211 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates } } - public void RunActions(FileTemplateOptions options) + public override void RunActions(FileTemplateResult result) { if (actions != null) - actions(options); + actions(result); + } + + public override string SuggestFileName(DirectoryName basePath) + { + if (defaultName.IndexOf("${Number}") >= 0) { + try { + int curNumber = 1; + + while (true) { + string fileName = StringParser.Parse(defaultName, new StringTagPair("Number", curNumber.ToString())); + if (basePath == null) { + bool found = false; + foreach (string openFile in FileService.GetOpenFiles()) { + if (Path.GetFileName(openFile) == fileName) { + found = true; + break; + } + } + if (found == false) + return fileName; + } else if (!File.Exists(Path.Combine(basePath, fileName))) { + return fileName; + } + ++curNumber; + } + } catch (Exception e) { + MessageService.ShowException(e); + } + } + return StringParser.Parse(defaultName); } + + public override object CreateCustomizationObject() + { + if (!HasProperties) + return null; + LocalizedTypeDescriptor localizedTypeDescriptor = new LocalizedTypeDescriptor(); + foreach (TemplateProperty property in Properties) { + LocalizedProperty localizedProperty; + if (property.Type.StartsWith("Types:")) { + localizedProperty = new LocalizedProperty(property.Name, "System.Enum", property.Category, property.Description); + TemplateType type = null; + foreach (TemplateType templateType in CustomTypes) { + if (templateType.Name == property.Type.Substring("Types:".Length)) { + type = templateType; + break; + } + } + if (type == null) { + throw new Exception("type : " + property.Type + " not found."); + } + localizedProperty.TypeConverterObject = new CustomTypeConverter(type); + StringParserPropertyContainer.LocalizedProperty["Properties." + localizedProperty.Name] = property.DefaultValue; + localizedProperty.DefaultValue = property.DefaultValue; // localizedProperty.TypeConverterObject.ConvertFrom(); + } else { + localizedProperty = new LocalizedProperty(property.Name, property.Type, property.Category, property.Description); + if (property.Type == "System.Boolean") { + localizedProperty.TypeConverterObject = new BooleanTypeConverter(); + string defVal = property.DefaultValue == null ? null : property.DefaultValue.ToString(); + if (defVal == null || defVal.Length == 0) { + defVal = "True"; + } + StringParserPropertyContainer.LocalizedProperty["Properties." + localizedProperty.Name] = defVal; + localizedProperty.DefaultValue = Boolean.Parse(defVal); + } else { + string defVal = property.DefaultValue == null ? String.Empty : property.DefaultValue.ToString(); + StringParserPropertyContainer.LocalizedProperty["Properties." + localizedProperty.Name] = defVal; + localizedProperty.DefaultValue = defVal; + } + } + localizedProperty.LocalizedName = property.LocalizedName; + localizedTypeDescriptor.Properties.Add(localizedProperty); + } + return localizedTypeDescriptor; + } + + public override FileTemplateResult Create(FileTemplateOptions options) + { + FileTemplateResult result = new FileTemplateResult(options); + + StringParserPropertyContainer.FileCreation["StandardNamespace"] = options.Namespace; + StringParserPropertyContainer.FileCreation["FullName"] = options.FileName; + StringParserPropertyContainer.FileCreation["FileName"] = Path.GetFileName(options.FileName); + StringParserPropertyContainer.FileCreation["FileNameWithoutExtension"] = Path.GetFileNameWithoutExtension(options.FileName); + StringParserPropertyContainer.FileCreation["Extension"] = Path.GetExtension(options.FileName); + StringParserPropertyContainer.FileCreation["Path"] = Path.GetDirectoryName(options.FileName); + + StringParserPropertyContainer.FileCreation["ClassName"] = options.ClassName; + + // when adding a file to a project (but not when creating a standalone file while a project is open): + var project = options.Project; + if (project != null && !options.IsUntitled) { + // add required assembly references to the project + foreach (ReferenceProjectItem reference in RequiredAssemblyReferences) { + IEnumerable refs = project.GetItemsOfType(ItemType.Reference); + if (!refs.Any(projItem => string.Equals(projItem.Include, reference.Include, StringComparison.OrdinalIgnoreCase))) { + ReferenceProjectItem projItem = (ReferenceProjectItem)reference.CloneFor(project); + ProjectService.AddProjectItem(project, projItem); + ProjectBrowserPad.RefreshViewAsync(); + } + } + } + + foreach (FileDescriptionTemplate newfile in FileDescriptionTemplates) { + if (!IsFilenameAvailable(StringParser.Parse(newfile.Name))) { + MessageService.ShowError(string.Format("Filename {0} is in use.\nChoose another one", StringParser.Parse(newfile.Name))); // TODO : translate + return null; + } + } + var createdFiles = new List>(); + ScriptRunner scriptRunner = new ScriptRunner(); + foreach (FileDescriptionTemplate newFile in FileDescriptionTemplates) { + FileOperationResult opresult = FileUtility.ObservedSave( + () => { + string resultFile; + if (!String.IsNullOrEmpty(newFile.BinaryFileName)) { + resultFile = SaveFile(newFile, null, newFile.BinaryFileName); + } else { + resultFile = SaveFile(newFile, scriptRunner.CompileScript(this, newFile), null); + } + if (resultFile != null) { + result.NewFiles.Add(FileName.Create(resultFile)); + createdFiles.Add(new KeyValuePair(resultFile, newFile)); + } + }, FileName.Create(StringParser.Parse(newFile.Name)) + ); + if (opresult != FileOperationResult.OK) + return null; + } + + if (project != null) { + foreach (KeyValuePair createdFile in createdFiles) { + FileName fileName = FileName.Create(createdFile.Key); + ItemType type = project.GetDefaultItemType(fileName); + FileProjectItem newItem = new FileProjectItem(project, type); + newItem.FileName = fileName; + createdFile.Value.SetProjectItemProperties(newItem); + project.Items.Add(newItem); + } + project.Save(); + } + + // raise FileCreated event for the new files. + foreach (var fileName in result.NewFiles) { + FileService.FireFileCreated(fileName, false); + } + return result; + } + + bool IsFilenameAvailable(string fileName) + { + if (Path.IsPathRooted(fileName)) { + return !File.Exists(fileName); + } + return true; + } + + string SaveFile(FileDescriptionTemplate newfile, string content, string binaryFileName) + { + string unresolvedFileName = StringParser.Parse(newfile.Name); + // Parse twice so that tags used in included standard header are parsed + string parsedContent = StringParser.Parse(StringParser.Parse(content)); + + if (parsedContent != null) { + if (SD.EditorControlService.GlobalOptions.IndentationString != "\t") { + parsedContent = parsedContent.Replace("\t", SD.EditorControlService.GlobalOptions.IndentationString); + } + } + + + // when newFile.Name is "${Path}/${FileName}", there might be a useless '/' in front of the file name + // if the file is created when no project is opened. So we remove single '/' or '\', but not double + // '\\' (project is saved on network share). + if (unresolvedFileName.StartsWith("/") && !unresolvedFileName.StartsWith("//") + || unresolvedFileName.StartsWith("\\") && !unresolvedFileName.StartsWith("\\\\")) + { + unresolvedFileName = unresolvedFileName.Substring(1); + } + + if (newfile.IsDependentFile && Path.IsPathRooted(unresolvedFileName)) { + Directory.CreateDirectory(Path.GetDirectoryName(unresolvedFileName)); + if (!String.IsNullOrEmpty(binaryFileName)) + File.Copy(binaryFileName, unresolvedFileName); + else + File.WriteAllText(unresolvedFileName, parsedContent, SD.FileService.DefaultFileEncoding); + } else { + if (!String.IsNullOrEmpty(binaryFileName)) { + LoggingService.Warn("binary file was skipped"); + return null; + } + IViewContent viewContent = FileService.NewFile(Path.GetFileName(unresolvedFileName), parsedContent); + if (viewContent == null) { + return null; + } + if (Path.IsPathRooted(unresolvedFileName)) { + Directory.CreateDirectory(Path.GetDirectoryName(unresolvedFileName)); + viewContent.PrimaryFile.SaveToDisk(FileName.Create(unresolvedFileName)); + } + } + return unresolvedFileName; + } + } } diff --git a/src/Main/Base/Project/Src/Internal/Templates/File/ScriptRunner.cs b/src/Main/Base/Project/Src/Internal/Templates/File/ScriptRunner.cs index ebc99dd9ed..fb7a98b2c3 100644 --- a/src/Main/Base/Project/Src/Internal/Templates/File/ScriptRunner.cs +++ b/src/Main/Base/Project/Src/Internal/Templates/File/ScriptRunner.cs @@ -15,12 +15,12 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates { internal class ScriptRunner { - FileTemplate item; + FileTemplateImpl item; FileDescriptionTemplate file; readonly static Regex scriptRegex = new Regex("<%.*?%>"); - public string CompileScript(FileTemplate item, FileDescriptionTemplate file) + public string CompileScript(FileTemplateImpl item, FileDescriptionTemplate file) { if (file.Content == null) throw new ArgumentException("file must have textual content"); diff --git a/src/Main/Base/Project/Templates/FileTemplate.cs b/src/Main/Base/Project/Templates/FileTemplate.cs index 6c15daf47f..7c24468f53 100644 --- a/src/Main/Base/Project/Templates/FileTemplate.cs +++ b/src/Main/Base/Project/Templates/FileTemplate.cs @@ -7,7 +7,7 @@ using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.SharpDevelop.Templates { - public abstract class FileTemplate + public abstract class FileTemplate : TemplateBase { /// /// Gets whether this template is available for the specified project. @@ -39,5 +39,9 @@ namespace ICSharpCode.SharpDevelop.Templates /// Instanciates the template, writes the new files to disk, and adds them to the project. /// public abstract FileTemplateResult Create(FileTemplateOptions options); + + public virtual void RunActions(FileTemplateResult result) + { + } } } diff --git a/src/Main/SharpDevelop/Project/ProjectService.cs b/src/Main/SharpDevelop/Project/ProjectService.cs index 3bf70e4895..d7366ded74 100644 --- a/src/Main/SharpDevelop/Project/ProjectService.cs +++ b/src/Main/SharpDevelop/Project/ProjectService.cs @@ -315,7 +315,7 @@ namespace ICSharpCode.SharpDevelop.Project throw new ArgumentNullException("fileName"); if (progress == null) throw new ArgumentNullException("progress"); - if (!Path.IsPathRooted(fileName)) + if (fileName.IsRelative) throw new ArgumentException("Path must be rooted!"); Solution solution = new Solution(fileName, new ProjectChangeWatcher(fileName), SD.FileService); bool ok = false; @@ -333,6 +333,10 @@ namespace ICSharpCode.SharpDevelop.Project public ISolution CreateEmptySolutionFile(FileName fileName) { + if (fileName == null) + throw new ArgumentNullException("fileName"); + if (fileName.IsRelative) + throw new ArgumentException("Path must be rooted!"); Solution solution = new Solution(fileName, new ProjectChangeWatcher(fileName), SD.FileService); solution.LoadPreferences(); return solution; diff --git a/src/Main/SharpDevelop/Services/UIService.cs b/src/Main/SharpDevelop/Services/UIService.cs index 483241dbce..facda98d28 100644 --- a/src/Main/SharpDevelop/Services/UIService.cs +++ b/src/Main/SharpDevelop/Services/UIService.cs @@ -30,31 +30,19 @@ namespace ICSharpCode.SharpDevelop } } - public FileTemplateResult ShowNewFileDialog(IProject project, DirectoryName directory, IEnumerable templates) + public FileTemplateResult ShowNewFileDialog(IProject project, DirectoryName directory, IEnumerable templates) { - using (NewFileDialog nfd = new NewFileDialog(project, directory)) { - if (nfd.ShowDialog(SD.WinForms.MainWin32Window) != DialogResult.OK) + using (NewFileDialog nfd = new NewFileDialog(project, directory, templates ?? SD.Templates.FileTemplates)) { + if (nfd.ShowDialog(SD.WinForms.MainWin32Window) == DialogResult.OK) + return nfd.result; + else return null; - if (project != null) { - foreach (KeyValuePair createdFile in nfd.CreatedFiles) { - FileName fileName = FileName.Create(createdFile.Key); - ItemType type = project.GetDefaultItemType(fileName); - FileProjectItem newItem = new FileProjectItem(project, type); - newItem.FileName = fileName; - createdFile.Value.SetProjectItemProperties(newItem); - project.Items.Add(newItem); - } - project.Save(); - } - var result = new FileTemplateResult(nfd.options); - result.NewFiles.AddRange(nfd.CreatedFiles.Select(p => FileName.Create(p.Key))); - return result; } } - public ProjectTemplateResult ShowNewProjectDialog(ISolutionFolder solutionFolder, IEnumerable templates) + public ProjectTemplateResult ShowNewProjectDialog(ISolutionFolder solutionFolder, IEnumerable templates) { - using (NewProjectDialog npdlg = new NewProjectDialog(createNewSolution: solutionFolder == null)) { + using (NewProjectDialog npdlg = new NewProjectDialog(createNewSolution: solutionFolder == null, projectTemplates: templates ?? SD.Templates.ProjectTemplates)) { npdlg.SolutionFolder = solutionFolder; if (solutionFolder != null) { npdlg.InitialProjectLocationDirectory = AddNewProjectToSolution.GetInitialDirectorySuggestion(solutionFolder); diff --git a/src/Main/SharpDevelop/SharpDevelop.csproj b/src/Main/SharpDevelop/SharpDevelop.csproj index 6751d9273f..c7d11ac22d 100644 --- a/src/Main/SharpDevelop/SharpDevelop.csproj +++ b/src/Main/SharpDevelop/SharpDevelop.csproj @@ -212,9 +212,9 @@ Resources.SplashScreen.jpg - - Always - + + Never + Configuration\GlobalAssemblyInfo.cs GlobalAssemblyInfo.template diff --git a/src/Main/SharpDevelop/Templates/TemplateFileDoozer.cs b/src/Main/SharpDevelop/Templates/TemplateFileDoozer.cs index 05c71e1bde..f6ec35ce7e 100644 --- a/src/Main/SharpDevelop/Templates/TemplateFileDoozer.cs +++ b/src/Main/SharpDevelop/Templates/TemplateFileDoozer.cs @@ -47,9 +47,12 @@ namespace ICSharpCode.SharpDevelop.Templates { var fileSystem = GetFileSystem(args); var templates = new List(); - foreach (var fileName in fileSystem.GetFiles(DirectoryName.Create("."), "*.xpt", SearchOption.AllDirectories)) { + var xpt = fileSystem.GetFiles(DirectoryName.Create("."), "*.xpt", SearchOption.AllDirectories); + var xft = fileSystem.GetFiles(DirectoryName.Create("."), "*.xft", SearchOption.AllDirectories); + foreach (var fileName in xpt.Concat(xft)) { using (var stream = fileSystem.OpenRead(fileName)) { - templates.Add(SD.Templates.LoadTemplate(stream, fileSystem)); + var relFileSystem = new ReadOnlyChrootFileSystem(fileSystem, fileName.GetParentDirectory()); + templates.Add(SD.Templates.LoadTemplate(stream, relFileSystem)); } } if (templates.Count == 1) diff --git a/src/Main/SharpDevelop/Templates/TemplateService.cs b/src/Main/SharpDevelop/Templates/TemplateService.cs index b7d8976d85..654d5bb0b2 100644 --- a/src/Main/SharpDevelop/Templates/TemplateService.cs +++ b/src/Main/SharpDevelop/Templates/TemplateService.cs @@ -56,7 +56,7 @@ namespace ICSharpCode.SharpDevelop.Templates XmlDocument doc = new XmlDocument(); doc.Load(stream); if (doc.DocumentElement["Files"] != null) - throw new NotImplementedException(); + return new FileTemplateImpl(doc, fileSystem); else if (doc.DocumentElement["Project"] != null || doc.DocumentElement["Solution"] != null) return new ProjectTemplateImpl(doc, fileSystem); else diff --git a/src/Main/SharpDevelop/app.config b/src/Main/SharpDevelop/app.config new file mode 100644 index 0000000000..969f663c16 --- /dev/null +++ b/src/Main/SharpDevelop/app.config @@ -0,0 +1,144 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools/UpdateAssemblyInfo/Main.cs b/src/Tools/UpdateAssemblyInfo/Main.cs index 012ca8b073..f65e434bc4 100644 --- a/src/Tools/UpdateAssemblyInfo/Main.cs +++ b/src/Tools/UpdateAssemblyInfo/Main.cs @@ -30,7 +30,7 @@ namespace UpdateAssemblyInfo }, new TemplateFile { Input = "src/Main/SharpDevelop/app.template.config", - Output = "src/Main/SharpDevelop/SharpDevelop.exe.config" + Output = "src/Main/SharpDevelop/app.config" }, new TemplateFile { Input = "src/Setup/SharpDevelop.Setup.wixproj.user.template",