Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs')
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs1859
1 files changed, 1070 insertions, 789 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
index 3dd753efab..4cf410e674 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
@@ -1,4 +1,4 @@
-// SolutionItem.cs
+// SolutionEntityItem.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
@@ -26,419 +26,301 @@
//
using System;
+using System.Linq;
+using System.Xml;
+using System.IO;
using System.Collections;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Xml;
+using System.Collections.Specialized;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Diagnostics;
using System.CodeDom.Compiler;
+
using MonoDevelop.Core;
+using MonoDevelop.Projects;
using MonoDevelop.Core.Serialization;
-using MonoDevelop.Projects.Extensions;
-using MonoDevelop.Core.Collections;
+using MonoDevelop.Projects.Extensions;
using MonoDevelop.Core.StringParsing;
-using MonoDevelop.Core.Instrumentation;
-using MonoDevelop.Projects.Policies;
using MonoDevelop.Core.Execution;
+using Mono.Addins;
+using MonoDevelop.Core.Instrumentation;
+using MonoDevelop.Core.Collections;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
- public abstract class SolutionItem: IExtendedDataItem, IBuildTarget, ILoadController, IPolicyProvider
+ public abstract class SolutionItem : SolutionFolderItem, IWorkspaceFileObject, IConfigurationTarget, ILoadController, IBuildTarget
{
- SolutionFolder parentFolder;
- Solution parentSolution;
- ISolutionItemHandler handler;
+ internal object MemoryProbe = Counters.ItemsInMemory.CreateMemoryProbe ();
+
int loading;
- SolutionFolder internalChildren;
+ ProjectItemCollection items;
+ ProjectItemCollection wildcardItems;
+ ItemCollection<SolutionItem> dependencies = new ItemCollection<SolutionItem> ();
+
+ SolutionItemEventArgs thisItemArgs;
- [ProjectPathItemProperty ("BaseDirectory", DefaultValue=null)]
- string baseDirectory;
+ FileStatusTracker<SolutionItemEventArgs> fileStatusTracker;
+
+ FilePath fileName;
+ string name;
- Hashtable extendedProperties;
+ FileFormat fileFormat;
- [ItemProperty ("Policies", IsExternal = true, SkipEmpty = true)]
- MonoDevelop.Projects.Policies.PolicyBag policies;
+ SolutionItemConfiguration activeConfiguration;
+ SolutionItemConfigurationCollection configurations;
- [ItemProperty ("UseMSBuildEngine")]
- public bool? UseMSBuildEngine { get; set; }
-
- PropertyBag userProperties;
+ public event EventHandler ConfigurationsChanged;
+ public event ConfigurationEventHandler DefaultConfigurationChanged;
+ public event ConfigurationEventHandler ConfigurationAdded;
+ public event ConfigurationEventHandler ConfigurationRemoved;
+ public event EventHandler<ProjectItemEventArgs> ProjectItemAdded;
+ public event EventHandler<ProjectItemEventArgs> ProjectItemRemoved;
+
+ // When set, it means this item is saved as part of a global solution save operation
+ internal bool SavingSolution { get; set; }
- /// <summary>
- /// Initializes a new instance of the <see cref="MonoDevelop.Projects.SolutionItem"/> class.
- /// </summary>
- public SolutionItem()
+ public SolutionItem ()
{
+ var fmt = Services.ProjectService.FileFormats.GetFileFormat (MSBuildProjectService.DefaultFormat);
+ TypeGuid = MSBuildProjectService.GetTypeGuidForItem (this);
+
+ SetSolutionFormat ((MSBuildFileFormat)fmt.Format, true);
ProjectExtensionUtil.LoadControl (this);
+ items = new ProjectItemCollection (this);
+ wildcardItems = new ProjectItemCollection (this);
+ thisItemArgs = new SolutionItemEventArgs (this);
+ configurations = new SolutionItemConfigurationCollection (this);
+ configurations.ConfigurationAdded += OnConfigurationAddedToCollection;
+ configurations.ConfigurationRemoved += OnConfigurationRemovedFromCollection;
+ Counters.ItemsLoaded++;
+ fileStatusTracker = new FileStatusTracker<SolutionItemEventArgs> (this, OnReloadRequired, new SolutionItemEventArgs (this));
}
-
- /// <summary>
- /// Initializes a new instance of this item, using an xml element as template
- /// </summary>
- /// <param name='template'>
- /// The template
- /// </param>
- public virtual void InitializeFromTemplate (XmlElement template)
- {
- }
-
- /// <summary>
- /// Gets the handler for this solution item
- /// </summary>
- /// <value>
- /// The solution item handler.
- /// </value>
- /// <exception cref='InvalidOperationException'>
- /// Is thrown if there isn't a ISolutionItemHandler for this solution item
- /// </exception>
- protected internal ISolutionItemHandler ItemHandler {
+
+ SolutionItemExtension itemExtension;
+
+ SolutionItemExtension ItemExtension {
get {
- if (handler == null) {
- InitializeItemHandler ();
- if (handler == null)
- throw new InvalidOperationException ("No handler found for solution item of type: " + GetType ());
- }
- return handler;
+ if (itemExtension == null)
+ itemExtension = ExtensionChain.GetExtension<SolutionItemExtension> ();
+ return itemExtension;
}
}
-
- /// <summary>
- /// Sets the handler for this solution item
- /// </summary>
- /// <param name='handler'>
- /// A handler.
- /// </param>
- internal virtual void SetItemHandler (ISolutionItemHandler handler)
+
+ protected override IEnumerable<WorkspaceObjectExtension> CreateDefaultExtensions ()
{
- if (this.handler != null)
- this.handler.Dispose ();
- this.handler = handler;
+ foreach (var e in base.CreateDefaultExtensions ())
+ yield return e;
+ yield return new DefaultMSBuildItemExtension ();
}
-
- internal ISolutionItemHandler GetItemHandler ()
+
+ internal protected virtual IEnumerable<string> GetItemTypeGuids ()
{
- // Used to get the handler without lazy loading it
- return this.handler;
+ yield return TypeGuid;
}
-
- /// <summary>
- /// Gets the author information for this solution item, inherited from the solution and global settings.
- /// </summary>
- public AuthorInformation AuthorInformation {
- get {
- if (ParentSolution != null)
- return ParentSolution.AuthorInformation;
- else
- return AuthorInformation.Default;
- }
- }
-
- /// <summary>
- /// Gets a service instance of a given type
- /// </summary>
- /// <returns>
- /// The service.
- /// </returns>
- /// <typeparam name='T'>
- /// Type of the service
- /// </typeparam>
- /// <remarks>
- /// This method looks for an imlpementation of a service of the given type.
- /// </remarks>
- public T GetService<T> () where T: class
+
+ public override void Dispose ()
{
- return (T) GetService (typeof(T));
+ base.Dispose ();
+ Counters.ItemsLoaded--;
+
+ foreach (var item in items.Concat (wildcardItems)) {
+ IDisposable disp = item as IDisposable;
+ if (disp != null)
+ disp.Dispose ();
+ }
+
+ // items = null;
+ // wildcardItems = null;
+ // thisItemArgs = null;
+ // fileStatusTracker = null;
+ // fileFormat = null;
+ // activeConfiguration = null;
+ // configurations = null;
}
- /// <summary>
- /// Gets a service instance of a given type
- /// </summary>
- /// <returns>
- /// The service.
- /// </returns>
- /// <param name='t'>
- /// Type of the service
- /// </param>
- /// <remarks>
- /// This method looks for an imlpementation of a service of the given type.
- /// </remarks>
- public virtual object GetService (Type t)
+ void HandleSolutionItemAdded (object sender, SolutionItemChangeEventArgs e)
{
- return Services.ProjectService.GetExtensionChain (this).GetService (this, t);
- }
-
- /// <summary>
- /// Gets the solution to which this item belongs
- /// </summary>
- public Solution ParentSolution {
- get {
- if (parentFolder != null)
- return parentFolder.ParentSolution;
- return parentSolution;
- }
- internal set {
- parentSolution = value;
- NotifyBoundToSolution (true);
+ if (e.Reloading && dependencies.Count > 0 && (e.SolutionItem is SolutionItem) && (e.ReplacedItem is SolutionItem)) {
+ int i = dependencies.IndexOf ((SolutionItem)e.ReplacedItem);
+ if (i != -1)
+ dependencies [i] = (SolutionItem) e.SolutionItem;
}
}
- /// <summary>
- /// Gets a value indicating whether this item is currently being loaded from a file
- /// </summary>
- /// <remarks>
- /// While an item is loading, some events such as project file change events may be fired.
- /// This flag can be used to check if change events are caused by data being loaded.
- /// </remarks>
- public bool Loading {
- get { return loading > 0; }
- }
-
- /// <summary>
- /// Saves the solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor.
- /// </param>
- public abstract void Save (IProgressMonitor monitor);
-
- /// <summary>
- /// Name of the solution item
- /// </summary>
- public abstract string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the base directory of this solution item
- /// </summary>
- /// <value>
- /// The base directory.
- /// </value>
- /// <remarks>
- /// The base directory is the directory where files belonging to this project
- /// are placed. Notice that this directory may be different than the directory
- /// where the project file is placed.
- /// </remarks>
- public FilePath BaseDirectory {
- get {
- if (baseDirectory == null) {
- FilePath dir = GetDefaultBaseDirectory ();
- if (dir.IsNullOrEmpty)
- dir = ".";
- return dir.FullPath;
- }
- else
- return baseDirectory;
- }
- set {
- FilePath def = GetDefaultBaseDirectory ();
- if (value != FilePath.Null && def != FilePath.Null && value.FullPath == def.FullPath)
- baseDirectory = null;
- else if (string.IsNullOrEmpty (value))
- baseDirectory = null;
- else
- baseDirectory = value.FullPath;
- NotifyModified ("BaseDirectory");
- }
+ void HandleSolutionItemRemoved (object sender, SolutionItemChangeEventArgs e)
+ {
+ if (!e.Reloading && (e.SolutionItem is SolutionItem))
+ dependencies.Remove ((SolutionItem)e.SolutionItem);
}
-
- /// <summary>
- /// Gets the directory where this solution item is placed
- /// </summary>
- public FilePath ItemDirectory {
- get {
- FilePath dir = GetDefaultBaseDirectory ();
- if (string.IsNullOrEmpty (dir))
- dir = ".";
- return dir.FullPath;
- }
+
+ void ILoadController.BeginLoad ()
+ {
+ loading++;
+ OnBeginLoad ();
}
-
- internal bool HasCustomBaseDirectory {
- get { return baseDirectory != null; }
- }
-
- /// <summary>
- /// Gets the default base directory.
- /// </summary>
- /// <remarks>
- /// The base directory is the directory where files belonging to this project
- /// are placed. Notice that this directory may be different than the directory
- /// where the project file is placed.
- /// </remarks>
- protected virtual FilePath GetDefaultBaseDirectory ( )
+
+ void ILoadController.EndLoad ()
{
- return ParentSolution.BaseDirectory;
+ loading--;
+ OnEndLoad ();
}
/// <summary>
- /// Gets the identifier of this solution item
+ /// Called when a load operation for this solution item has started
/// </summary>
- /// <remarks>
- /// The identifier is unique inside the solution
- /// </remarks>
- public string ItemId {
- get { return ItemHandler.ItemId; }
+ protected virtual void OnBeginLoad ()
+ {
}
-
+
/// <summary>
- /// Gets extended properties.
+ /// Called when a load operation for this solution item has finished
/// </summary>
- /// <remarks>
- /// This dictionary can be used by add-ins to store arbitrary information about this solution item.
- /// Keys and values can be of any type.
- /// If a value implements IDisposable, the value will be disposed when this solution item is disposed.
- /// Values in this dictionary won't be serialized, unless they are registered as serializable using
- /// the /MonoDevelop/ProjectModel/ExtendedProperties extension point.
- /// </remarks>
- public IDictionary ExtendedProperties {
- get { return InternalGetExtendedProperties; }
+ protected virtual void OnEndLoad ()
+ {
+ fileStatusTracker.ResetLoadTimes ();
+
+ if (syncReleaseVersion && ParentSolution != null)
+ releaseVersion = ParentSolution.Version;
}
+
+ [ItemProperty ("ReleaseVersion", DefaultValue="0.1")]
+ string releaseVersion = "0.1";
- /// <summary>
- /// Gets policies.
- /// </summary>
- /// <remarks>
- /// Returns a policy container which can be used to query policies specific for this
- /// solution item. If a policy is not defined for this item, the inherited value will be returned.
- /// </remarks>
- public MonoDevelop.Projects.Policies.PolicyBag Policies {
+ [ItemProperty ("SynchReleaseVersion", DefaultValue = true)]
+ bool syncReleaseVersion = true;
+
+ public string Version {
get {
- //newly created (i.e. not deserialised) SolutionItems may have a null PolicyBag
- if (policies == null)
- policies = new MonoDevelop.Projects.Policies.PolicyBag ();
- //this is the easiest reliable place to associate a deserialised Policybag with its owner
- policies.Owner = this;
- return policies;
+ // If syncReleaseVersion is set, releaseVersion will already contain the solution's version
+ // That's because the version must be up to date even when loading the project individually
+ return releaseVersion;
}
- //setter so that a solution can deserialise the PropertyBag on its RootFolder
- internal set {
- policies = value;
+ set {
+ releaseVersion = value;
+ NotifyModified ("Version");
}
}
- PolicyContainer IPolicyProvider.Policies {
+ public bool SyncVersionWithSolution {
get {
- return Policies;
+ return syncReleaseVersion;
+ }
+ set {
+ syncReleaseVersion = value;
+ if (syncReleaseVersion && ParentSolution != null)
+ Version = ParentSolution.Version;
+ NotifyModified ("SyncVersionWithSolution");
}
}
- /// <summary>
- /// Gets solution item properties specific to the current user
- /// </summary>
- /// <remarks>
- /// These properties are not stored in the project file, but in a separate file which is not to be shared
- /// with other users.
- /// User properties are only loaded when the project is loaded inside the IDE.
- /// </remarks>
- public PropertyBag UserProperties {
- get {
- if (userProperties == null)
- userProperties = new PropertyBag ();
- return userProperties;
+ protected override string OnGetName ()
+ {
+ return name ?? string.Empty;
+ }
+
+ protected override void OnSetName (string value)
+ {
+ name = value;
+ if (!Loading && SyncFileName) {
+ if (string.IsNullOrEmpty (fileName))
+ FileName = value;
+ else {
+ string ext = fileName.Extension;
+ FileName = fileName.ParentDirectory.Combine (value) + ext;
+ }
}
}
-
+
/// <summary>
- /// Initializes the user properties of the item
+ /// Returns a value indicating whether the name of the solution item should be the same as the name of the file
/// </summary>
- /// <param name='properties'>
- /// Properties to be set
- /// </param>
- /// <exception cref='InvalidOperationException'>
- /// The user properties have already been set
- /// </exception>
- /// <remarks>
- /// This method is used by the IDE to initialize the user properties when a project is loaded.
- /// </remarks>
- public void LoadUserProperties (PropertyBag properties)
- {
- if (userProperties != null)
- throw new InvalidOperationException ("User properties already loaded.");
- userProperties = properties;
+ /// <value>
+ /// <c>true</c> if the file name must be in sync with the solution item name; otherwise, <c>false</c>.
+ /// </value>
+ protected virtual bool SyncFileName {
+ get { return true; }
}
- /// <summary>
- /// Gets the parent solution folder.
- /// </summary>
- public SolutionFolder ParentFolder {
+ public virtual FilePath FileName {
get {
- return parentFolder;
+ return fileName;
}
- internal set {
- parentFolder = value;
- if (internalChildren != null) {
- internalChildren.ParentFolder = value;
- }
- if (value != null && value.ParentSolution != null) {
- NotifyBoundToSolution (false);
+ set {
+ if (FileFormat != null)
+ value = FileFormat.GetValidFileName (this, value);
+ if (value != fileName) {
+ fileName = value;
+ if (SyncFileName)
+ Name = fileName.FileNameWithoutExtension;
+ NotifyModified ("FileName");
}
}
}
- // Normally, the ParentFolder setter fires OnBoundToSolution. However, when deserializing, child
- // ParentFolder hierarchies can become connected before the ParentSolution becomes set. This method
- // enables us to recursively fire the OnBoundToSolution call in those cases.
- void NotifyBoundToSolution (bool includeInternalChildren)
- {
- var folder = this as SolutionFolder;
- if (folder != null) {
- var items = folder.GetItemsWithoutCreating ();
- if (items != null) {
- foreach (var item in items) {
- item.NotifyBoundToSolution (includeInternalChildren);
- }
+ public bool Enabled {
+ get { return ParentSolution != null ? ParentSolution.IsSolutionItemEnabled (FileName) : true; }
+ set {
+ if (ParentSolution != null)
+ ParentSolution.SetSolutionItemEnabled (FileName, value);
+ }
+ }
+
+ public FileFormat FileFormat {
+ get {
+ if (ParentSolution != null) {
+ if (ParentSolution.FileFormat.Format.SupportsMixedFormats && fileFormat != null)
+ return fileFormat;
+ return ParentSolution.FileFormat;
}
+ if (fileFormat == null)
+ fileFormat = Services.ProjectService.GetDefaultFormat (this);
+ return fileFormat;
}
- if (includeInternalChildren && internalChildren != null) {
- internalChildren.NotifyBoundToSolution (includeInternalChildren);
+ set {
+ if (ParentSolution != null && !ParentSolution.FileFormat.Format.SupportsMixedFormats)
+ throw new InvalidOperationException ("The file format can't be changed when the item belongs to a solution.");
+ InstallFormat (value);
+ fileFormat.Format.ConvertToFormat (this);
+ NeedsReload = false;
+ NotifyModified ("FileFormat");
}
- OnBoundToSolution ();
+ }
+
+ protected override object OnGetService (Type t)
+ {
+ return null;
}
+ public ProjectItemCollection Items {
+ get { return items; }
+ }
+ internal ProjectItemCollection WildcardItems {
+ get { return wildcardItems; }
+ }
+
/// <summary>
- /// Gets a value indicating whether this <see cref="MonoDevelop.Projects.SolutionItem"/> has been disposed.
+ /// Projects that need to be built before building this one
/// </summary>
- /// <value>
- /// <c>true</c> if disposed; otherwise, <c>false</c>.
- /// </value>
- internal protected bool Disposed { get; private set; }
+ /// <value>The dependencies.</value>
+ public ItemCollection<SolutionItem> ItemDependencies {
+ get { return dependencies; }
+ }
/// <summary>
- /// Releases all resource used by the <see cref="MonoDevelop.Projects.SolutionItem"/> object.
+ /// Gets a value indicating whether this item is currently being loaded from a file
/// </summary>
/// <remarks>
- /// Call <see cref="Dispose"/> when you are finished using the <see cref="MonoDevelop.Projects.SolutionItem"/>. The
- /// <see cref="Dispose"/> method leaves the <see cref="MonoDevelop.Projects.SolutionItem"/> in an unusable state.
- /// After calling <see cref="Dispose"/>, you must release all references to the
- /// <see cref="MonoDevelop.Projects.SolutionItem"/> so the garbage collector can reclaim the memory that the
- /// <see cref="MonoDevelop.Projects.SolutionItem"/> was occupying.
+ /// While an item is loading, some events such as project file change events may be fired.
+ /// This flag can be used to check if change events are caused by data being loaded.
/// </remarks>
- public virtual void Dispose ()
- {
- Disposed = true;
-
- if (extendedProperties != null) {
- foreach (object ob in extendedProperties.Values) {
- IDisposable disp = ob as IDisposable;
- if (disp != null)
- disp.Dispose ();
- }
- extendedProperties = null;
- }
- if (handler != null) {
- handler.Dispose ();
- // handler = null;
- }
- if (userProperties != null) {
- ((IDisposable)userProperties).Dispose ();
- userProperties = null;
- }
-
- // parentFolder = null;
- // parentSolution = null;
- // internalChildren = null;
- // policies = null;
+ public bool Loading {
+ get { return loading > 0; }
}
-
+
/// <summary>
/// Gets solution items referenced by this instance (items on which this item depends)
/// </summary>
@@ -448,94 +330,215 @@ namespace MonoDevelop.Projects
/// <param name='configuration'>
/// Configuration for which to get the referenced items
/// </param>
- public virtual IEnumerable<SolutionItem> GetReferencedItems (ConfigurationSelector configuration)
+ public IEnumerable<SolutionItem> GetReferencedItems (ConfigurationSelector configuration)
+ {
+ return ItemExtension.OnGetReferencedItems (configuration);
+ }
+
+ protected virtual IEnumerable<SolutionItem> OnGetReferencedItems (ConfigurationSelector configuration)
+ {
+ return dependencies;
+ }
+
+ Task IWorkspaceFileObject.ConvertToFormat (FileFormat format, bool convertChildren)
+ {
+ this.FileFormat = format;
+ return Task.FromResult (0);
+ }
+
+ public bool SupportsFormat (FileFormat format)
+ {
+ return ItemExtension.OnGetSupportsFormat (format);
+ }
+
+ protected virtual bool OnGetSupportsFormat (FileFormat format)
+ {
+ return true;
+ }
+
+ internal void InstallFormat (FileFormat format)
{
- return new SolutionItem [0];
+ fileFormat = format;
+ if (fileName != FilePath.Null)
+ fileName = fileFormat.GetValidFileName (this, fileName);
}
/// <summary>
- /// Runs a build or execution target.
+ /// Initializes a new instance of this item, using an xml element as template
/// </summary>
- /// <returns>
- /// The result of the operation
- /// </returns>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='target'>
- /// Name of the target
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to run the target
+ /// <param name='template'>
+ /// The template
/// </param>
- public BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ public void InitializeFromTemplate (XmlElement template)
{
- return Services.ProjectService.GetExtensionChain (this).RunTarget (monitor, this, target, configuration);
+ ItemExtension.OnInitializeFromTemplate (template);
}
-
- public bool SupportsTarget (string target)
+
+ protected virtual void OnInitializeFromTemplate (XmlElement template)
{
- return Services.ProjectService.GetExtensionChain (this).SupportsTarget (this, target);
}
- public bool SupportsBuild ()
+ public virtual void InitializeNew (ProjectCreateInformation projectCreateInfo, XmlElement projectOptions)
{
- return SupportsTarget (ProjectService.BuildTarget);
}
- public bool SupportsExecute ()
+ protected override FilePath GetDefaultBaseDirectory ( )
{
- return Services.ProjectService.GetExtensionChain (this).SupportsExecute (this);
+ return ItemExtension.OnGetDefaultBaseDirectory ();
}
+ internal Task LoadAsync (ProgressMonitor monitor, FilePath fileName, MSBuildFileFormat format)
+ {
+ FileName = fileName;
+ Name = Path.GetFileNameWithoutExtension (fileName);
+ SetSolutionFormat (format ?? new MSBuildFileFormatVS12 (), false);
+ return ItemExtension.OnLoad (monitor);
+ }
+
+ public void Save (ProgressMonitor monitor, FilePath fileName)
+ {
+ SaveAsync (monitor, fileName).Wait ();
+ }
+
+ public Task SaveAsync (ProgressMonitor monitor, FilePath fileName)
+ {
+ FileName = fileName;
+ return SaveAsync (monitor);
+ }
+
/// <summary>
- /// Cleans the files produced by this solution item
+ /// Saves the solution item
/// </summary>
/// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to clean the project
+ /// A progress monitor.
/// </param>
- public void Clean (IProgressMonitor monitor, ConfigurationSelector configuration)
+ public void Save (ProgressMonitor monitor)
{
- ITimeTracker tt = Counters.BuildProjectTimer.BeginTiming ("Cleaning " + Name);
+ ItemExtension.OnSave (monitor).Wait ();
+ }
+
+
+ public async Task SaveAsync (ProgressMonitor monitor)
+ {
+ await ItemExtension.OnSave (monitor);
+
+ if (HasSlnData && !SavingSolution && ParentSolution != null) {
+ // The project has data that has to be saved in the solution, but the solution is not being saved. Do it now.
+ await SolutionFormat.SlnFileFormat.WriteFile (ParentSolution.FileName, ParentSolution, false, monitor);
+ ParentSolution.NeedsReload = false;
+ }
+ }
+
+ async Task DoSave (ProgressMonitor monitor)
+ {
+ if (string.IsNullOrEmpty (FileName))
+ throw new InvalidOperationException ("Project does not have a file name");
+
try {
- //SolutionFolder handles the begin/end task itself, don't duplicate
- if (this is SolutionFolder) {
- RunTarget (monitor, ProjectService.CleanTarget, configuration);
- return;
- }
-
- try {
- SolutionEntityItem it = this as SolutionEntityItem;
- SolutionItemConfiguration iconf = it != null ? it.GetConfiguration (configuration) : null;
- string confName = iconf != null ? iconf.Id : configuration.ToString ();
- monitor.BeginTask (GettextCatalog.GetString ("Cleaning: {0} ({1})", Name, confName), 1);
- RunTarget (monitor, ProjectService.CleanTarget, configuration);
- } finally {
- monitor.EndTask ();
- }
+ fileStatusTracker.BeginSave ();
+ await OnSave (monitor);
+ OnSaved (thisItemArgs);
+ } finally {
+ fileStatusTracker.EndSave ();
}
- finally {
- tt.End ();
+ FileService.NotifyFileChanged (FileName);
+ }
+
+ internal bool IsSaved {
+ get {
+ return !string.IsNullOrEmpty (FileName) && File.Exists (FileName);
}
}
+ public override bool NeedsReload {
+ get { return fileStatusTracker.NeedsReload; }
+ set { fileStatusTracker.NeedsReload = value; }
+ }
+
+ public virtual bool ItemFilesChanged {
+ get { return ItemExtension.ItemFilesChanged; }
+ }
+
+ bool BaseItemFilesChanged {
+ get { return fileStatusTracker.ItemFilesChanged; }
+ }
+
+ public bool SupportsBuild ()
+ {
+ return ItemExtension.OnSupportsBuild ();
+ }
+
+ protected virtual bool OnGetSupportsBuild ()
+ {
+ return true;
+ }
+
+ public bool SupportsExecute ()
+ {
+ return ItemExtension.OnSupportsExecute ();
+ }
+
+ protected virtual bool OnGetSupportsExecute ()
+ {
+ return true;
+ }
+
+ public virtual bool SupportsConfigurations ()
+ {
+ // TODO NPM: -> extension chain
+ return SupportsBuild ();
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this project is supported.
+ /// </summary>
+ /// <remarks>
+ /// Unsupported projects are shown in the solution pad, but operations such as building on executing won't be available.
+ /// </remarks>
+ public bool IsUnsupportedProject { get; protected set; }
+
+ /// <summary>
+ /// Gets a message that explain why the project is not supported (when IsUnsupportedProject returns true)
+ /// </summary>
+ public string UnsupportedProjectMessage {
+ get { return IsUnsupportedProject ? (loadError ?? GettextCatalog.GetString ("Unknown project type")) : ""; }
+ set { loadError = value; }
+ }
+ string loadError;
+
+ public bool NeedsBuilding (ConfigurationSelector configuration)
+ {
+ return ItemExtension.OnNeedsBuilding (configuration);
+ }
+
+ internal protected virtual bool OnGetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ return false;
+ }
+
+ public void SetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ OnSetNeedsBuilding (configuration);
+ }
+
+ protected virtual void OnSetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ }
+
/// <summary>
/// Builds the solution item
/// </summary>
/// <param name='monitor'>
/// A progress monitor
/// </param>
- /// <param name='configuration'>
+ /// <param name='solutionConfiguration'>
/// Configuration to use to build the project
/// </param>
- public BuildResult Build (IProgressMonitor monitor, ConfigurationSelector configuration)
+ public Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector solutionConfiguration)
{
- return Build (monitor, configuration, false);
+ return Build (monitor, solutionConfiguration, false);
}
-
+
/// <summary>
/// Builds the solution item
/// </summary>
@@ -548,54 +551,47 @@ namespace MonoDevelop.Projects
/// <param name='buildReferences'>
/// When set to <c>true</c>, the referenced items will be built before building this item
/// </param>
- public BuildResult Build (IProgressMonitor monitor, ConfigurationSelector solutionConfiguration, bool buildReferences)
+ public async Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector solutionConfiguration, bool buildReferences)
{
ITimeTracker tt = Counters.BuildProjectTimer.BeginTiming ("Building " + Name);
try {
if (!buildReferences) {
- //SolutionFolder's OnRunTarget handles the begin/end task itself, don't duplicate
- if (this is SolutionFolder) {
- return RunTarget (monitor, ProjectService.BuildTarget, solutionConfiguration);
- }
-
try {
- SolutionEntityItem it = this as SolutionEntityItem;
- SolutionItemConfiguration iconf = it != null ? it.GetConfiguration (solutionConfiguration) : null;
+ SolutionItemConfiguration iconf = GetConfiguration (solutionConfiguration);
string confName = iconf != null ? iconf.Id : solutionConfiguration.ToString ();
monitor.BeginTask (GettextCatalog.GetString ("Building: {0} ({1})", Name, confName), 1);
-
- // This will end calling OnBuild ()
- return RunTarget (monitor, ProjectService.BuildTarget, solutionConfiguration);
-
+
+ return await InternalBuild (monitor, solutionConfiguration);
+
} finally {
monitor.EndTask ();
}
}
-
+
// Get a list of all items that need to be built (including this),
// and build them in the correct order
-
- List<SolutionItem> referenced = new List<SolutionItem> ();
- Set<SolutionItem> visited = new Set<SolutionItem> ();
+
+ var referenced = new List<SolutionItem> ();
+ var visited = new Set<SolutionItem> ();
GetBuildableReferencedItems (visited, referenced, this, solutionConfiguration);
-
- ReadOnlyCollection<SolutionItem> sortedReferenced = SolutionFolder.TopologicalSort (referenced, solutionConfiguration);
-
+
+ var sortedReferenced = TopologicalSort (referenced, solutionConfiguration);
+
BuildResult cres = new BuildResult ();
cres.BuildCount = 0;
- HashSet<SolutionItem> failedItems = new HashSet<SolutionItem> ();
-
+ var failedItems = new HashSet<SolutionItem> ();
+
monitor.BeginTask (null, sortedReferenced.Count);
- foreach (SolutionItem p in sortedReferenced) {
+ foreach (var p in sortedReferenced) {
if (!p.ContainsReferences (failedItems, solutionConfiguration)) {
- BuildResult res = p.Build (monitor, solutionConfiguration, false);
+ BuildResult res = await p.Build (monitor, solutionConfiguration, false);
cres.Append (res);
if (res.ErrorCount > 0)
failedItems.Add (p);
} else
failedItems.Add (p);
monitor.Step (1);
- if (monitor.IsCancelRequested)
+ if (monitor.CancellationToken.IsCancellationRequested)
break;
}
monitor.EndTask ();
@@ -604,40 +600,258 @@ namespace MonoDevelop.Projects
tt.End ();
}
}
-
+
+ async Task<BuildResult> InternalBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ if (IsUnsupportedProject) {
+ var r = new BuildResult ();
+ r.AddError (UnsupportedProjectMessage);
+ return r;
+ }
+
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.BeforeBuild, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.BeforeBuild, configuration)) {
+ var r = new BuildResult ();
+ r.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ return r;
+ }
+ }
+ }
+
+ if (monitor.CancellationToken.IsCancellationRequested)
+ return new BuildResult (new CompilerResults (null), "");
+
+ BuildResult res = await ItemExtension.OnBuild (monitor, configuration);
+
+ if (conf != null && !monitor.CancellationToken.IsCancellationRequested && !res.Failed) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.AfterBuild, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.AfterBuild, configuration))
+ res.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ }
+ }
+
+ return res;
+ }
+
+ /// <summary>
+ /// Builds the solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to build the project
+ /// </param>
+ protected virtual Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Task.FromResult (BuildResult.Success);
+ }
+
+ void GetBuildableReferencedItems (Set<SolutionItem> visited, List<SolutionItem> referenced, SolutionItem item, ConfigurationSelector configuration)
+ {
+ if (!visited.Add(item))
+ return;
+
+ referenced.Add (item);
+
+ foreach (var ritem in item.GetReferencedItems (configuration))
+ GetBuildableReferencedItems (visited, referenced, ritem, configuration);
+ }
+
internal bool ContainsReferences (HashSet<SolutionItem> items, ConfigurationSelector conf)
{
- foreach (SolutionItem it in GetReferencedItems (conf))
+ foreach (var it in GetReferencedItems (conf))
if (items.Contains (it))
return true;
return false;
}
/// <summary>
- /// Gets the time of the last build
+ /// Cleans the files produced by this solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to clean the project
+ /// </param>
+ public async Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ ITimeTracker tt = Counters.BuildProjectTimer.BeginTiming ("Cleaning " + Name);
+ try {
+ try {
+ SolutionItemConfiguration iconf = GetConfiguration (configuration);
+ string confName = iconf != null ? iconf.Id : configuration.ToString ();
+ monitor.BeginTask (GettextCatalog.GetString ("Cleaning: {0} ({1})", Name, confName), 1);
+
+ SolutionItemConfiguration conf = GetConfiguration (configuration);
+ if (conf != null) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.BeforeClean, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.BeforeClean, configuration)) {
+ var r = new BuildResult ();
+ r.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ return r;
+ }
+ }
+ }
+
+ if (monitor.CancellationToken.IsCancellationRequested)
+ return BuildResult.Success;
+
+ var res = await ItemExtension.OnClean (monitor, configuration);
+
+ if (conf != null && !monitor.CancellationToken.IsCancellationRequested) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.AfterClean, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.AfterClean, configuration))
+ res.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ }
+ }
+ return res;
+
+ } finally {
+ monitor.EndTask ();
+ }
+ }
+ finally {
+ tt.End ();
+ }
+ }
+
+ /// <summary>
+ /// Cleans the files produced by this solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to clean the project
+ /// </param>
+ protected virtual Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Task.FromResult (BuildResult.Success);
+ }
+
+ /// <summary>
+ /// Sorts a collection of solution items, taking into account the dependencies between them
/// </summary>
/// <returns>
- /// The last build time.
+ /// The sorted collection of items
/// </returns>
+ /// <param name='items'>
+ /// Items to sort
+ /// </param>
/// <param name='configuration'>
- /// Configuration for which to get the last build time.
+ /// A configuration
/// </param>
- public DateTime GetLastBuildTime (ConfigurationSelector configuration)
+ /// <remarks>
+ /// This methods sorts a collection of items, ensuring that every item is placed after all the items
+ /// on which it depends.
+ /// </remarks>
+ public static ReadOnlyCollection<T> TopologicalSort<T> (IEnumerable<T> items, ConfigurationSelector configuration) where T: SolutionItem
+ {
+ IList<T> allItems;
+ allItems = items as IList<T>;
+ if (allItems == null)
+ allItems = new List<T> (items);
+
+ List<T> sortedEntries = new List<T> ();
+ bool[] inserted = new bool[allItems.Count];
+ bool[] triedToInsert = new bool[allItems.Count];
+ for (int i = 0; i < allItems.Count; ++i) {
+ if (!inserted[i])
+ Insert<T> (i, allItems, sortedEntries, inserted, triedToInsert, configuration);
+ }
+ return sortedEntries.AsReadOnly ();
+ }
+
+ static void Insert<T> (int index, IList<T> allItems, List<T> sortedItems, bool[] inserted, bool[] triedToInsert, ConfigurationSelector solutionConfiguration) where T: SolutionItem
{
- return OnGetLastBuildTime (configuration);
+ if (triedToInsert[index]) {
+ throw new CyclicDependencyException ();
+ }
+ triedToInsert[index] = true;
+ var insertItem = allItems[index];
+
+ foreach (var reference in insertItem.GetReferencedItems (solutionConfiguration)) {
+ for (int j=0; j < allItems.Count; ++j) {
+ SolutionFolderItem checkItem = allItems[j];
+ if (reference == checkItem) {
+ if (!inserted[j])
+ Insert (j, allItems, sortedItems, inserted, triedToInsert, solutionConfiguration);
+ break;
+ }
+ }
+ }
+ sortedItems.Add (insertItem);
+ inserted[index] = true;
}
-
- void GetBuildableReferencedItems (Set<SolutionItem> visited, List<SolutionItem> referenced, SolutionItem item, ConfigurationSelector configuration)
- {
- if (!visited.Add(item))
+
+ /// <summary>
+ /// Executes this solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='context'>
+ /// An execution context
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to execute the item
+ /// </param>
+ public async Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null) {
+ ExecutionContext localContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, context.ConsoleFactory, context.ExecutionTarget);
+
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.BeforeExecute, localContext, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.BeforeExecute, localContext, configuration))
+ return;
+ }
+ }
+
+ if (monitor.CancellationToken.IsCancellationRequested)
return;
-
- referenced.Add (item);
- foreach (SolutionItem ritem in item.GetReferencedItems (configuration))
- GetBuildableReferencedItems (visited, referenced, ritem, configuration);
+ await ItemExtension.OnExecute (monitor, context, configuration);
+
+ if (conf != null && !monitor.CancellationToken.IsCancellationRequested) {
+ ExecutionContext localContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, context.ConsoleFactory, context.ExecutionTarget);
+
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.AfterExecute, localContext, configuration))
+ await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.AfterExecute, localContext, configuration);
+ }
}
-
+
+ /// <summary>
+ /// Determines whether this solution item can be executed using the specified context and configuration.
+ /// </summary>
+ /// <returns>
+ /// <c>true</c> if this instance can be executed; otherwise, <c>false</c>.
+ /// </returns>
+ /// <param name='context'>
+ /// An execution context
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to execute the item
+ /// </param>
+ public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return !IsUnsupportedProject && ItemExtension.OnGetCanExecute (context, configuration);
+ }
+
+ async Task DoExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute)) {
+ await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.Execute, context, configuration);
+ return;
+ }
+ await OnExecute (monitor, context, configuration);
+ }
+
/// <summary>
/// Executes this solution item
/// </summary>
@@ -650,11 +864,19 @@ namespace MonoDevelop.Projects
/// <param name='configuration'>
/// Configuration to use to execute the item
/// </param>
- public void Execute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ protected virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
- Services.ProjectService.GetExtensionChain (this).Execute (monitor, this, context, configuration);
+ return Task.FromResult (0);
}
-
+
+ bool DoGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute))
+ return conf.CustomCommands.CanExecute (this, CustomCommandType.Execute, context, configuration);
+ return OnGetCanExecute (context, configuration);
+ }
+
/// <summary>
/// Determines whether this solution item can be executed using the specified context and configuration.
/// </summary>
@@ -667,11 +889,9 @@ namespace MonoDevelop.Projects
/// <param name='configuration'>
/// Configuration to use to execute the item
/// </param>
- public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
{
- if (!SupportsExecute ())
- return false;
- return Services.ProjectService.GetExtensionChain (this).CanExecute (this, context, configuration);
+ return ItemExtension.OnGetCanExecute (context, configuration);
}
/// <summary>
@@ -681,7 +901,12 @@ namespace MonoDevelop.Projects
/// <param name="configuration">The configuration.</param>
public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration)
{
- return Services.ProjectService.GetExtensionChain (this).GetExecutionTargets (this, configuration);
+ return ItemExtension.OnGetExecutionTargets (configuration);
+ }
+
+ protected void NotifyExecutionTargetsChanged ()
+ {
+ ItemExtension.OnExecutionTargetsChanged ();
}
public event EventHandler ExecutionTargetsChanged;
@@ -691,429 +916,480 @@ namespace MonoDevelop.Projects
if (ExecutionTargetsChanged != null)
ExecutionTargetsChanged (this, EventArgs.Empty);
}
-
- /// <summary>
- /// Checks if this solution item has modified files and has to be built
- /// </summary>
- /// <returns>
- /// <c>true</c> if the solution item has to be built
- /// </returns>
- /// <param name='configuration'>
- /// Configuration for which to do the check
- /// </param>
- [Obsolete ("This method will be removed in future releases")]
- public bool NeedsBuilding (ConfigurationSelector configuration)
+
+ protected virtual Task OnLoad (ProgressMonitor monitor)
{
- return true;
+ return Task.FromResult (0);
}
- internal bool InternalCheckNeedsBuild (ConfigurationSelector configuration)
+ protected internal virtual Task OnSave (ProgressMonitor monitor)
{
- using (Counters.NeedsBuildingTimer.BeginTiming ("NeedsBuilding check for " + Name)) {
- return Services.ProjectService.GetExtensionChain (this).GetNeedsBuilding (this, configuration);
- }
+ return Task.FromResult (0);
}
- /// <summary>
- /// States whether this solution item needs to be built or not
- /// </summary>
- /// <param name='value'>
- /// Whether this solution item needs to be built or not
- /// </param>
- /// <param name='configuration'>
- /// Configuration for which to set the flag
- /// </param>
- [Obsolete ("This method will be removed in future releases")]
- public void SetNeedsBuilding (bool value, ConfigurationSelector configuration)
+ public FilePath GetAbsoluteChildPath (FilePath relPath)
{
- // Nothing to be done.
+ return relPath.ToAbsolute (BaseDirectory);
}
-
- /// <summary>
- /// Gets or sets a value indicating whether this <see cref="MonoDevelop.Projects.SolutionItem"/> needs to be reload due to changes in project or solution file
- /// </summary>
- /// <value>
- /// <c>true</c> if needs reload; otherwise, <c>false</c>.
- /// </value>
- public virtual bool NeedsReload {
- get {
- if (ParentSolution != null)
- return ParentSolution.NeedsReload;
- else
- return false;
- }
- set {
- }
+
+ public FilePath GetRelativeChildPath (FilePath absPath)
+ {
+ return absPath.ToRelative (BaseDirectory);
}
-
- /// <summary>
- /// Registers an internal child item.
- /// </summary>
- /// <param name='item'>
- /// An item
- /// </param>
- /// <remarks>
- /// Some kind of projects may be composed of several child projects.
- /// By registering those child projects using this method, the child
- /// projects will be plugged into the parent solution infrastructure
- /// (so for example, the ParentSolution property for those projects
- /// will return the correct value)
- /// </remarks>
- protected void RegisterInternalChild (SolutionItem item)
+
+ public IEnumerable<FilePath> GetItemFiles (bool includeReferencedFiles)
{
- if (internalChildren == null) {
- internalChildren = new SolutionFolder ();
- internalChildren.ParentFolder = parentFolder;
- }
- internalChildren.Items.Add (item);
+ return ItemExtension.OnGetItemFiles (includeReferencedFiles);
}
-
- /// <summary>
- /// Unregisters an internal child item.
- /// </summary>
- /// <param name='item'>
- /// The item
- /// </param>
- protected void UnregisterInternalChild (SolutionItem item)
+
+ protected virtual IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
{
- if (internalChildren != null)
- internalChildren.Items.Remove (item);
+ List<FilePath> col = FileFormat.Format.GetItemFiles (this);
+ if (!string.IsNullOrEmpty (FileName) && !col.Contains (FileName))
+ col.Add (FileName);
+ return col;
}
-
- /// <summary>
- /// Gets the string tag model description for this solution item
- /// </summary>
- /// <returns>
- /// The string tag model description
- /// </returns>
- /// <param name='conf'>
- /// Configuration for which to get the string tag model description
- /// </param>
- public virtual StringTagModelDescription GetStringTagModelDescription (ConfigurationSelector conf)
+
+ protected override void OnNameChanged (SolutionItemRenamedEventArgs e)
{
- StringTagModelDescription model = new StringTagModelDescription ();
- model.Add (GetType ());
- model.Add (typeof(Solution));
- return model;
+ Solution solution = this.ParentSolution;
+
+ if (solution != null) {
+ foreach (DotNetProject project in solution.GetAllItems<DotNetProject>()) {
+ if (project == this)
+ continue;
+
+ project.RenameReferences (e.OldName, e.NewName);
+ }
+ }
+ fileStatusTracker.ResetLoadTimes ();
+ base.OnNameChanged (e);
}
- /// <summary>
- /// Gets the string tag model for this solution item
- /// </summary>
- /// <returns>
- /// The string tag model
- /// </returns>
- /// <param name='conf'>
- /// Configuration for which to get the string tag model
- /// </param>
- public virtual StringTagModel GetStringTagModel (ConfigurationSelector conf)
+ protected virtual void OnSaved (SolutionItemEventArgs args)
{
- StringTagModel source = new StringTagModel ();
- source.Add (this);
- if (ParentSolution != null)
- source.Add (ParentSolution.GetStringTagModel ());
- return source;
+ if (Saved != null)
+ Saved (this, args);
}
- /// <summary>
- /// Sorts a collection of solution items, taking into account the dependencies between them
- /// </summary>
- /// <returns>
- /// The sorted collection of items
- /// </returns>
- /// <param name='items'>
- /// Items to sort
- /// </param>
- /// <param name='configuration'>
- /// A configuration
- /// </param>
- /// <remarks>
- /// This methods sorts a collection of items, ensuring that every item is placed after all the items
- /// on which it depends.
- /// </remarks>
- public static ReadOnlyCollection<T> TopologicalSort<T> (IEnumerable<T> items, ConfigurationSelector configuration) where T: SolutionItem
- {
- IList<T> allItems;
- allItems = items as IList<T>;
- if (allItems == null)
- allItems = new List<T> (items);
-
- List<T> sortedEntries = new List<T> ();
- bool[] inserted = new bool[allItems.Count];
- bool[] triedToInsert = new bool[allItems.Count];
- for (int i = 0; i < allItems.Count; ++i) {
- if (!inserted[i])
- Insert<T> (i, allItems, sortedEntries, inserted, triedToInsert, configuration);
+ public virtual string[] SupportedPlatforms {
+ get {
+ return new string [0];
}
- return sortedEntries.AsReadOnly ();
}
- static void Insert<T> (int index, IList<T> allItems, List<T> sortedItems, bool[] inserted, bool[] triedToInsert, ConfigurationSelector solutionConfiguration) where T: SolutionItem
+ public virtual SolutionItemConfiguration GetConfiguration (ConfigurationSelector configuration)
{
- if (triedToInsert[index]) {
- throw new CyclicDependencyException ();
+ return (SolutionItemConfiguration) configuration.GetConfiguration (this) ?? DefaultConfiguration;
+ }
+
+ ItemConfiguration IConfigurationTarget.DefaultConfiguration {
+ get { return DefaultConfiguration; }
+ set { DefaultConfiguration = (SolutionItemConfiguration) value; }
+ }
+
+ public SolutionItemConfiguration DefaultConfiguration {
+ get {
+ if (activeConfiguration == null && configurations.Count > 0) {
+ return configurations[0];
+ }
+ return activeConfiguration;
}
- triedToInsert[index] = true;
- SolutionItem insertItem = allItems[index];
-
- foreach (SolutionItem reference in insertItem.GetReferencedItems (solutionConfiguration)) {
- for (int j=0; j < allItems.Count; ++j) {
- SolutionItem checkItem = allItems[j];
- if (reference == checkItem) {
- if (!inserted[j])
- Insert (j, allItems, sortedItems, inserted, triedToInsert, solutionConfiguration);
- break;
- }
+ set {
+ if (activeConfiguration != value) {
+ activeConfiguration = value;
+ NotifyModified ("DefaultConfiguration");
+ OnDefaultConfigurationChanged (new ConfigurationEventArgs (this, value));
}
}
- sortedItems.Add ((T)insertItem);
- inserted[index] = true;
}
- internal virtual IDictionary InternalGetExtendedProperties {
+ public string DefaultConfigurationId {
get {
- if (extendedProperties == null)
- extendedProperties = new Hashtable ();
- return extendedProperties;
+ if (DefaultConfiguration != null)
+ return DefaultConfiguration.Id;
+ else
+ return null;
+ }
+ set {
+ DefaultConfiguration = GetConfiguration (new ItemConfigurationSelector (value));
}
}
- void ILoadController.BeginLoad ()
+ public virtual ReadOnlyCollection<string> GetConfigurations ()
{
- loading++;
- OnBeginLoad ();
+ List<string> configs = new List<string> ();
+ foreach (SolutionItemConfiguration conf in Configurations)
+ configs.Add (conf.Id);
+ return configs.AsReadOnly ();
}
- void ILoadController.EndLoad ()
- {
- loading--;
- OnEndLoad ();
+ [ItemProperty ("Configurations")]
+ [ItemProperty ("Configuration", ValueType=typeof(SolutionItemConfiguration), Scope="*")]
+ public SolutionItemConfigurationCollection Configurations {
+ get {
+ return configurations;
+ }
}
- /// <summary>
- /// Called when a load operation for this solution item has started
- /// </summary>
- protected virtual void OnBeginLoad ()
- {
+ IItemConfigurationCollection IConfigurationTarget.Configurations {
+ get {
+ return Configurations;
+ }
}
- /// <summary>
- /// Called when a load operation for this solution item has finished
- /// </summary>
- protected virtual void OnEndLoad ()
+ public SolutionItemConfiguration AddNewConfiguration (string name)
{
+ SolutionItemConfiguration config = CreateConfiguration (name);
+ Configurations.Add (config);
+ return config;
}
- /// <summary>
- /// Notifies that this solution item has been modified
- /// </summary>
- /// <param name='hint'>
- /// Hint about which part of the solution item has been modified. This will typically be the property name.
- /// </param>
- internal protected void NotifyModified (string hint)
+ ItemConfiguration IConfigurationTarget.CreateConfiguration (string name)
{
- if (!Loading)
- ItemHandler.OnModified (hint);
- OnModified (new SolutionItemModifiedEventArgs (this, hint));
+ return CreateConfiguration (name);
}
-
- /// <summary>
- /// Raises the modified event.
- /// </summary>
- /// <param name='args'>
- /// Arguments.
- /// </param>
- protected virtual void OnModified (SolutionItemModifiedEventArgs args)
+
+ public virtual SolutionItemConfiguration CreateConfiguration (string name)
{
- if (Modified != null && !Disposed)
- Modified (this, args);
+ return ItemExtension.OnCreateConfiguration (name);
}
- /// <summary>
- /// Raises the name changed event.
- /// </summary>
- /// <param name='e'>
- /// Arguments.
- /// </param>
- protected virtual void OnNameChanged (SolutionItemRenamedEventArgs e)
+ void OnConfigurationAddedToCollection (object ob, ConfigurationEventArgs args)
{
- NotifyModified ("Name");
- if (NameChanged != null && !Disposed)
- NameChanged (this, e);
+ NotifyModified ("Configurations");
+ OnConfigurationAdded (new ConfigurationEventArgs (this, args.Configuration));
+ if (ConfigurationsChanged != null)
+ ConfigurationsChanged (this, EventArgs.Empty);
+ if (activeConfiguration == null)
+ DefaultConfigurationId = args.Configuration.Id;
}
- /// <summary>
- /// Initializes the item handler.
- /// </summary>
- /// <remarks>
- /// This method is called the first time an item handler is requested.
- /// Subclasses should override this method use SetItemHandler to
- /// assign a handler to this item.
- /// </remarks>
- protected virtual void InitializeItemHandler ()
+ void OnConfigurationRemovedFromCollection (object ob, ConfigurationEventArgs args)
{
+ if (activeConfiguration == args.Configuration) {
+ if (Configurations.Count > 0)
+ DefaultConfiguration = Configurations [0];
+ else
+ DefaultConfiguration = null;
+ }
+ NotifyModified ("Configurations");
+ OnConfigurationRemoved (new ConfigurationEventArgs (this, args.Configuration));
+ if (ConfigurationsChanged != null)
+ ConfigurationsChanged (this, EventArgs.Empty);
}
- /// <summary>
- /// Runs a build or execution target.
- /// </summary>
- /// <returns>
- /// The result of the operation
- /// </returns>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='target'>
- /// Name of the target
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to run the target
- /// </param>
- /// <remarks>
- /// Subclasses can override this method to provide a custom implementation of project operations such as
- /// build or clean. The default implementation delegates the execution to the more specific OnBuild
- /// and OnClean methods, or to the item handler for other targets.
- /// </remarks>
- internal protected virtual BuildResult OnRunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ public override StringTagModelDescription GetStringTagModelDescription (ConfigurationSelector conf)
{
- if (target == ProjectService.BuildTarget)
- return OnBuild (monitor, configuration);
- else if (target == ProjectService.CleanTarget) {
- OnClean (monitor, configuration);
- return new BuildResult ();
- }
- return ItemHandler.RunTarget (monitor, target, configuration) ?? new BuildResult ();
+ return ItemExtension.OnGetStringTagModelDescription (conf);
}
- /// <summary>
- /// Cleans the files produced by this solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to clean the project
- /// </param>
- protected abstract void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration);
+ StringTagModelDescription DoGetStringTagModelDescription (ConfigurationSelector conf)
+ {
+ StringTagModelDescription model = base.GetStringTagModelDescription (conf);
+ SolutionItemConfiguration config = GetConfiguration (conf);
+ if (config != null)
+ model.Add (config.GetType ());
+ else
+ model.Add (typeof(SolutionItemConfiguration));
+ return model;
+ }
+
+ public override StringTagModel GetStringTagModel (ConfigurationSelector conf)
+ {
+ return ItemExtension.OnGetStringTagModel (conf);
+ }
- /// <summary>
- /// Builds the solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to build the project
- /// </param>
- protected abstract BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration);
+ StringTagModel DoGetStringTagModel (ConfigurationSelector conf)
+ {
+ StringTagModel source = base.GetStringTagModel (conf);
+ SolutionItemConfiguration config = GetConfiguration (conf);
+ if (config != null)
+ source.Add (config);
+ return source;
+ }
+
+ internal protected override DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return ItemExtension.OnGetLastBuildTime (configuration);
+ }
+
+ DateTime DoGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return base.OnGetLastBuildTime (configuration);
+ }
+
+ internal protected virtual void OnItemsAdded (IEnumerable<ProjectItem> objs)
+ {
+ ItemExtension.OnItemsAdded (objs);
+ }
- /// <summary>
- /// Executes this solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='context'>
- /// An execution context
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to execute the item
- /// </param>
- internal protected abstract void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration);
+ void DoOnItemsAdded (IEnumerable<ProjectItem> objs)
+ {
+ NotifyModified ("Items");
+ var args = new ProjectItemEventArgs ();
+ args.AddRange (objs.Select (pi => new ProjectItemEventInfo (this, pi)));
+ if (ProjectItemAdded != null)
+ ProjectItemAdded (this, args);
+ }
+
+ internal protected virtual void OnItemsRemoved (IEnumerable<ProjectItem> objs)
+ {
+ ItemExtension.OnItemsRemoved (objs);
+ }
- /// <summary>
- /// Checks if this solution item has modified files and has to be built
- /// </summary>
- /// <returns>
- /// <c>true</c> if the solution item has to be built
- /// </returns>
- /// <param name='configuration'>
- /// Configuration for which to do the check
- /// </param>
- internal protected virtual bool OnGetNeedsBuilding (ConfigurationSelector configuration)
+ void DoOnItemsRemoved (IEnumerable<ProjectItem> objs)
{
- return true;
+ NotifyModified ("Items");
+ var args = new ProjectItemEventArgs ();
+ args.AddRange (objs.Select (pi => new ProjectItemEventInfo (this, pi)));
+ if (ProjectItemRemoved != null)
+ ProjectItemRemoved (this, args);
+ }
+
+ protected virtual void OnDefaultConfigurationChanged (ConfigurationEventArgs args)
+ {
+ ItemExtension.OnDefaultConfigurationChanged (args);
}
- /// <summary>
- /// States whether this solution item needs to be built or not
- /// </summary>
- /// <param name='val'>
- /// Whether this solution item needs to be built or not
- /// </param>
- /// <param name='configuration'>
- /// Configuration for which to set the flag
- /// </param>
- internal protected virtual void OnSetNeedsBuilding (bool val, ConfigurationSelector configuration)
+ void DoOnDefaultConfigurationChanged (ConfigurationEventArgs args)
+ {
+ if (DefaultConfigurationChanged != null)
+ DefaultConfigurationChanged (this, args);
+ }
+
+ protected virtual void OnConfigurationAdded (ConfigurationEventArgs args)
{
+ ItemExtension.OnConfigurationAdded (args);
}
- /// <summary>
- /// Gets the time of the last build
- /// </summary>
- /// <returns>
- /// The last build time.
- /// </returns>
- /// <param name='configuration'>
- /// Configuration for which to get the last build time.
- /// </param>
- internal protected virtual DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ void DoOnConfigurationAdded (ConfigurationEventArgs args)
{
- return DateTime.MinValue;
+ if (ConfigurationAdded != null)
+ ConfigurationAdded (this, args);
+ }
+
+ protected virtual void OnConfigurationRemoved (ConfigurationEventArgs args)
+ {
+ ItemExtension.OnConfigurationRemoved (args);
}
- internal protected virtual bool OnGetSupportsTarget (string target)
+ void DoOnConfigurationRemoved (ConfigurationEventArgs args)
{
- return true;
+ if (ConfigurationRemoved != null)
+ ConfigurationRemoved (this, args);
}
- internal protected virtual bool OnGetSupportsExecute ()
+ protected virtual void OnReloadRequired (SolutionItemEventArgs args)
{
- return true;
+ ItemExtension.OnReloadRequired (args);
+ }
+
+ void DoOnReloadRequired (SolutionItemEventArgs args)
+ {
+ fileStatusTracker.FireReloadRequired (args);
}
- /// <summary>
- /// Determines whether this solution item can be executed using the specified context and configuration.
- /// </summary>
- /// <returns>
- /// <c>true</c> if this instance can be executed; otherwise, <c>false</c>.
- /// </returns>
- /// <param name='context'>
- /// An execution context
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to execute the item
- /// </param>
- internal protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ protected override void OnBoundToSolution ()
{
- return false;
+ ParentSolution.SolutionItemRemoved += HandleSolutionItemRemoved;
+ ParentSolution.SolutionItemAdded += HandleSolutionItemAdded;
+ ItemExtension.OnBoundToSolution ();
}
- internal protected virtual IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration)
+ void DoOnBoundToSolution ()
{
- yield break;
+ base.OnBoundToSolution ();
}
- protected virtual void OnBoundToSolution ()
+ protected override void OnUnboundFromSolution ()
{
+ ParentSolution.SolutionItemAdded -= HandleSolutionItemAdded;
+ ParentSolution.SolutionItemRemoved -= HandleSolutionItemRemoved;
+ ItemExtension.OnUnboundFromSolution ();
}
- internal protected virtual object OnGetService (Type t)
+ void DoOnUnboundFromSolution ()
{
- return ItemHandler.GetService (t);
+ base.OnUnboundFromSolution ();
}
- /// <summary>
- /// Occurs when the name of the item changes
- /// </summary>
- public event SolutionItemRenamedEventHandler NameChanged;
+
+ public event SolutionItemEventHandler Saved;
- /// <summary>
- /// Occurs when the item is modified.
- /// </summary>
- public event SolutionItemModifiedEventHandler Modified;
- }
+ class DefaultMSBuildItemExtension: SolutionItemExtension
+ {
+ internal protected override void OnInitializeFromTemplate (XmlElement template)
+ {
+ Item.OnInitializeFromTemplate (template);
+ }
+
+ internal protected override FilePath OnGetDefaultBaseDirectory ()
+ {
+ return Item.FileName.IsNullOrEmpty ? FilePath.Empty : Item.FileName.ParentDirectory;
+ }
+
+ internal protected override IEnumerable<SolutionItem> OnGetReferencedItems (ConfigurationSelector configuration)
+ {
+ return Item.OnGetReferencedItems (configuration);
+ }
+
+ internal protected override StringTagModelDescription OnGetStringTagModelDescription (ConfigurationSelector conf)
+ {
+ return Item.DoGetStringTagModelDescription (conf);
+ }
+
+ internal protected override StringTagModel OnGetStringTagModel (ConfigurationSelector conf)
+ {
+ return Item.DoGetStringTagModel (conf);
+ }
+
+ internal protected override bool OnGetSupportsFormat (FileFormat format)
+ {
+ return Item.OnGetSupportsFormat (format);
+ }
+
+ internal protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
+ {
+ return Item.OnGetItemFiles (includeReferencedFiles);
+ }
+
+ internal protected override SolutionItemConfiguration OnCreateConfiguration (string name)
+ {
+ return new SolutionItemConfiguration (name);
+ }
+
+ internal protected override string[] SupportedPlatforms {
+ get {
+ return new string [0];
+ }
+ }
+
+ internal protected override DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return Item.DoGetLastBuildTime (configuration);
+ }
+
+ internal protected override Task OnLoad (ProgressMonitor monitor)
+ {
+ return Item.OnLoad (monitor);
+ }
+
+ internal protected override Task OnSave (ProgressMonitor monitor)
+ {
+ return Item.DoSave (monitor);
+ }
+
+ internal protected override bool OnSupportsBuild ()
+ {
+ return Item.OnGetSupportsBuild ();
+ }
+
+ internal protected override bool OnSupportsExecute ()
+ {
+ return Item.OnGetSupportsExecute ();
+ }
+
+ internal protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return Item.DoExecute (monitor, context, configuration);
+ }
+
+ internal protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return Item.DoGetCanExecute (context, configuration);
+ }
+
+ internal protected override IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration)
+ {
+ yield break;
+ }
+
+ internal protected override void OnExecutionTargetsChanged ()
+ {
+ Item.OnExecutionTargetsChanged ();
+ }
+
+ internal protected override void OnReloadRequired (SolutionItemEventArgs args)
+ {
+ Item.DoOnReloadRequired (args);
+ }
+
+ internal protected override void OnItemsAdded (IEnumerable<ProjectItem> objs)
+ {
+ Item.DoOnItemsAdded (objs);
+ }
+
+ internal protected override void OnItemsRemoved (IEnumerable<ProjectItem> objs)
+ {
+ Item.DoOnItemsRemoved (objs);
+ }
+
+ internal protected override void OnDefaultConfigurationChanged (ConfigurationEventArgs args)
+ {
+ Item.DoOnDefaultConfigurationChanged (args);
+ }
+
+ internal protected override void OnBoundToSolution ()
+ {
+ Item.DoOnBoundToSolution ();
+ }
+
+ internal protected override void OnUnboundFromSolution ()
+ {
+ Item.DoOnUnboundFromSolution ();
+ }
+
+ internal protected override void OnConfigurationAdded (ConfigurationEventArgs args)
+ {
+ Item.DoOnConfigurationAdded (args);
+ }
+
+ internal protected override void OnConfigurationRemoved (ConfigurationEventArgs args)
+ {
+ Item.DoOnConfigurationRemoved (args);
+ }
+
+ internal protected override void OnModified (SolutionItemModifiedEventArgs args)
+ {
+ Item.OnModified (args);
+ }
+
+ internal protected override void OnNameChanged (SolutionItemRenamedEventArgs e)
+ {
+ Item.OnNameChanged (e);
+ }
+
+ internal protected override IconId StockIcon {
+ get {
+ return "md-project";
+ }
+ }
+
+ internal protected override bool ItemFilesChanged {
+ get {
+ return Item.BaseItemFilesChanged;
+ }
+ }
+
+ internal protected override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Item.OnBuild (monitor, configuration);
+ }
+
+ internal protected override Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Item.OnClean (monitor, configuration);
+ }
+
+ internal protected override bool OnNeedsBuilding (ConfigurationSelector configuration)
+ {
+ return Item.OnGetNeedsBuilding (configuration);
+ }
+ }
+ }
+
[Mono.Addins.Extension]
class SolutionItemTagProvider: StringTagProvider<SolutionItem>, IStringTagProvider
{
@@ -1126,32 +1402,37 @@ namespace MonoDevelop.Projects
yield return new StringTagDescription ("AuthorCopyright", "Project Author Copyright");
yield return new StringTagDescription ("AuthorCompany", "Project Author Company");
yield return new StringTagDescription ("AuthorTrademark", "Project Trademark");
+ yield return new StringTagDescription ("ProjectFile", "Project File");
}
-
+
public override object GetTagValue (SolutionItem item, string tag)
{
switch (tag) {
- case "ITEMNAME":
- case "PROJECTNAME":
- return item.Name;
- case "AUTHORCOPYRIGHT":
- AuthorInformation authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Copyright;
- case "AUTHORCOMPANY":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Company;
- case "AUTHORTRADEMARK":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Trademark;
- case "AUTHOREMAIL":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Email;
- case "AUTHORNAME":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Name;
- case "ITEMDIR":
- case "PROJECTDIR":
- return item.BaseDirectory;
+ case "ITEMNAME":
+ case "PROJECTNAME":
+ return item.Name;
+ case "AUTHORCOPYRIGHT":
+ AuthorInformation authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Copyright;
+ case "AUTHORCOMPANY":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Company;
+ case "AUTHORTRADEMARK":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Trademark;
+ case "AUTHOREMAIL":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Email;
+ case "AUTHORNAME":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Name;
+ case "ITEMDIR":
+ case "PROJECTDIR":
+ return item.BaseDirectory;
+ case "ITEMFILE":
+ case "PROJECTFILE":
+ case "PROJECTFILENAME":
+ return item.FileName;
}
throw new NotSupportedException ();
}