コード例 #1
0
		public static Stetic.CodeGenerationResult GenerateSteticCode (IProgressMonitor monitor, DotNetProject project, ConfigurationSelector configuration)
		{
			if (generating || !GtkDesignInfo.HasDesignedObjects (project))
				return null;
			
			using (var timer = Counters.SteticFileGeneratedTimer.BeginTiming ()) {
				
				timer.Trace ("Checking references");
				GtkDesignInfo info = GtkDesignInfo.FromProject (project);
	
				DateTime last_gen_time = File.Exists (info.SteticGeneratedFile) ? File.GetLastWriteTime (info.SteticGeneratedFile) : DateTime.MinValue;
				
				bool ref_changed = false;
				foreach (ProjectReference pref in project.References) {
					if (!pref.IsValid)
						continue;
					foreach (string filename in pref.GetReferencedFileNames (configuration)) {
						if (File.GetLastWriteTime (filename) > last_gen_time) {
							ref_changed = true;
							break;
						}
					}
					if (ref_changed)
						break;
				}
	
				// Check if generated code is already up to date.
				if (!ref_changed && last_gen_time >= File.GetLastWriteTime (info.SteticFile))
					return null;
				
				if (info.GuiBuilderProject.HasError) {
					monitor.ReportError (GettextCatalog.GetString ("GUI code generation failed for project '{0}'. The file '{1}' could not be loaded.", project.Name, info.SteticFile), null);
					monitor.AsyncOperation.Cancel ();
					return null;
				}
				
				if (info.GuiBuilderProject.IsEmpty) 
					return null;
	
				monitor.Log.WriteLine (GettextCatalog.GetString ("Generating GUI code for project '{0}'...", project.Name));
				
				timer.Trace ("Copy support files");
				
				// Make sure the referenced assemblies are up to date. It is necessary to do
				// it now since they may contain widget libraries.
				project.CopySupportFiles (monitor, configuration);
				
				timer.Trace ("Update libraries");
				
				info.GuiBuilderProject.UpdateLibraries ();
				
				ArrayList projects = new ArrayList ();
				projects.Add (info.GuiBuilderProject.File);
				
				generating = true;
				Stetic.CodeGenerationResult generationResult = null;
				Exception generatedException = null;
				
				bool canGenerateInProcess = IsolationMode != Stetic.IsolationMode.None || info.GuiBuilderProject.SteticProject.CanGenerateCode;
				
				if (!canGenerateInProcess) {
					timer.Trace ("Generating out of process");
				
					// Run the generation in another thread to avoid freezing the GUI
					System.Threading.ThreadPool.QueueUserWorkItem (delegate {
						try {
							// Generate the code in another process if stetic is not isolated
							CodeGeneratorProcess cob = (CodeGeneratorProcess)Runtime.ProcessService.CreateExternalProcessObject (typeof(CodeGeneratorProcess), false);
							using (cob) {
								generationResult = cob.GenerateCode (projects, info.GenerateGettext, info.GettextClass, project.UsePartialTypes);
							}
						} catch (Exception ex) {
							generatedException = ex;
						} finally {
							generating = false;
						}
					});
				
					while (generating) {
						DispatchService.RunPendingEvents ();
						System.Threading.Thread.Sleep (100);
					}
				} else {
					timer.Trace ("Generating in-process");
					// No need to create another process, since stetic has its own backend process
					// or the widget libraries have no custom wrappers
					try {
						Stetic.GenerationOptions options = new Stetic.GenerationOptions ();
						options.UseGettext = info.GenerateGettext;
						options.GettextClass = info.GettextClass;
						options.UsePartialClasses = project.UsePartialTypes;
						options.GenerateSingleFile = false;
						generationResult = SteticApp.GenerateProjectCode (options, info.GuiBuilderProject.SteticProject);
					} catch (Exception ex) {
						generatedException = ex;
					}
					generating = false;
				}
				timer.Trace ("Writing code units");
				
				if (generatedException != null) {
					LoggingService.LogError ("GUI code generation failed", generatedException);
					throw new UserException ("GUI code generation failed: " + generatedException.Message);
				}
				
				if (generationResult == null)
					return null;
					
				CodeDomProvider provider = project.LanguageBinding.GetCodeDomProvider ();
				if (provider == null)
					throw new UserException ("Code generation not supported for language: " + project.LanguageName);
				
				string basePath = Path.GetDirectoryName (info.SteticGeneratedFile);
				string ext = Path.GetExtension (info.SteticGeneratedFile);
				
				var pol = project.Policies.Get<TextStylePolicy> ();
				var codeGeneratorOptions = new CodeGeneratorOptions () {
					IndentString = pol.TabsToSpaces? new string (' ', pol.TabWidth) : "\t",
					BlankLinesBetweenMembers = true
				};

				foreach (Stetic.SteticCompilationUnit unit in generationResult.Units) {
					string fname;
					if (unit.Name.Length == 0)
						fname = info.SteticGeneratedFile;
					else
						fname = Path.Combine (basePath, unit.Name) + ext;
					StringWriter sw = new StringWriter ();
					try {
						foreach (CodeNamespace ns in unit.Namespaces)
							ns.Comments.Add (new CodeCommentStatement ("This file has been generated by the GUI designer. Do not modify."));
						timer.Trace ("Generating code for " + unit.Name);
						provider.GenerateCodeFromCompileUnit (unit, sw, codeGeneratorOptions);
						string content = sw.ToString ();
						timer.Trace ("Formatting code");
						content = FormatGeneratedFile (fname, content, provider);
						timer.Trace ("Writing code");
						File.WriteAllText (fname, content);
					} finally {
						timer.Trace ("Notifying changes");
						FileService.NotifyFileChanged (fname);
					}
				}
				
				timer.Trace ("Updating GTK folder");
				
				// Make sure the generated files are added to the project
				if (info.UpdateGtkFolder ()) {
					Gtk.Application.Invoke (delegate {
						IdeApp.ProjectOperations.Save (project);
					});
				}
				
				return generationResult;
			}
		}