/*----------------------------------------------------------------------
Prof-It for C#
Copyright (c) 2004 Klaus Lehner, University of Linz
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
----------------------------------------------------------------------*/
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
using System.Runtime.Serialization.Formatters.Binary;
using at.jku.ssw.ProfIt.Coco;
using at.jku.ssw.ProfIt.Components;
using at.jku.ssw.ProfIt.CodeGen;
using at.jku.ssw.ProfIt.Dialogs;
using at.jku.ssw.ProfIt.Runtime;
namespace at.jku.ssw.ProfIt{
/// <summary>
/// The SolutionManager is the most important class of the whole project.
/// It is responsible for handling all business logic.
/// </summary>
public class SolutionManager : SolutionController {
/// <summary>
/// Creates a new solution with a containing project. Optionally,
/// all *.cs-files in the root directory and its containing subdirectories
/// are added to the project.
/// Raises a Changed-Event (Action.SolutionOpened)
/// </summary>
/// <param name="solution">The new blank solution</param>
/// <param name="addFiles">true, if all *.cs-files should be added</param>
public static void CreateNewSolution(Solution solution, bool addFiles) {
Project project = new Project(solution.Name, solution);
project.SetRelativeDirectory("");
project.OutputType = OutputType.WinExe;
solution.AddProject(project);
solution.StartProject = project;
if (addFiles) addFilesToProject(project.RootPath, project);
currentSolution = solution;
PerformChanged(Action.SolutionOpened, solution);
}
/// <summary>
/// Adds a new Project to the current Solution
/// </summary>
/// <param name="project">the new Project</param>
/// <param name="path">root path of the project</param>
/// <param name="addFiles">true, if all *.cs-files should be added</param>
public static void AddProject(Project project, string path, bool addFiles) {
currentSolution.AddProject(project);
PerformChanged(Action.ProjectAdded, project);
}
/// <summary>
/// Recursively adds all files with the extension *.cs in all subdirectories to the specified project
/// </summary>
/// <param name="path">the root path</param>
/// <param name="project"></param>
private static void addFilesToProject(string path, Project project) {
for (int i = 0; i < Directory.GetDirectories(path).Length; i++) {
addFilesToProject(Directory.GetDirectories(path)[i], project);
}
for (int i = 0; i < Directory.GetFiles(path, "*.cs").Length; i++) {
project.AddFile(Directory.GetFiles(path, "*.cs")[i]);
}
}
/// <summary>
/// First asks if the current solution should be stored (if necessary)
/// and then closes the solution.
/// Raises a Changed-Event (Action.SolutionClosed)
/// </summary>
public static void CloseCurrentSolution() {
AskForStore();
currentSolution = null;
PerformChanged(Action.SolutionClosed, null);
}
/// <summary>
/// Opens a solution. If previous counters are found, they are
/// imported on demand.
/// Raises a Changed-Event (SolutionOpened)
/// </summary>
/// <param name="solution">the solution that should be opened</param>
public static void OpenSolution(Solution solution) {
if (currentSolution != null) CloseCurrentSolution();
currentSolution = solution;
if (File.Exists(GetStorePath(solution))) {
Configuration.AddSolution(GetStorePath(solution));
} else {
System.Windows.Forms.MessageBox.Show("Could not open solution " + solution.Name);
return;
}
PerformChanged(Action.SolutionOpened, solution);
if ((Configuration.ImportCountersStrategy & ImportCounters.None) == 0) {
ProfilingResult sfc = CounterConverter.LoadCounters(CurrentSolution);
if (sfc != null && solution.CheckCounters(sfc)) {
ImportCounters strategy = ImportCounters.None;
sfc.CalculateStatisticalValues();
if ((Configuration.ImportCountersStrategy & ImportCounters.AskMe) != 0) {
ImportCountersDialog dialog = new ImportCountersDialog(sfc);
dialog.ShowDialog();
if (dialog.DialogResult == System.Windows.Forms.DialogResult.OK) {
if (!dialog.AskAgain) {
Configuration.ImportCountersStrategy = dialog.Strategy;
}
strategy = dialog.Strategy;
}
} else {
strategy = Configuration.ImportCountersStrategy;
}
if ((strategy & (ImportCounters.All | ImportCounters.Reset)) != 0) {
if ((Configuration.ImportCountersStrategy & ImportCounters.Reset) != 0) {
sfc.ResetCounters();
Console.WriteLine("Counters have been reset to 0.");
}
SolutionManager.ImportProfilingResults(sfc);
Console.WriteLine("Counters from " + sfc.LastModification.ToString() + " have been imported");
}
}
}
}
/// <summary>
/// Reads a solution from the specified file and calls OpenSolution(solution)
/// </summary>
/// <param name="path">the filename where the solution is stored</param>
public static void OpenSolution(string path) {
Solution solution = ReadSolution(path);
if (solution != null) {
OpenSolution(solution);
}
}
/// <summary>
/// Parses the whole solution
/// </summary>
/// <returns>true, if parsing was successful</returns>
public static bool ParseSolution() {
int filesWithErrors = 0;
DateTime time = System.DateTime.Now;
foreach (Project project in CurrentSolution.Projects) {
Console.WriteLine("[Prof-It] Parsing project '" + project.Name + "'");
foreach (SourceFile file in project.Files) {
if (ParseFile(file, false) == false) filesWithErrors++;
}
}
TimeSpan elapsedTime = System.DateTime.Now - time;
Console.WriteLine("[Prof-It] Parsing took " + elapsedTime.TotalSeconds + " seconds");
Console.WriteLine("[Prof-It] Found errors in " + filesWithErrors + " files.");
UpdateProfilingResult();
return filesWithErrors == 0;
}
/// <summary>
/// Parses the file, if hasn't already been parsed and the file
/// hasn't changed since it has been parsed the last time.
/// </summary>
/// <param name="file">the SourceFile to parse</param>
/// <param name="notify">true, if a Changed-Event should be raised</param>
/// <returns>true, if parsing was successful</returns>
public static bool ParseFile(SourceFile file, bool notify) {
if (!File.Exists(file.FileName)) {
Console.WriteLine(" Could not find + '" + file.FileName + "'");
return false;
}
if (file.Profile && file.IsParsingNecessary) {
CounterCollection counters = Parser.Parse(file.FileName);
if (Errors.count == 0) {
counters.LastParseTime = System.DateTime.Now;
counters.RemoveEmptyBlocks();
file.SetCounters(counters);
Console.WriteLine(" parsing " + FileUtility.ToShortFileName(file.FileName) + ". found " + file.Counters.blocks.Count + " blocks");
} else {
Console.WriteLine(" error(s) in " + FileUtility.ToShortFileName(file.FileName));
return false;
}
}
if (notify) {
UpdateProfilingResult(file);
}
return true;
}
/// <summary>
/// Builds the current solution, if any changes have been made
/// </summary>
/// <returns>true, if the build was successful</returns>
public static bool BuildSolution() {
if (ParseSolution() == false) return false;
return Compiler.Compile(CurrentSolution);
}
/// <summary>
/// Runs the current solution. If it is necessary, a new build is made.
/// </summary>
/// <param name="reloadBlocks">will be notified as soon as the counter file has been written</param>
/// <param name="processExited">will be notified as soon as the solution has stopped</param>
/// <returns>true, if solution has been started</returns>
public static bool RunSolution(EventHandler reloadBlocks, EventHandler processExited) {
if (BuildSolution()) {
if ((Configuration.ResetCountersStrategy & at.jku.ssw.ProfIt.ResetCounters.AskMe) != 0) {
if (CurrentSolution.GetLastProfilingResult() != null &&
CurrentSolution.GetLastProfilingResult().MaximumCounter > 0) {
DialogProvider.ShowResetCountersDialog();
}
}
if ((Configuration.ResetCountersStrategy & at.jku.ssw.ProfIt.ResetCounters.Always) != 0) {
ResetCounters();
}
if (CurrentSolution.AskForStartParameters && CurrentSolution.RequiresStartParameters()) {
DialogProvider.ShowStartParametersDialog();
}
ProcessStarter starter = new ProcessStarter();
starter.CounterFileChanged += reloadBlocks;
starter.ProcessExited += processExited;
starter.RunSolution(SolutionManager.CurrentSolution);
return true;
} else {
return false;
}
}
/// <summary>
/// If any changes have been made to the solution, a popup-window asks
/// the user if the changes should be stored to a file.
/// </summary>
public static void AskForStore() {
if (CurrentSolution == null) return;
StoreSolutionDialog dialog = new StoreSolutionDialog(GetStorePath(CurrentSolution));
if (CurrentSolution.Changed) {
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
StoreSolution();
}
}
}
/// <summary>
/// Stores the current solution to a file (XML)
/// </summary>
public static void StoreSolution() {
if (currentSolution != null) {
FileStream myStream = null;
try {
string path = GetStorePath(CurrentSolution);
myStream = File.Create(path);
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(myStream, CurrentSolution);
myStream.Close();
PerformChanged(Action.SolutionSaved, currentSolution);
Configuration.AddSolution(path);
} catch {
} finally {
if (myStream != null) myStream.Close();
}
}
}
/// <summary>
/// Raises a Changed-Event (RangedColorsChanged)
/// </summary>
public static void RangedColorsChanged() {
PerformChanged(Action.RangedColorsChanged, null);
}
/// <summary>
/// Reads a solution from a file (XML)
/// </summary>
/// <param name="fileName">the file where the solution has been stored</param>
/// <returns>null, if the solution could not be deserialized</returns>
public static Solution ReadSolution(string fileName) {
if (!File.Exists(fileName)) return null;
FileStream myStream = File.OpenRead(fileName);
SoapFormatter formatter = new SoapFormatter();
Solution solution = null;
try {
solution = (Solution)formatter.Deserialize(myStream);
} catch (Exception e) {
Console.WriteLine(e.StackTrace);
Console.WriteLine("Could not read solution in file '" + fileName + "'.");
Console.WriteLine("Maybe it has been created with an older version of Prof-It");
myStream.Close();
return null;
} finally {
myStream.Close();
}
if (solution != null) {
solution.RootPath = FileUtility.GetPath(fileName);
return solution;
} else return null;
}
/// <returns>the filename for the solution</returns>
internal static string GetStorePath(Solution solution) {
return FileUtility.FormatPath(solution.RootPath + "\\" + solution.Name + ".csps");
}
}
}
|