4
// Lluis Sanchez Gual <lluis@novell.com>
6
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
8
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
// of this software and associated documentation files (the "Software"), to deal
10
// in the Software without restriction, including without limitation the rights
11
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
// copies of the Software, and to permit persons to whom the Software is
13
// furnished to do so, subject to the following conditions:
15
// The above copyright notice and this permission notice shall be included in
16
// all copies or substantial portions of the Software.
18
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using System.Collections;
30
using System.Collections.Generic;
31
using System.Collections.ObjectModel;
33
using System.CodeDom.Compiler;
34
using MonoDevelop.Core;
35
using MonoDevelop.Core.Serialization;
36
using MonoDevelop.Projects.Extensions;
37
using MonoDevelop.Core.Collections;
38
using MonoDevelop.Core.StringParsing;
39
using MonoDevelop.Core.Instrumentation;
41
namespace MonoDevelop.Projects
43
public abstract class SolutionItem: IExtendedDataItem, IBuildTarget, ILoadController
45
SolutionFolder parentFolder;
46
Solution parentSolution;
47
ISolutionItemHandler handler;
49
SolutionFolder internalChildren;
51
[ProjectPathItemProperty ("BaseDirectory", DefaultValue=null)]
54
Hashtable extendedProperties;
56
[ItemProperty ("Policies", IsExternal = true, SkipEmpty = true)]
57
MonoDevelop.Projects.Policies.PolicyBag policies;
59
PropertyBag userProperties;
63
ProjectExtensionUtil.LoadControl (this);
66
public virtual void InitializeFromTemplate (XmlElement template)
70
protected internal ISolutionItemHandler ItemHandler {
72
if (handler == null) {
73
InitializeItemHandler ();
75
throw new InvalidOperationException ("No handler found for solution item of type: " + GetType ());
81
internal virtual void SetItemHandler (ISolutionItemHandler handler)
83
if (this.handler != null)
84
this.handler.Dispose ();
85
this.handler = handler;
88
internal ISolutionItemHandler GetItemHandler ()
90
// Used to get the handler without lazy loading it
94
public T GetService<T> () where T: class
96
return (T) GetService (typeof(T));
99
public virtual object GetService (Type t)
101
if (t.IsInstanceOfType (this))
103
return Services.ProjectService.GetExtensionChain (this).GetService (this, t);
106
public Solution ParentSolution {
108
if (parentFolder != null)
109
return parentFolder.ParentSolution;
110
return parentSolution;
113
parentSolution = value;
117
public bool Loading {
118
get { return loading > 0; }
121
public abstract void Save (IProgressMonitor monitor);
123
public abstract string Name { get; set; }
125
public FilePath BaseDirectory {
127
if (baseDirectory == null) {
128
FilePath dir = GetDefaultBaseDirectory ();
129
if (dir.IsNullOrEmpty)
134
return baseDirectory;
137
FilePath def = GetDefaultBaseDirectory ();
138
if (value != FilePath.Null && def != FilePath.Null && value.FullPath == def.FullPath)
139
baseDirectory = null;
140
else if (string.IsNullOrEmpty (value))
141
baseDirectory = null;
143
baseDirectory = value.FullPath;
144
NotifyModified ("BaseDirectory");
148
public FilePath ItemDirectory {
150
FilePath dir = GetDefaultBaseDirectory ();
151
if (string.IsNullOrEmpty (dir))
157
internal bool HasCustomBaseDirectory {
158
get { return baseDirectory != null; }
161
protected virtual FilePath GetDefaultBaseDirectory ( )
163
return ParentSolution.BaseDirectory;
166
public string ItemId {
167
get { return ItemHandler.ItemId; }
170
public IDictionary ExtendedProperties {
171
get { return InternalGetExtendedProperties; }
174
public MonoDevelop.Projects.Policies.PolicyBag Policies {
176
//newly created (i.e. not deserialised) SolutionItems may have a null PolicyBag
177
if (policies == null)
178
policies = new MonoDevelop.Projects.Policies.PolicyBag ();
179
//this is the easiest reliable place to associate a deserialised Policybag with its owner
180
policies.Owner = this;
183
//setter so that a solution can deserialise the PropertyBag on its RootFolder
189
// User properties are only loaded when the project is loaded in the IDE.
190
public PropertyBag UserProperties {
192
if (userProperties == null)
193
userProperties = new PropertyBag ();
194
return userProperties;
198
// Initializes the user properties of the item
199
public void LoadUserProperties (PropertyBag properties)
201
if (userProperties != null)
202
throw new InvalidOperationException ("User properties already loaded.");
203
userProperties = properties;
206
public SolutionFolder ParentFolder {
211
parentFolder = value;
212
if (internalChildren != null)
213
internalChildren.ParentFolder = value;
217
public virtual void Dispose ()
219
if (extendedProperties != null) {
220
foreach (object ob in extendedProperties.Values) {
221
IDisposable disp = ob as IDisposable;
228
if (userProperties != null)
229
((IDisposable)userProperties).Dispose ();
232
public virtual IEnumerable<SolutionItem> GetReferencedItems (ConfigurationSelector configuration)
234
return new SolutionItem [0];
237
public virtual BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
239
return Services.ProjectService.GetExtensionChain (this).RunTarget (monitor, this, target, configuration);
242
public void Clean (IProgressMonitor monitor, ConfigurationSelector configuration)
244
RunTarget (monitor, ProjectService.CleanTarget, configuration);
247
public BuildResult Build (IProgressMonitor monitor, ConfigurationSelector configuration)
249
return Build (monitor, configuration, false);
252
public BuildResult Build (IProgressMonitor monitor, ConfigurationSelector solutionConfiguration, bool buildReferences)
254
ITimeTracker tt = Counters.BuildProjectTimer.BeginTiming ("Building " + Name);
256
if (!buildReferences) {
257
if (!NeedsBuilding (solutionConfiguration))
258
return new BuildResult (new CompilerResults (null), "");
261
SolutionEntityItem it = this as SolutionEntityItem;
262
SolutionItemConfiguration iconf = it != null ? it.GetConfiguration (solutionConfiguration) : null;
263
string confName = iconf != null ? iconf.Id : solutionConfiguration.ToString ();
264
monitor.BeginTask (GettextCatalog.GetString ("Building: {0} ({1})", Name, confName), 1);
266
// This will end calling OnBuild ()
267
return RunTarget (monitor, ProjectService.BuildTarget, solutionConfiguration);
274
// Get a list of all items that need to be built (including this),
275
// and build them in the correct order
277
List<SolutionItem> referenced = new List<SolutionItem> ();
278
Set<SolutionItem> visited = new Set<SolutionItem> ();
279
GetBuildableReferencedItems (visited, referenced, this, solutionConfiguration);
281
ReadOnlyCollection<SolutionItem> sortedReferenced = SolutionFolder.TopologicalSort (referenced, solutionConfiguration);
283
BuildResult cres = new BuildResult ();
285
HashSet<SolutionItem> failedItems = new HashSet<SolutionItem> ();
287
monitor.BeginTask (null, sortedReferenced.Count);
288
foreach (SolutionItem p in sortedReferenced) {
289
if (p.NeedsBuilding (solutionConfiguration) && !p.ContainsReferences (failedItems, solutionConfiguration)) {
290
BuildResult res = p.Build (monitor, solutionConfiguration, false);
292
if (res.ErrorCount > 0)
297
if (monitor.IsCancelRequested)
307
internal bool ContainsReferences (HashSet<SolutionItem> items, ConfigurationSelector conf)
309
foreach (SolutionItem it in GetReferencedItems (conf))
310
if (items.Contains (it))
315
public DateTime GetLastBuildTime (ConfigurationSelector configuration)
317
return OnGetLastBuildTime (configuration);
320
void GetBuildableReferencedItems (Set<SolutionItem> visited, List<SolutionItem> referenced, SolutionItem item, ConfigurationSelector configuration)
322
if (!visited.Add(item))
325
if (item.NeedsBuilding (configuration))
326
referenced.Add (item);
328
foreach (SolutionItem ritem in item.GetReferencedItems (configuration))
329
GetBuildableReferencedItems (visited, referenced, ritem, configuration);
332
public void Execute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
334
Services.ProjectService.GetExtensionChain (this).Execute (monitor, this, context, configuration);
337
public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
339
return Services.ProjectService.GetExtensionChain (this).CanExecute (this, context, configuration);
342
public bool NeedsBuilding (ConfigurationSelector configuration)
344
using (Counters.NeedsBuildingTimer.BeginTiming ("NeedsBuilding check for " + Name)) {
345
if (ParentSolution != null && this is SolutionEntityItem) {
346
SolutionConfiguration sconf = ParentSolution.GetConfiguration (configuration);
347
if (sconf != null && !sconf.BuildEnabledForItem ((SolutionEntityItem) this))
350
return Services.ProjectService.GetExtensionChain (this).GetNeedsBuilding (this, configuration);
354
public void SetNeedsBuilding (bool value, ConfigurationSelector configuration)
356
Services.ProjectService.GetExtensionChain (this).SetNeedsBuilding (this, value, configuration);
359
public virtual bool NeedsReload {
361
if (ParentSolution != null)
362
return ParentSolution.NeedsReload;
370
protected void RegisterInternalChild (SolutionItem item)
372
if (internalChildren == null) {
373
internalChildren = new SolutionFolder ();
374
internalChildren.ParentFolder = parentFolder;
376
internalChildren.Items.Add (item);
379
protected void UnregisterInternalChild (SolutionItem item)
381
if (internalChildren != null)
382
internalChildren.Items.Remove (item);
385
public virtual StringTagModelDescription GetStringTagModelDescription (ConfigurationSelector conf)
387
StringTagModelDescription model = new StringTagModelDescription ();
388
model.Add (GetType ());
389
model.Add (typeof(Solution));
393
public virtual StringTagModel GetStringTagModel (ConfigurationSelector conf)
395
StringTagModel source = new StringTagModel ();
397
if (ParentSolution != null)
398
source.Add (ParentSolution.GetStringTagModel ());
402
public static ReadOnlyCollection<T> TopologicalSort<T> (IEnumerable<T> items, ConfigurationSelector configuration) where T: SolutionItem
405
allItems = items as IList<T>;
406
if (allItems == null)
407
allItems = new List<T> (items);
409
List<T> sortedEntries = new List<T> ();
410
bool[] inserted = new bool[allItems.Count];
411
bool[] triedToInsert = new bool[allItems.Count];
412
for (int i = 0; i < allItems.Count; ++i) {
414
Insert<T> (i, allItems, sortedEntries, inserted, triedToInsert, configuration);
416
return sortedEntries.AsReadOnly ();
419
static void Insert<T> (int index, IList<T> allItems, List<T> sortedItems, bool[] inserted, bool[] triedToInsert, ConfigurationSelector solutionConfiguration) where T: SolutionItem
421
if (triedToInsert[index]) {
422
throw new CyclicDependencyException ();
424
triedToInsert[index] = true;
425
SolutionItem insertItem = allItems[index];
427
foreach (SolutionItem reference in insertItem.GetReferencedItems (solutionConfiguration)) {
428
for (int j=0; j < allItems.Count; ++j) {
429
SolutionItem checkItem = allItems[j];
430
if (reference == checkItem) {
432
Insert (j, allItems, sortedItems, inserted, triedToInsert, solutionConfiguration);
437
sortedItems.Add ((T)insertItem);
438
inserted[index] = true;
441
internal virtual IDictionary InternalGetExtendedProperties {
443
if (extendedProperties == null)
444
extendedProperties = new Hashtable ();
445
return extendedProperties;
449
void ILoadController.BeginLoad ()
455
void ILoadController.EndLoad ()
461
protected virtual void OnBeginLoad ()
465
protected virtual void OnEndLoad ()
469
protected void NotifyModified (string hint)
471
OnModified (new SolutionItemModifiedEventArgs (this, hint));
474
protected virtual void OnModified (SolutionItemModifiedEventArgs args)
476
if (Modified != null)
477
Modified (this, args);
480
protected virtual void OnNameChanged (SolutionItemRenamedEventArgs e)
482
NotifyModified ("Name");
483
if (NameChanged != null)
484
NameChanged (this, e);
487
protected virtual void InitializeItemHandler ()
492
internal protected abstract void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration);
493
internal protected abstract BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration);
494
internal protected abstract void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration);
495
internal protected abstract bool OnGetNeedsBuilding (ConfigurationSelector configuration);
496
internal protected abstract void OnSetNeedsBuilding (bool val, ConfigurationSelector configuration);
498
internal protected virtual DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
500
return DateTime.MinValue;
503
internal protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
508
public event SolutionItemRenamedEventHandler NameChanged;
509
public event SolutionItemModifiedEventHandler Modified;
512
[Mono.Addins.Extension]
513
class SolutionItemTagProvider: StringTagProvider<SolutionItem>, IStringTagProvider
515
public override IEnumerable<StringTagDescription> GetTags ()
517
yield return new StringTagDescription ("ProjectName", "Project Name");
518
yield return new StringTagDescription ("ProjectDir", "Project Directory");
521
public override object GetTagValue (SolutionItem item, string tag)
529
return item.BaseDirectory;
531
throw new NotSupportedException ();