PageRenderTime 65ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs

https://github.com/directhex/monodevelop
C# | 1628 lines | 1227 code | 228 blank | 173 comment | 253 complexity | 81a456b8583653742f1ebb072a54e710 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause, LGPL-2.0, GPL-2.0, CC-BY-SA-3.0, MIT
  1. // RootWorkspace.cs
  2. //
  3. // Author:
  4. // Lluis Sanchez Gual <lluis@novell.com>
  5. //
  6. // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
  7. //
  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:
  14. //
  15. // The above copyright notice and this permission notice shall be included in
  16. // all copies or substantial portions of the Software.
  17. //
  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
  24. // THE SOFTWARE.
  25. //
  26. //
  27. using System;
  28. using System.IO;
  29. using System.Linq;
  30. using System.Collections;
  31. using System.Collections.Generic;
  32. using System.Collections.ObjectModel;
  33. using System.Xml;
  34. using MonoDevelop.Projects;
  35. using MonoDevelop.Core;
  36. using MonoDevelop.Core.Assemblies;
  37. using MonoDevelop.Core.Serialization;
  38. using MonoDevelop.Ide.Gui.Dialogs;
  39. using MonoDevelop.Ide.Gui.Content;
  40. using System.Runtime.CompilerServices;
  41. using MonoDevelop.Core.Instrumentation;
  42. using MonoDevelop.Ide.Gui;
  43. using MonoDevelop.Ide.Projects;
  44. using MonoDevelop.Core.Execution;
  45. namespace MonoDevelop.Ide
  46. {
  47. public class RootWorkspace: IBuildTarget, IWorkspaceObject
  48. {
  49. WorkspaceItemCollection items;
  50. // IParserDatabase parserDatabase;
  51. string activeConfiguration;
  52. bool useDefaultRuntime;
  53. string preferredActiveExecutionTarget;
  54. ProjectFileEventHandler fileAddedToProjectHandler;
  55. ProjectFileEventHandler fileRemovedFromProjectHandler;
  56. ProjectFileRenamedEventHandler fileRenamedInProjectHandler;
  57. ProjectFileEventHandler fileChangedInProjectHandler;
  58. ProjectFileEventHandler filePropertyChangedInProjectHandler;
  59. ProjectReferenceEventHandler referenceAddedToProjectHandler;
  60. ProjectReferenceEventHandler referenceRemovedFromProjectHandler;
  61. SolutionItemChangeEventHandler itemAddedToSolutionHandler;
  62. SolutionItemChangeEventHandler itemRemovedFromSolutionHandler;
  63. EventHandler<WorkspaceItemChangeEventArgs> descendantItemAddedHandler;
  64. EventHandler<WorkspaceItemChangeEventArgs> descendantItemRemovedHandler;
  65. EventHandler configurationsChanged;
  66. internal RootWorkspace ()
  67. {
  68. fileAddedToProjectHandler = (ProjectFileEventHandler) DispatchService.GuiDispatch (new ProjectFileEventHandler (NotifyFileAddedToProject));
  69. fileRemovedFromProjectHandler = (ProjectFileEventHandler) DispatchService.GuiDispatch (new ProjectFileEventHandler (NotifyFileRemovedFromProject));
  70. fileRenamedInProjectHandler = (ProjectFileRenamedEventHandler) DispatchService.GuiDispatch (new ProjectFileRenamedEventHandler (NotifyFileRenamedInProject));
  71. fileChangedInProjectHandler = (ProjectFileEventHandler) DispatchService.GuiDispatch (new ProjectFileEventHandler (NotifyFileChangedInProject));
  72. filePropertyChangedInProjectHandler = (ProjectFileEventHandler) DispatchService.GuiDispatch (new ProjectFileEventHandler (NotifyFilePropertyChangedInProject));
  73. referenceAddedToProjectHandler = (ProjectReferenceEventHandler) DispatchService.GuiDispatch (new ProjectReferenceEventHandler (NotifyReferenceAddedToProject));
  74. referenceRemovedFromProjectHandler = (ProjectReferenceEventHandler) DispatchService.GuiDispatch (new ProjectReferenceEventHandler (NotifyReferenceRemovedFromProject));
  75. itemAddedToSolutionHandler = (SolutionItemChangeEventHandler) DispatchService.GuiDispatch (new SolutionItemChangeEventHandler (NotifyItemAddedToSolution));
  76. itemRemovedFromSolutionHandler = (SolutionItemChangeEventHandler) DispatchService.GuiDispatch (new SolutionItemChangeEventHandler (NotifyItemRemovedFromSolution));
  77. descendantItemAddedHandler = (EventHandler<WorkspaceItemChangeEventArgs>) DispatchService.GuiDispatch (new EventHandler<WorkspaceItemChangeEventArgs> (NotifyDescendantItemAdded));
  78. descendantItemRemovedHandler = (EventHandler<WorkspaceItemChangeEventArgs>) DispatchService.GuiDispatch (new EventHandler<WorkspaceItemChangeEventArgs> (NotifyDescendantItemRemoved));
  79. configurationsChanged = (EventHandler) DispatchService.GuiDispatch (new EventHandler (NotifyConfigurationsChanged));
  80. FileService.FileRenamed += (EventHandler<FileCopyEventArgs>) DispatchService.GuiDispatch (new EventHandler<FileCopyEventArgs> (CheckFileRename));
  81. // Set the initial active runtime
  82. UseDefaultRuntime = true;
  83. IdeApp.Preferences.DefaultTargetRuntimeChanged += delegate {
  84. // If the default runtime changes and current active is default, update it
  85. if (UseDefaultRuntime) {
  86. Runtime.SystemAssemblyService.DefaultRuntime = IdeApp.Preferences.DefaultTargetRuntime;
  87. useDefaultRuntime = true;
  88. }
  89. };
  90. FileService.FileChanged += (EventHandler<FileEventArgs>) DispatchService.GuiDispatch (new EventHandler<FileEventArgs> (CheckWorkspaceItems));;
  91. }
  92. public WorkspaceItemCollection Items {
  93. get {
  94. if (items == null)
  95. items = new RootWorkspaceItemCollection (this);
  96. return items;
  97. }
  98. }
  99. /*
  100. public IParserDatabase ParserDatabase {
  101. get {
  102. if (parserDatabase == null) {
  103. parserDatabase = Services.ParserService.CreateParserDatabase ();
  104. parserDatabase.TrackFileChanges = true;
  105. parserDatabase.ParseProgressMonitorFactory = new ParseProgressMonitorFactory ();
  106. }
  107. return parserDatabase;
  108. }
  109. }*/
  110. public string ActiveConfigurationId {
  111. get {
  112. return activeConfiguration;
  113. }
  114. set {
  115. if (activeConfiguration != value) {
  116. activeConfiguration = value;
  117. OnActiveConfigurationChanged ();
  118. }
  119. }
  120. }
  121. void OnActiveConfigurationChanged ()
  122. {
  123. if (ActiveConfigurationChanged != null)
  124. ActiveConfigurationChanged (this, EventArgs.Empty);
  125. }
  126. public ExecutionTarget ActiveExecutionTarget { get; set; }
  127. internal string PreferredActiveExecutionTarget {
  128. get { return ActiveExecutionTarget != null ? ActiveExecutionTarget.Id : preferredActiveExecutionTarget; }
  129. set { preferredActiveExecutionTarget = value; }
  130. }
  131. public ConfigurationSelector ActiveConfiguration {
  132. get { return new SolutionConfigurationSelector (activeConfiguration); }
  133. }
  134. public TargetRuntime ActiveRuntime {
  135. get {
  136. return Runtime.SystemAssemblyService.DefaultRuntime;
  137. }
  138. set {
  139. useDefaultRuntime = false;
  140. Runtime.SystemAssemblyService.DefaultRuntime = value;
  141. }
  142. }
  143. public bool UseDefaultRuntime {
  144. get { return useDefaultRuntime; }
  145. set {
  146. if (useDefaultRuntime != value) {
  147. useDefaultRuntime = value;
  148. if (value)
  149. Runtime.SystemAssemblyService.DefaultRuntime = IdeApp.Preferences.DefaultTargetRuntime;
  150. }
  151. }
  152. }
  153. public bool IsOpen {
  154. get { return Items.Count > 0; }
  155. }
  156. IDictionary IExtendedDataItem.ExtendedProperties {
  157. get {
  158. throw new NotSupportedException ("Root namespace can't have extended properties.");
  159. }
  160. }
  161. string IWorkspaceObject.Name {
  162. get {
  163. return "MonoDevelop Workspace";
  164. }
  165. set {
  166. throw new NotSupportedException ("Can't change the name of the root workspace.");
  167. }
  168. }
  169. public FilePath BaseDirectory {
  170. get {
  171. return IdeApp.ProjectOperations.ProjectsDefaultPath;
  172. }
  173. }
  174. FilePath IWorkspaceObject.BaseDirectory {
  175. get {
  176. return BaseDirectory;
  177. }
  178. set {
  179. throw new NotSupportedException ();
  180. }
  181. }
  182. FilePath IWorkspaceObject.ItemDirectory {
  183. get {
  184. return BaseDirectory;
  185. }
  186. }
  187. #region Model queries
  188. public SolutionEntityItem FindSolutionItem (string fileName)
  189. {
  190. foreach (WorkspaceItem it in Items) {
  191. SolutionEntityItem si = it.FindSolutionItem (fileName);
  192. if (si != null)
  193. return si;
  194. }
  195. return null;
  196. }
  197. public ReadOnlyCollection<SolutionItem> GetAllSolutionItems ()
  198. {
  199. return GetAllSolutionItems<SolutionItem> ();
  200. }
  201. public virtual ReadOnlyCollection<T> GetAllSolutionItems<T> () where T: SolutionItem
  202. {
  203. List<T> list = new List<T> ();
  204. foreach (WorkspaceItem it in Items) {
  205. list.AddRange (it.GetAllSolutionItems<T> ());
  206. }
  207. return list.AsReadOnly ();
  208. }
  209. public ReadOnlyCollection<Project> GetAllProjects ()
  210. {
  211. return GetAllSolutionItems<Project> ();
  212. }
  213. public ReadOnlyCollection<Solution> GetAllSolutions ()
  214. {
  215. return GetAllItems<Solution> ();
  216. }
  217. public ReadOnlyCollection<T> GetAllItems<T> () where T:WorkspaceItem
  218. {
  219. List<T> list = new List<T> ();
  220. foreach (WorkspaceItem it in Items)
  221. GetAllItems<T> (list, it);
  222. return list.AsReadOnly ();
  223. }
  224. void GetAllItems<T> (List<T> list, WorkspaceItem item) where T: WorkspaceItem
  225. {
  226. if (item is T)
  227. list.Add ((T) item);
  228. if (item is Workspace) {
  229. foreach (WorkspaceItem citem in ((Workspace)item).Items)
  230. GetAllItems<T> (list, citem);
  231. }
  232. }
  233. public Project GetProjectContainingFile (string fileName)
  234. {
  235. foreach (WorkspaceItem it in Items) {
  236. Project p = it.GetProjectContainingFile (fileName);
  237. if (p != null)
  238. return p;
  239. }
  240. return null;
  241. }
  242. #endregion
  243. #region Build and run operations
  244. public void Save ()
  245. {
  246. IProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true);
  247. try {
  248. Save (monitor);
  249. monitor.ReportSuccess (GettextCatalog.GetString ("Workspace saved."));
  250. } catch (Exception ex) {
  251. monitor.ReportError (GettextCatalog.GetString ("Save failed."), ex);
  252. } finally {
  253. monitor.Dispose ();
  254. }
  255. }
  256. public IAsyncOperation Build ()
  257. {
  258. return IdeApp.ProjectOperations.Build (this);
  259. }
  260. public void Clean ()
  261. {
  262. IdeApp.ProjectOperations.Clean (this);
  263. }
  264. public IAsyncOperation Execute ()
  265. {
  266. if (IdeApp.ProjectOperations.CurrentSelectedSolution != null)
  267. return IdeApp.ProjectOperations.Execute (IdeApp.ProjectOperations.CurrentSelectedSolution);
  268. else {
  269. MessageService.ShowError (GettextCatalog.GetString ("No solution has been selected"), GettextCatalog.GetString ("The solution to be executed must be selected in the solution pad."));
  270. return null;
  271. }
  272. }
  273. public bool CanExecute ()
  274. {
  275. if (IdeApp.ProjectOperations.CurrentSelectedSolution != null)
  276. return IdeApp.ProjectOperations.CanExecute (IdeApp.ProjectOperations.CurrentSelectedSolution);
  277. else {
  278. return false;
  279. }
  280. }
  281. bool IBuildTarget.CanExecute (ExecutionContext context, ConfigurationSelector configuration)
  282. {
  283. if (IdeApp.ProjectOperations.CurrentSelectedSolution != null)
  284. return IdeApp.ProjectOperations.CurrentSelectedSolution.CanExecute (context, configuration);
  285. else {
  286. return false;
  287. }
  288. }
  289. public void Dispose ()
  290. {
  291. }
  292. public void Save (IProgressMonitor monitor)
  293. {
  294. monitor.BeginTask (GettextCatalog.GetString ("Saving Workspace..."), Items.Count);
  295. List<WorkspaceItem> items = new List<WorkspaceItem> (Items);
  296. foreach (WorkspaceItem it in items) {
  297. it.Save (monitor);
  298. monitor.Step (1);
  299. }
  300. monitor.EndTask ();
  301. }
  302. BuildResult IBuildTarget.RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
  303. {
  304. BuildResult result = null;
  305. List<WorkspaceItem> items = new List<WorkspaceItem> (Items);
  306. foreach (WorkspaceItem it in items) {
  307. BuildResult res = it.RunTarget (monitor, target, configuration);
  308. if (res != null) {
  309. if (result == null)
  310. result = new BuildResult ();
  311. result.Append (res);
  312. }
  313. }
  314. return result;
  315. }
  316. public void Execute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
  317. {
  318. Solution sol = IdeApp.ProjectOperations.CurrentSelectedSolution;
  319. if (sol == null) {
  320. ReadOnlyCollection<Solution> sols = GetAllSolutions ();
  321. if (sols.Count > 0)
  322. sol = sols [0];
  323. }
  324. if (sol != null)
  325. sol.Execute (monitor, context, configuration);
  326. else
  327. throw new UserException (GettextCatalog.GetString ("No solution has been selected."));
  328. }
  329. public bool NeedsBuilding ()
  330. {
  331. return NeedsBuilding (IdeApp.Workspace.ActiveConfiguration) || IsDirtyFileInCombine;
  332. }
  333. public bool NeedsBuilding (ConfigurationSelector configuration)
  334. {
  335. foreach (WorkspaceItem it in Items) {
  336. if (it.NeedsBuilding (configuration))
  337. return true;
  338. }
  339. return false;
  340. }
  341. public void SetNeedsBuilding (bool needsBuilding, ConfigurationSelector configuration)
  342. {
  343. foreach (WorkspaceItem it in Items)
  344. it.SetNeedsBuilding (needsBuilding, configuration);
  345. }
  346. bool IsDirtyFileInCombine {
  347. get {
  348. foreach (Project projectEntry in GetAllProjects()) {
  349. foreach (ProjectFile fInfo in projectEntry.Files) {
  350. foreach (Document doc in IdeApp.Workbench.Documents) {
  351. if (doc.IsDirty && doc.FileName == fInfo.FilePath) {
  352. return true;
  353. }
  354. }
  355. }
  356. }
  357. return false;
  358. }
  359. }
  360. public ReadOnlyCollection<string> GetConfigurations ()
  361. {
  362. List<string> configs = new List<string> ();
  363. foreach (WorkspaceItem it in Items) {
  364. foreach (string conf in it.GetConfigurations ()) {
  365. if (!configs.Contains (conf))
  366. configs.Add (conf);
  367. }
  368. }
  369. return configs.AsReadOnly ();
  370. }
  371. #endregion
  372. #region Opening and closing
  373. public void SavePreferences ()
  374. {
  375. foreach (WorkspaceItem it in Items)
  376. SavePreferences (it);
  377. }
  378. public bool Close ()
  379. {
  380. return Close (true);
  381. }
  382. public bool Close (bool saveWorkspacePreferencies)
  383. {
  384. return Close (saveWorkspacePreferencies, true);
  385. }
  386. internal bool Close (bool saveWorkspacePreferencies, bool closeProjectFiles)
  387. {
  388. if (Items.Count > 0) {
  389. // Request permission for unloading the items
  390. foreach (WorkspaceItem it in new List<WorkspaceItem> (Items)) {
  391. if (!RequestItemUnload (it))
  392. return false;
  393. }
  394. if (saveWorkspacePreferencies)
  395. SavePreferences ();
  396. if (closeProjectFiles) {
  397. foreach (Document doc in IdeApp.Workbench.Documents.ToArray ()) {
  398. if (!doc.Close ())
  399. return false;
  400. }
  401. }
  402. foreach (WorkspaceItem it in new List<WorkspaceItem> (Items)) {
  403. try {
  404. Items.Remove (it);
  405. it.Dispose ();
  406. } catch (Exception ex) {
  407. MessageService.ShowException (ex, GettextCatalog.GetString ("Could not close solution '{0}'.", it.Name));
  408. }
  409. }
  410. }
  411. return true;
  412. }
  413. public void CloseWorkspaceItem (WorkspaceItem item, bool closeItemFiles = true)
  414. {
  415. if (!Items.Contains (item))
  416. throw new InvalidOperationException ("Only top level items can be closed.");
  417. if (Items.Count == 1 && closeItemFiles) {
  418. // There is only one item, close the whole workspace
  419. Close (true, closeItemFiles);
  420. return;
  421. }
  422. if (RequestItemUnload (item)) {
  423. if (closeItemFiles) {
  424. var projects = item.GetAllProjects ();
  425. foreach (Document doc in IdeApp.Workbench.Documents.Where (d => d.Project != null && projects.Contains (d.Project)).ToArray ()) {
  426. if (!doc.Close ())
  427. return;
  428. }
  429. }
  430. Items.Remove (item);
  431. }
  432. }
  433. public bool RequestItemUnload (IBuildTarget item)
  434. {
  435. if (ItemUnloading != null) {
  436. try {
  437. ItemUnloadingEventArgs args = new ItemUnloadingEventArgs (item);
  438. ItemUnloading (this, args);
  439. return !args.Cancel;
  440. } catch (Exception ex) {
  441. LoggingService.LogError ("Exception in ItemUnloading.", ex);
  442. }
  443. }
  444. return true;
  445. }
  446. public IAsyncOperation OpenWorkspaceItem (string filename)
  447. {
  448. return OpenWorkspaceItem (filename, true);
  449. }
  450. public IAsyncOperation OpenWorkspaceItem (string filename, bool closeCurrent)
  451. {
  452. return OpenWorkspaceItem (filename, closeCurrent, true);
  453. }
  454. public IAsyncOperation OpenWorkspaceItem (string filename, bool closeCurrent, bool loadPreferences)
  455. {
  456. if (closeCurrent) {
  457. if (!Close ())
  458. return MonoDevelop.Core.ProgressMonitoring.NullAsyncOperation.Failure;
  459. }
  460. if (filename.StartsWith ("file://"))
  461. filename = new Uri(filename).LocalPath;
  462. var monitor = IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor (true);
  463. bool reloading = IsReloading;
  464. DispatchService.BackgroundDispatch (delegate {
  465. BackgroundLoadWorkspace (monitor, filename, loadPreferences, reloading);
  466. });
  467. return monitor.AsyncOperation;
  468. }
  469. void ReattachDocumentProjects (IEnumerable<string> closedDocs)
  470. {
  471. foreach (Document doc in IdeApp.Workbench.Documents) {
  472. if (doc.Project == null && doc.IsFile) {
  473. Project p = GetProjectContainingFile (doc.FileName);
  474. if (p != null)
  475. doc.SetProject (p);
  476. }
  477. }
  478. if (closedDocs != null) {
  479. foreach (string doc in closedDocs) {
  480. IdeApp.Workbench.OpenDocument (doc, false);
  481. }
  482. }
  483. }
  484. void BackgroundLoadWorkspace (IProgressMonitor monitor, string filename, bool loadPreferences, bool reloading)
  485. {
  486. WorkspaceItem item = null;
  487. ITimeTracker timer = Counters.OpenWorkspaceItemTimer.BeginTiming ();
  488. try {
  489. if (reloading)
  490. SetReloading (true);
  491. if (!File.Exists (filename)) {
  492. monitor.ReportError (GettextCatalog.GetString ("File not found: {0}", filename), null);
  493. monitor.Dispose ();
  494. return;
  495. }
  496. for (int i = 0; i < Items.Count; i++) {
  497. if (Items[i].FileName == filename) {
  498. IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem = Items[i];
  499. monitor.Dispose ();
  500. return;
  501. }
  502. }
  503. if (!Services.ProjectService.IsWorkspaceItemFile (filename)) {
  504. if (!Services.ProjectService.IsSolutionItemFile (filename)) {
  505. monitor.ReportError (GettextCatalog.GetString ("File is not a project or solution: {0}", filename), null);
  506. monitor.Dispose ();
  507. return;
  508. }
  509. // It is a project, not a solution. Try to create a dummy solution and add the project to it
  510. timer.Trace ("Getting wrapper solution");
  511. item = IdeApp.Services.ProjectService.GetWrapperSolution (monitor, filename);
  512. }
  513. if (item == null) {
  514. timer.Trace ("Reading item");
  515. item = Services.ProjectService.ReadWorkspaceItem (monitor, filename);
  516. if (monitor.IsCancelRequested) {
  517. monitor.Dispose ();
  518. return;
  519. }
  520. }
  521. timer.Trace ("Registering to recent list");
  522. DesktopService.RecentFiles.AddProject (item.FileName, item.Name);
  523. timer.Trace ("Adding to items list");
  524. Items.Add (item);
  525. timer.Trace ("Searching for new files");
  526. SearchForNewFiles ();
  527. } catch (Exception ex) {
  528. monitor.ReportError ("Load operation failed.", ex);
  529. // Don't use 'finally' to dispose the monitor, since it has to be disposed later
  530. monitor.Dispose ();
  531. timer.End ();
  532. return;
  533. } finally {
  534. if (reloading)
  535. SetReloading (false);
  536. }
  537. Gtk.Application.Invoke (delegate {
  538. using (monitor) {
  539. try {
  540. if (IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem == null)
  541. IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem = GetAllSolutions ().FirstOrDefault ();
  542. if (Items.Count == 1 && loadPreferences) {
  543. timer.Trace ("Restoring workspace preferences");
  544. RestoreWorkspacePreferences (item);
  545. }
  546. timer.Trace ("Reattaching documents");
  547. ReattachDocumentProjects (null);
  548. monitor.ReportSuccess (GettextCatalog.GetString ("Solution loaded."));
  549. } finally {
  550. timer.End ();
  551. }
  552. }
  553. });
  554. }
  555. void SearchForNewFiles ()
  556. {
  557. foreach (Project p in GetAllProjects ()) {
  558. if (p.NewFileSearch != NewFileSearch.None)
  559. SearchNewFiles (p);
  560. }
  561. }
  562. void SearchNewFiles (Project project)
  563. {
  564. var newFiles = new List<string> ();
  565. string[] collection = Directory.GetFiles (project.BaseDirectory, "*", SearchOption.AllDirectories);
  566. var projectFileNames = new HashSet<string> ();
  567. foreach (var file in project.GetItemFiles (true))
  568. projectFileNames.Add (file);
  569. //also ignore files that would conflict with links
  570. foreach (var f in project.Files)
  571. projectFileNames.Add (f.ProjectVirtualPath.ToAbsolute (project.BaseDirectory));
  572. foreach (string sfile in collection) {
  573. if (projectFileNames.Contains (Path.GetFullPath (sfile)))
  574. continue;
  575. if (IdeApp.Services.ProjectService.IsSolutionItemFile (sfile) || IdeApp.Services.ProjectService.IsWorkspaceItemFile (sfile))
  576. continue;
  577. if (IgnoreFileInSearch (sfile))
  578. continue;
  579. newFiles.Add (sfile);
  580. }
  581. if (newFiles.Count == 0)
  582. return;
  583. if (project.NewFileSearch == NewFileSearch.OnLoadAutoInsert) {
  584. foreach (string file in newFiles) {
  585. project.AddFile (file);
  586. }
  587. return;
  588. }
  589. DispatchService.GuiDispatch (delegate {
  590. var dialog = new IncludeNewFilesDialog (
  591. GettextCatalog.GetString ("Found new files in {0}", project.Name),
  592. project.BaseDirectory
  593. );
  594. dialog.AddFiles (newFiles);
  595. if (MessageService.ShowCustomDialog (dialog) != (int)Gtk.ResponseType.Ok)
  596. return;
  597. foreach (var file in dialog.IgnoredFiles) {
  598. var projectFile = project.AddFile (file, BuildAction.None);
  599. if (projectFile != null)
  600. projectFile.Visible = false;
  601. }
  602. foreach (var file in dialog.SelectedFiles) {
  603. project.AddFile (file);
  604. }
  605. IdeApp.ProjectOperations.Save (project);
  606. });
  607. }
  608. bool IgnoreFileInSearch (string sfile)
  609. {
  610. string extension = Path.GetExtension (sfile).ToUpper();
  611. string file = Path.GetFileName (sfile);
  612. if (file.StartsWith (".") || file.EndsWith ("~"))
  613. return true;
  614. string[] ignoredExtensions = new string [] {
  615. ".SCC", ".DLL", ".PDB", ".MDB", ".EXE", ".SLN", ".CMBX", ".PRJX",
  616. ".SWP", ".MDSX", ".MDS", ".MDP", ".PIDB", ".PIDB-JOURNAL",
  617. };
  618. if (ignoredExtensions.Contains (extension))
  619. return true;
  620. string directory = Path.GetDirectoryName (sfile);
  621. if (directory.IndexOf (".svn") != -1 || directory.IndexOf (".git") != -1 || directory.IndexOf ("CVS") != -1)
  622. return true;
  623. if (directory.IndexOf (Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar) != -1
  624. || directory.IndexOf (Path.DirectorySeparatorChar + "obj" + Path.DirectorySeparatorChar) != -1)
  625. return true;
  626. if (file.EndsWith ("make.sh") || file.StartsWith ("Makefile") || directory.EndsWith ("ProjectDocumentation"))
  627. return true;
  628. return false;
  629. }
  630. void RestoreWorkspacePreferences (WorkspaceItem item)
  631. {
  632. // Restore local configuration data
  633. try {
  634. WorkspaceUserData data = item.UserProperties.GetValue<WorkspaceUserData> ("MonoDevelop.Ide.Workspace");
  635. if (data != null) {
  636. PreferredActiveExecutionTarget = data.PreferredExecutionTarget;
  637. ActiveExecutionTarget = null;
  638. if (GetConfigurations ().Contains (data.ActiveConfiguration))
  639. activeConfiguration = data.ActiveConfiguration;
  640. else
  641. activeConfiguration = GetBestDefaultConfiguration ();
  642. if (string.IsNullOrEmpty (data.ActiveRuntime))
  643. UseDefaultRuntime = true;
  644. else {
  645. TargetRuntime tr = Runtime.SystemAssemblyService.GetTargetRuntime (data.ActiveRuntime);
  646. if (tr != null)
  647. ActiveRuntime = tr;
  648. else
  649. UseDefaultRuntime = true;
  650. }
  651. OnActiveConfigurationChanged ();
  652. }
  653. else {
  654. ActiveConfigurationId = GetBestDefaultConfiguration ();
  655. }
  656. }
  657. catch (Exception ex) {
  658. LoggingService.LogError ("Exception while loading user solution preferences.", ex);
  659. }
  660. // Allow add-ins to restore preferences
  661. if (LoadingUserPreferences != null) {
  662. UserPreferencesEventArgs args = new UserPreferencesEventArgs (item, item.UserProperties);
  663. try {
  664. LoadingUserPreferences (this, args);
  665. } catch (Exception ex) {
  666. LoggingService.LogError ("Exception in LoadingUserPreferences.", ex);
  667. }
  668. }
  669. }
  670. string GetBestDefaultConfiguration ()
  671. {
  672. // 'Debug' is always the best candidate. If there is no debug, pick
  673. // the configuration with the highest number of built projects.
  674. int nbuilds = 0;
  675. string bestConfig = null;
  676. foreach (Solution sol in GetAllSolutions ()) {
  677. foreach (string conf in sol.GetConfigurations ()) {
  678. if (conf == "Debug")
  679. return conf;
  680. SolutionConfiguration sconf = sol.GetConfiguration (new SolutionConfigurationSelector (conf));
  681. int c = 0;
  682. foreach (var sce in sconf.Configurations)
  683. if (sce.Build) c++;
  684. if (c > nbuilds) {
  685. nbuilds = c;
  686. bestConfig = conf;
  687. }
  688. }
  689. }
  690. return bestConfig;
  691. }
  692. public void SavePreferences (WorkspaceItem item)
  693. {
  694. // Local configuration info
  695. WorkspaceUserData data = new WorkspaceUserData ();
  696. data.ActiveConfiguration = ActiveConfigurationId;
  697. data.ActiveRuntime = UseDefaultRuntime ? null : ActiveRuntime.Id;
  698. if (ActiveExecutionTarget != null)
  699. data.PreferredExecutionTarget = ActiveExecutionTarget.Id;
  700. item.UserProperties.SetValue ("MonoDevelop.Ide.Workspace", data);
  701. // Allow add-ins to fill-up data
  702. if (StoringUserPreferences != null) {
  703. UserPreferencesEventArgs args = new UserPreferencesEventArgs (item, item.UserProperties);
  704. try {
  705. StoringUserPreferences (this, args);
  706. } catch (Exception ex) {
  707. LoggingService.LogError ("Exception in UserPreferencesRequested.", ex);
  708. }
  709. }
  710. // Save the file
  711. item.SaveUserProperties ();
  712. }
  713. public FileStatusTracker GetFileStatusTracker ()
  714. {
  715. FileStatusTracker fs = new FileStatusTracker ();
  716. fs.AddFiles (GetKnownFiles ());
  717. return fs;
  718. }
  719. IEnumerable<FilePath> GetKnownFiles ()
  720. {
  721. foreach (WorkspaceItem item in IdeApp.Workspace.Items) {
  722. foreach (FilePath file in item.GetItemFiles (true))
  723. yield return file;
  724. }
  725. }
  726. int reloadingCount;
  727. internal bool IsReloading {
  728. get { return reloadingCount > 0; }
  729. }
  730. void SetReloading (bool doingIt)
  731. {
  732. if (doingIt)
  733. reloadingCount++;
  734. else
  735. reloadingCount--;
  736. }
  737. void CheckWorkspaceItems (object sender, FileEventArgs args)
  738. {
  739. List<FilePath> files = args.Select (e => e.FileName.CanonicalPath).ToList ();
  740. foreach (Solution s in GetAllSolutions ().Where (sol => files.Contains (sol.FileName.CanonicalPath)))
  741. OnCheckWorkspaceItem (s);
  742. foreach (Project p in GetAllProjects ().Where (proj => files.Contains (proj.FileName.CanonicalPath)))
  743. OnCheckProject (p);
  744. }
  745. bool OnRunProjectChecks ()
  746. {
  747. // If any project has been modified, reload it
  748. foreach (WorkspaceItem it in new List<WorkspaceItem> (Items))
  749. OnCheckWorkspaceItem (it);
  750. return true;
  751. }
  752. void OnCheckWorkspaceItem (WorkspaceItem item)
  753. {
  754. if (item.NeedsReload) {
  755. IEnumerable<string> closedDocs;
  756. if (AllowReload (item.GetAllProjects (), out closedDocs)) {
  757. if (item.ParentWorkspace == null) {
  758. string file = item.FileName;
  759. try {
  760. SetReloading (true);
  761. SavePreferences ();
  762. CloseWorkspaceItem (item, false);
  763. OpenWorkspaceItem (file, false, false);
  764. } finally {
  765. SetReloading (false);
  766. }
  767. }
  768. else {
  769. using (IProgressMonitor m = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true)) {
  770. item.ParentWorkspace.ReloadItem (m, item);
  771. ReattachDocumentProjects (closedDocs);
  772. }
  773. }
  774. return;
  775. } else
  776. item.NeedsReload = false;
  777. }
  778. if (item is Workspace) {
  779. Workspace ws = (Workspace) item;
  780. List<WorkspaceItem> items = new List<WorkspaceItem> (ws.Items);
  781. foreach (WorkspaceItem it in items)
  782. OnCheckWorkspaceItem (it);
  783. }
  784. else if (item is Solution) {
  785. Solution sol = (Solution) item;
  786. OnCheckProject (sol.RootFolder);
  787. }
  788. }
  789. void OnCheckProject (SolutionItem entry)
  790. {
  791. if (entry.NeedsReload) {
  792. IEnumerable projects = null;
  793. if (entry is Project) {
  794. projects = new Project [] { (Project) entry };
  795. } else if (entry is SolutionFolder) {
  796. projects = ((SolutionFolder)entry).GetAllProjects ();
  797. }
  798. IEnumerable<string> closedDocs;
  799. if (AllowReload (projects, out closedDocs)) {
  800. using (IProgressMonitor m = IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor (true)) {
  801. // Root folders never need to reload
  802. entry.ParentFolder.ReloadItem (m, entry);
  803. ReattachDocumentProjects (closedDocs);
  804. }
  805. return;
  806. } else
  807. entry.NeedsReload = false;
  808. }
  809. if (entry is SolutionFolder) {
  810. ArrayList ens = new ArrayList ();
  811. foreach (SolutionItem ce in ((SolutionFolder)entry).Items)
  812. ens.Add (ce);
  813. foreach (SolutionItem ce in ens)
  814. OnCheckProject (ce);
  815. }
  816. }
  817. // bool AllowReload (IEnumerable projects)
  818. // {
  819. // IEnumerable<string> closedDocs;
  820. // return AllowReload (projects, out closedDocs);
  821. // }
  822. bool AllowReload (IEnumerable projects, out IEnumerable<string> closedDocs)
  823. {
  824. closedDocs = null;
  825. if (projects == null)
  826. return true;
  827. List<Document> docs = new List<Document> ();
  828. foreach (Project p in projects) {
  829. docs.AddRange (GetOpenDocuments (p, false));
  830. }
  831. if (docs.Count == 0)
  832. return true;
  833. // Find a common project reload capability
  834. bool hasUnsaved = false;
  835. bool hasNoFiles = false;
  836. ProjectReloadCapability prc = ProjectReloadCapability.Full;
  837. foreach (Document doc in docs) {
  838. if (doc.IsDirty)
  839. hasUnsaved = true;
  840. if (!doc.IsFile)
  841. hasNoFiles = true;
  842. ISupportsProjectReload pr = doc.GetContent<ISupportsProjectReload> ();
  843. if (pr != null) {
  844. ProjectReloadCapability c = pr.ProjectReloadCapability;
  845. if ((int) c < (int) prc)
  846. prc = c;
  847. }
  848. else
  849. prc = ProjectReloadCapability.None;
  850. }
  851. string msg = null;
  852. switch (prc) {
  853. case ProjectReloadCapability.None:
  854. if (hasNoFiles && hasUnsaved)
  855. msg = GettextCatalog.GetString ("WARNING: Some documents may need to be closed, and unsaved data will be lost. You will be asked to save the unsaved documents.");
  856. else if (hasNoFiles)
  857. msg = GettextCatalog.GetString ("WARNING: Some documents may need to be reloaded or closed, and unsaved data will be lost. You will be asked to save the unsaved documents.");
  858. else if (hasUnsaved)
  859. msg = GettextCatalog.GetString ("WARNING: Some files may need to be reloaded, and unsaved data will be lost. You will be asked to save the unsaved files.");
  860. else
  861. goto case ProjectReloadCapability.UnsavedData;
  862. break;
  863. case ProjectReloadCapability.UnsavedData:
  864. msg = GettextCatalog.GetString ("Some files may need to be reloaded, and editing status for those files (such as the undo queue) will be lost.");
  865. break;
  866. }
  867. if (msg != null) {
  868. if (!MessageService.Confirm (GettextCatalog.GetString ("The project '{0}' has been modified by an external application. Do you want to reload it?", docs[0].Project.Name), msg, AlertButton.Reload))
  869. return false;
  870. }
  871. List<string> closed = new List<string> ();
  872. foreach (Document doc in docs) {
  873. if (doc.IsDirty)
  874. hasUnsaved = true;
  875. ISupportsProjectReload pr = doc.GetContent<ISupportsProjectReload> ();
  876. if (pr != null)
  877. doc.SetProject (null);
  878. else {
  879. FilePath file = doc.IsFile ? doc.FileName : FilePath.Null;
  880. EventHandler saved = delegate {
  881. if (doc.IsFile)
  882. file = doc.FileName;
  883. };
  884. doc.Saved += saved;
  885. try {
  886. if (!doc.Close ())
  887. return false;
  888. else if (!file.IsNullOrEmpty && File.Exists (file))
  889. closed.Add (file);
  890. } finally {
  891. doc.Saved -= saved;
  892. }
  893. }
  894. }
  895. closedDocs = closed;
  896. return true;
  897. }
  898. internal List<Document> GetOpenDocuments (Project project, bool modifiedOnly)
  899. {
  900. List<Document> docs = new List<Document> ();
  901. foreach (Document doc in IdeApp.Workbench.Documents) {
  902. if (doc.Project == project && (!modifiedOnly || doc.IsDirty)) {
  903. docs.Add (doc);
  904. }
  905. }
  906. return docs;
  907. }
  908. #endregion
  909. #region Event handling
  910. internal void NotifyItemAdded (WorkspaceItem item)
  911. {
  912. if (DispatchService.IsGuiThread)
  913. NotifyItemAddedGui (item, IsReloading);
  914. else {
  915. bool reloading = IsReloading;
  916. Gtk.Application.Invoke (delegate {
  917. NotifyItemAddedGui (item, reloading);
  918. });
  919. }
  920. }
  921. void NotifyItemAddedGui (WorkspaceItem item, bool reloading)
  922. {
  923. try {
  924. // Mono.Profiler.RuntimeControls.EnableProfiler ();
  925. MonoDevelop.Ide.TypeSystem.TypeSystemService.Load (item);
  926. // Mono.Profiler.RuntimeControls.DisableProfiler ();
  927. // Console.WriteLine ("PARSE LOAD: " + (DateTime.Now - t).TotalMilliseconds);
  928. } catch (Exception ex) {
  929. LoggingService.LogError ("Could not load parser database.", ex);
  930. }
  931. Workspace ws = item as Workspace;
  932. if (ws != null) {
  933. ws.DescendantItemAdded += descendantItemAddedHandler;
  934. ws.DescendantItemRemoved += descendantItemRemovedHandler;
  935. }
  936. item.ConfigurationsChanged += configurationsChanged;
  937. WorkspaceItemEventArgs args = new WorkspaceItemEventArgs (item);
  938. NotifyDescendantItemAdded (this, args);
  939. NotifyConfigurationsChanged (null, args);
  940. if (WorkspaceItemOpened != null)
  941. WorkspaceItemOpened (this, args);
  942. if (Items.Count == 1 && !reloading) {
  943. IdeApp.Workbench.CurrentLayout = "Solution";
  944. if (FirstWorkspaceItemOpened != null)
  945. FirstWorkspaceItemOpened (this, args);
  946. }
  947. }
  948. internal void NotifyItemRemoved (WorkspaceItem item)
  949. {
  950. if (DispatchService.IsGuiThread)
  951. NotifyItemRemovedGui (item, IsReloading);
  952. else {
  953. bool reloading = IsReloading;
  954. Gtk.Application.Invoke (delegate {
  955. NotifyItemRemovedGui (item, reloading);
  956. });
  957. }
  958. }
  959. internal void NotifyItemRemovedGui (WorkspaceItem item, bool reloading)
  960. {
  961. Workspace ws = item as Workspace;
  962. if (ws != null) {
  963. ws.DescendantItemAdded -= descendantItemAddedHandler;
  964. ws.DescendantItemRemoved -= descendantItemRemovedHandler;
  965. }
  966. item.ConfigurationsChanged -= configurationsChanged;
  967. if (Items.Count == 0 && !reloading) {
  968. if (LastWorkspaceItemClosed != null)
  969. LastWorkspaceItemClosed (this, EventArgs.Empty);
  970. }
  971. WorkspaceItemEventArgs args = new WorkspaceItemEventArgs (item);
  972. NotifyConfigurationsChanged (null, args);
  973. if (WorkspaceItemClosed != null)
  974. WorkspaceItemClosed (this, args);
  975. MonoDevelop.Ide.TypeSystem.TypeSystemService.Unload (item);
  976. // ParserDatabase.Unload (item);
  977. NotifyDescendantItemRemoved (this, args);
  978. }
  979. void SubscribeSolution (Solution sol)
  980. {
  981. sol.FileAddedToProject += fileAddedToProjectHandler;
  982. sol.FileRemovedFromProject += fileRemovedFromProjectHandler;
  983. sol.FileRenamedInProject += fileRenamedInProjectHandler;
  984. sol.FileChangedInProject += fileChangedInProjectHandler;
  985. sol.FilePropertyChangedInProject += filePropertyChangedInProjectHandler;
  986. sol.ReferenceAddedToProject += referenceAddedToProjectHandler;
  987. sol.ReferenceRemovedFromProject += referenceRemovedFromProjectHandler;
  988. sol.SolutionItemAdded += itemAddedToSolutionHandler;
  989. sol.SolutionItemRemoved += itemRemovedFromSolutionHandler;
  990. }
  991. void UnsubscribeSolution (Solution solution)
  992. {
  993. solution.FileAddedToProject -= fileAddedToProjectHandler;
  994. solution.FileRemovedFromProject -= fileRemovedFromProjectHandler;
  995. solution.FileRenamedInProject -= fileRenamedInProjectHandler;
  996. solution.FileChangedInProject -= fileChangedInProjectHandler;
  997. solution.FilePropertyChangedInProject -= filePropertyChangedInProjectHandler;
  998. solution.ReferenceAddedToProject -= referenceAddedToProjectHandler;
  999. solution.ReferenceRemovedFromProject -= referenceRemovedFromProjectHandler;
  1000. solution.SolutionItemAdded -= itemAddedToSolutionHandler;
  1001. solution.SolutionItemRemoved -= itemRemovedFromSolutionHandler;
  1002. }
  1003. void NotifyConfigurationsChanged (object s, EventArgs a)
  1004. {
  1005. if (ConfigurationsChanged != null)
  1006. ConfigurationsChanged (this, a);
  1007. }
  1008. void NotifyFileRemovedFromProject (object sender, ProjectFileEventArgs e)
  1009. {
  1010. if (FileRemovedFromProject != null) {
  1011. FileRemovedFromProject(this, e);
  1012. }
  1013. }
  1014. void NotifyFileAddedToProject (object sender, ProjectFileEventArgs e)
  1015. {
  1016. if (FileAddedToProject != null) {
  1017. FileAddedToProject (this, e);
  1018. }
  1019. }
  1020. internal void NotifyFileRenamedInProject (object sender, ProjectFileRenamedEventArgs e)
  1021. {
  1022. if (FileRenamedInProject != null) {
  1023. FileRenamedInProject (this, e);
  1024. }
  1025. }
  1026. internal void NotifyFileChangedInProject (object sender, ProjectFileEventArgs e)
  1027. {
  1028. if (FileChangedInProject != null) {
  1029. FileChangedInProject (this, e);
  1030. }
  1031. }
  1032. internal void NotifyFilePropertyChangedInProject (object sender, ProjectFileEventArgs e)
  1033. {
  1034. if (FilePropertyChangedInProject != null) {
  1035. FilePropertyChangedInProject (this, e);
  1036. }
  1037. }
  1038. internal void NotifyReferenceAddedToProject (object sender, ProjectReferenceEventArgs e)
  1039. {
  1040. if (ReferenceAddedToProject != null) {
  1041. ReferenceAddedToProject (this, e);
  1042. }
  1043. }
  1044. internal void NotifyReferenceRemovedFromProject (object sender, ProjectReferenceEventArgs e)
  1045. {
  1046. if (ReferenceRemovedFromProject != null) {
  1047. ReferenceRemovedFromProject (this, e);
  1048. }
  1049. }
  1050. void NotifyItemAddedToSolution (object sender, SolutionItemChangeEventArgs args)
  1051. {
  1052. // Delay the notification of this event to ensure that the new project is properly
  1053. // registered in the parser database when it is fired
  1054. Gtk.Application.Invoke (delegate {
  1055. if (ItemAddedToSolution != null)
  1056. ItemAddedToSolution (sender, args);
  1057. });
  1058. }
  1059. void NotifyItemRemovedFromSolution (object sender, SolutionItemChangeEventArgs args)
  1060. {
  1061. NotifyItemRemovedFromSolutionRec (sender, args.SolutionItem, args.Solution);
  1062. }
  1063. void NotifyItemRemovedFromSolutionRec (object sender, SolutionItem e, Solution sol)
  1064. {
  1065. if (e == IdeApp.ProjectOperations.CurrentSelectedSolutionItem)
  1066. IdeApp.ProjectOperations.CurrentSelectedSolutionItem = null;
  1067. if (e is SolutionFolder) {
  1068. foreach (SolutionItem ce in ((SolutionFolder)e).Items)
  1069. NotifyItemRemovedFromSolutionRec (sender, ce, sol);
  1070. }
  1071. if (ItemRemovedFromSolution != null)
  1072. ItemRemovedFromSolution (sender, new SolutionItemChangeEventArgs (e, sol, false));
  1073. }
  1074. void NotifyDescendantItemAdded (object s, WorkspaceItemEventArgs args)
  1075. {
  1076. // If a top level item has been moved to a child item, remove it from
  1077. // the top
  1078. if (s != this && Items.Contains (args.Item))
  1079. Items.Remove (args.Item);
  1080. foreach (WorkspaceItem item in args.Item.GetAllItems ()) {
  1081. if (item is Solution)
  1082. SubscribeSolution ((Solution)item);
  1083. OnItemLoaded (item);
  1084. }
  1085. }
  1086. void NotifyDescendantItemRemoved (object s, WorkspaceItemEventArgs args)
  1087. {
  1088. foreach (WorkspaceItem item in args.Item.GetAllItems ()) {
  1089. OnItemUnloaded (item);
  1090. if (item is Solution)
  1091. UnsubscribeSolution ((Solution)item);
  1092. }
  1093. }
  1094. void OnItemLoaded (WorkspaceItem item)
  1095. {
  1096. try {
  1097. if (WorkspaceItemLoaded != null)
  1098. WorkspaceItemLoaded (this, new WorkspaceItemEventArgs (item));
  1099. if (item is Solution && SolutionLoaded != null)
  1100. SolutionLoaded (this, new SolutionEventArgs ((Solution)item));
  1101. } catch (Exception ex) {
  1102. LoggingService.LogError ("Error in SolutionOpened event.", ex);
  1103. }
  1104. }
  1105. void OnItemUnloaded (WorkspaceItem item)
  1106. {
  1107. try {
  1108. if (WorkspaceItemUnloaded != null)
  1109. WorkspaceItemUnloaded (this, new WorkspaceItemEventArgs (item));
  1110. if (item is Solution && SolutionUnloaded != null)
  1111. SolutionUnloaded (this, new SolutionEventArgs ((Solution)item));
  1112. } catch (Exception ex) {
  1113. LoggingService.LogError ("Error in SolutionClosed event.", ex);
  1114. }
  1115. }
  1116. void CheckFileRename(object sender, FileCopyEventArgs args)
  1117. {
  1118. foreach (Solution sol in GetAllSolutions ()) {
  1119. foreach (FileCopyEventInfo e in args)
  1120. sol.RootFolder.RenameFileInProjects (e.SourceFile, e.TargetFile);
  1121. }
  1122. }
  1123. #endregion
  1124. #region Event declaration
  1125. /// <summary>
  1126. /// Fired when a file is removed from a project.
  1127. /// </summary>
  1128. public event ProjectFileEventHandler FileRemovedFromProject;
  1129. /// <summary>
  1130. /// Fired when a file is added to a project
  1131. /// </summary>
  1132. public event ProjectFileEventHandler FileAddedToProject;
  1133. /// <summary>
  1134. /// Fired when a file belonging to a project is modified.
  1135. /// </summary>
  1136. /// <remarks>
  1137. /// If the file belongs to several projects, the event will be fired for each project
  1138. /// </remarks>
  1139. public event ProjectFileEventHandler FileChangedInProject;
  1140. /// <summary>
  1141. /// Fired when a property of a project file is modified
  1142. /// </summary>
  1143. public event ProjectFileEventHandler FilePropertyChangedInProject;
  1144. /// <summary>
  1145. /// Fired when a project file is renamed
  1146. /// </summary>
  1147. public event ProjectFileRenamedEventHandler FileRenamedInProject;
  1148. /// <summary>
  1149. /// Fired when a solution is loaded in the workbench
  1150. /// </summary>
  1151. /// <remarks>
  1152. /// This event is fired recursively for every solution
  1153. /// opened in the IDE. For example, if the user opens a workspace
  1154. /// which contains two solutions, this event will be fired once
  1155. /// for each solution.
  1156. /// </remarks>
  1157. public event EventHandler<SolutionEventArgs> SolutionLoaded;
  1158. /// <summary>
  1159. /// Fired when a solution loaded in the workbench is unloaded
  1160. /// </summary>
  1161. public event EventHandler<SolutionEventArgs> SolutionUnloaded;
  1162. /// <summary>
  1163. /// Fired when a workspace item (a solution or workspace) is opened and there
  1164. /// is no other item already open
  1165. /// </summary>
  1166. public event EventHandler<WorkspaceItemEventArgs> FirstWorkspaceItemOpened;
  1167. /// <summary>
  1168. /// Fired a workspace item loaded in the IDE is closed and there are no other
  1169. /// workspace items opened.
  1170. /// </summary>
  1171. public event EventHandler LastWorkspaceItemClosed;
  1172. /// <summary>
  1173. /// Fired when a workspace item (a solution or workspace) is loaded.
  1174. /// </summary>
  1175. /// <remarks>
  1176. /// This event is fired recursively for every solution and workspace
  1177. /// opened in the IDE. For example, if the user opens a workspace
  1178. /// which contains two solutions, this event will be fired three times:
  1179. /// once for the workspace, and once for each solution.
  1180. /// </remarks>
  1181. public event EventHandler<WorkspaceItemEventArgs> WorkspaceItemLoaded;
  1182. /// <summary>
  1183. /// Fired when a workspace item (a solution or workspace) is unloaded
  1184. /// </summary>
  1185. public event EventHandler<WorkspaceItemEventArgs> WorkspaceItemUnloaded;
  1186. /// <summary>
  1187. /// Fired a workspace item (a solution or workspace) is opened in the IDE
  1188. /// </summary>
  1189. public event EventHandler<WorkspaceItemEventArgs> WorkspaceItemOpened;
  1190. /// <summary>
  1191. /// Fired when a workspace item (a solution or workspace) is closed in the IDE
  1192. /// </summary>
  1193. public event EventHandler<WorkspaceItemEventArgs> WorkspaceItemClosed;
  1194. /// <summary>
  1195. /// Fired when user preferences for the active solution are being stored
  1196. /// </summary>
  1197. /// <remarks>
  1198. /// Add-ins can subscribe to this event to store custom user preferences
  1199. /// for a solution. Preferences can be stored in the PropertyBag provided
  1200. /// in the event arguments object.
  1201. /// </remarks>
  1202. public event EventHandler<UserPreferencesEventArgs> StoringUserPreferences;
  1203. /// <summary>
  1204. /// Fired when user preferences for a solution are being loaded
  1205. /// </summary>
  1206. /// <remarks>
  1207. /// Add-ins can subscribe to this event to load preferences previously
  1208. /// stored in the StoringUserPreferences event.
  1209. /// </remarks>
  1210. public event EventHandler<UserPreferencesEventArgs> LoadingUserPreferences;
  1211. /// <summary>
  1212. /// Fired when an item (a project, solution or workspace) is going to be unloaded.
  1213. /// </summary>
  1214. /// <remarks>
  1215. /// This event is fired before unloading the item, and the unload operation can
  1216. /// be cancelled by setting the Cancel property of the ItemUnloadingEventArgs
  1217. /// object to True.
  1218. /// </remarks>
  1219. public event EventHandler<ItemUnloadingEventArgs> ItemUnloading;
  1220. /// <summary>
  1221. /// Fired when an assembly reference is added to a .NET project
  1222. /// </summary>
  1223. public event ProjectReferenceEventHandler ReferenceAddedToProject;
  1224. /// <summary>
  1225. /// Fired when an assembly reference is added to a .NET project
  1226. /// </summary>
  1227. public event ProjectReferenceEventHandler ReferenceRemovedFromProject;
  1228. /// <summary>
  1229. /// Fired just before a project is added to a solution
  1230. /// </summary>
  1231. public event SolutionItemChangeEventHandler ItemAddedToSolution;
  1232. /// <summary>
  1233. /// Fired after a project is removed from a solution
  1234. /// </summary>
  1235. public event SolutionItemChangeEventHandler ItemRemovedFromSolution;
  1236. /// <summary>
  1237. /// Fired when the active solution configuration has changed
  1238. /// </summary>
  1239. public event EventHandler ActiveConfigurationChanged;
  1240. /// <summary>
  1241. /// Fired when the list of solution configurations has changed
  1242. /// </summary>
  1243. public event EventHandler ConfigurationsChanged;
  1244. /// <summary>
  1245. /// Fired when the list of available .NET runtimes has changed
  1246. /// </summary>
  1247. public event EventHandler RuntimesChanged {
  1248. add { Runtime.SystemAssemblyService.RuntimesChanged += value; }
  1249. remove { Runtime.SystemAssemblyService.RuntimesChanged -= value; }
  1250. }
  1251. /// <summary>
  1252. /// Fired when the active .NET runtime has changed
  1253. /// </summary>
  1254. public event EventHandler ActiveRuntimeChanged {
  1255. add { Runtime.SystemAssemblyService.DefaultRuntimeChanged += value; }
  1256. remove { Runtime.SystemAssemblyService.DefaultRuntimeChanged -= value; }
  1257. }
  1258. #endregion
  1259. }
  1260. class RootWorkspaceItemCollection: WorkspaceItemCollection
  1261. {
  1262. RootWorkspace parent;
  1263. public RootWorkspaceItemCollection (RootWorkspace parent)
  1264. {
  1265. this.parent = parent;
  1266. }
  1267. protected override void ClearItems ()
  1268. {
  1269. if (parent != null) {
  1270. List<WorkspaceItem> items = new List<WorkspaceItem> (this);
  1271. foreach (WorkspaceItem it in items)
  1272. parent.NotifyItemRemoved (it);
  1273. }
  1274. else
  1275. base.ClearItems ();
  1276. }
  1277. protected override void InsertItem (int index, WorkspaceItem item)
  1278. {
  1279. base.InsertItem (index, item);
  1280. if (parent != null)
  1281. parent.NotifyItemAdded (item);
  1282. }
  1283. protected override void RemoveItem (int index)
  1284. {
  1285. WorkspaceItem item = this [index];
  1286. base.RemoveItem (index);
  1287. if (parent != null)
  1288. parent.NotifyItemRemoved (item);
  1289. }
  1290. protected override void SetItem (int index, WorkspaceItem item)
  1291. {
  1292. WorkspaceItem oldItem = this [index];
  1293. base.SetItem (index, item);
  1294. if (parent != null) {
  1295. parent.NotifyItemRemoved (oldItem);
  1296. parent.NotifyItemAdded (item);
  1297. }
  1298. }
  1299. }
  1300. public class UserPreferencesEventArgs: WorkspaceItemEventArgs
  1301. {
  1302. PropertyBag properties;
  1303. public PropertyBag Properties {
  1304. get {
  1305. return properties;
  1306. }
  1307. }
  1308. public UserPreferencesEventArgs (WorkspaceItem item, PropertyBag properties): base (item)
  1309. {
  1310. this.properties = properties;
  1311. }
  1312. }
  1313. [DataItem ("Workspace")]
  1314. class WorkspaceUserData
  1315. {
  1316. [ItemProperty]
  1317. public string ActiveConfiguration;
  1318. [ItemProperty]
  1319. public string ActiveRuntime;
  1320. [ItemProperty]
  1321. public string PreferredExecutionTarget;
  1322. }
  1323. public class ItemUnloadingEventArgs: EventArgs
  1324. {
  1325. IBuildTarget item;
  1326. public bool Cancel { get; set; }
  1327. public IBuildTarget Item {
  1328. get {
  1329. return item;
  1330. }
  1331. }
  1332. public ItemUnloadingEventArgs (IBuildTarget item)
  1333. {
  1334. this.item = item;
  1335. }
  1336. }
  1337. public class FileStatusTracker: IDisposable
  1338. {
  1339. class FileData
  1340. {
  1341. public FileData (FilePath file, DateTime time)
  1342. {
  1343. this.File = file;
  1344. this.Time = time;
  1345. }
  1346. public FilePath File;
  1347. public DateTime Time;
  1348. }
  1349. List<FileData> fileStatus = new List<FileData> ();
  1350. internal void AddFiles (IEnumerable<FilePath> files)
  1351. {
  1352. foreach (var file in files) {
  1353. try {
  1354. FileInfo fi = new FileInfo (file);
  1355. FileData fd = new FileData (file, fi.Exists ? fi.LastWriteTime : DateTime.MinValue);
  1356. fileStatus.Add (fd);
  1357. } catch {
  1358. // Ignore
  1359. }
  1360. }
  1361. }
  1362. public void NotifyChanges ()
  1363. {
  1364. List<FilePath> modified = new List<FilePath> ();
  1365. foreach (FileData fd in fileStatus) {
  1366. try {
  1367. FileInfo fi = new FileInfo (fd.File);
  1368. if (fi.Exists) {
  1369. DateTime wt = fi.LastWriteTime;
  1370. if (wt != fd.Time) {
  1371. modified.Add (fd.File);
  1372. fd.Time = wt;
  1373. }
  1374. } else if (fd.Time != DateTime.MinValue) {
  1375. FileService.NotifyFileRemoved (fd.File);
  1376. fd.Time = DateTime.MinValue;
  1377. }
  1378. } catch {
  1379. // Ignore
  1380. }
  1381. }
  1382. if (modified.Count > 0)
  1383. FileService.NotifyFilesChanged (modified);
  1384. }
  1385. void IDisposable.Dispose ()
  1386. {
  1387. NotifyChanges ();
  1388. }
  1389. }
  1390. }
  1391. namespace Mono.Profiler {
  1392. public class RuntimeControls {
  1393. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1394. public static extern void TakeHeapSnapshot ();
  1395. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1396. public static extern void EnableProfiler ();
  1397. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1398. public static extern void DisableProfiler ();
  1399. }
  1400. }