703 lines
20 KiB
C#
703 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Data.Common;
|
|
using System.Diagnostics;
|
|
using System.ComponentModel;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
|
|
using MatterHackers.VectorMath;
|
|
|
|
namespace MatterHackers.MatterControl.DataStorage
|
|
{
|
|
public class ApplicationDataStorage
|
|
{
|
|
//Describes the location for storing all local application data
|
|
static ApplicationDataStorage globalInstance;
|
|
string applicationPath;
|
|
readonly string datastoreName = "MatterControl.db";
|
|
readonly string applicationDataFolderName = "MatterControl";
|
|
|
|
public ApplicationDataStorage()
|
|
//Constructor - validates that local storage folder exists, creates if necessary
|
|
{
|
|
DirectoryInfo dir = new DirectoryInfo(ApplicationUserDataPath);
|
|
if (!dir.Exists)
|
|
{
|
|
dir.Create();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a global instance of ApplicationDataStorage
|
|
/// </summary>
|
|
public static ApplicationDataStorage Instance
|
|
{
|
|
get
|
|
{
|
|
if (globalInstance == null)
|
|
{
|
|
globalInstance = new ApplicationDataStorage();
|
|
}
|
|
return globalInstance;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns the application user data folder
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string ApplicationUserDataPath
|
|
{
|
|
get
|
|
{
|
|
return Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), applicationDataFolderName);
|
|
}
|
|
}
|
|
|
|
public string ApplicationLibraryDataPath
|
|
{
|
|
get
|
|
{
|
|
|
|
string libraryPath = Path.Combine(ApplicationDataStorage.Instance.ApplicationUserDataPath, "Library");
|
|
|
|
//Create library path if it doesn't exist
|
|
DirectoryInfo dir = new DirectoryInfo(libraryPath);
|
|
if (!dir.Exists)
|
|
{
|
|
dir.Create();
|
|
}
|
|
return libraryPath;
|
|
}
|
|
}
|
|
|
|
public string ApplicationPath
|
|
{
|
|
get
|
|
{
|
|
if (this.applicationPath == null)
|
|
{
|
|
applicationPath = System.IO.Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly ().Location);
|
|
}
|
|
return applicationPath;
|
|
}
|
|
|
|
}
|
|
|
|
public string ApplicationStaticDataPath
|
|
{
|
|
get
|
|
{
|
|
switch (MatterHackers.Agg.UI.WindowsFormsAbstract.GetOSType())
|
|
{
|
|
case Agg.UI.WindowsFormsAbstract.OSType.Windows:
|
|
if (Directory.Exists("StaticData"))
|
|
{
|
|
return "StaticData";
|
|
}
|
|
else
|
|
{
|
|
return Path.Combine("..", "..", "StaticData");
|
|
}
|
|
|
|
case Agg.UI.WindowsFormsAbstract.OSType.Mac:
|
|
if (Directory.Exists("StaticData"))
|
|
{
|
|
return "StaticData";
|
|
}
|
|
else if(Directory.Exists(Path.Combine(ApplicationPath, "StaticData")))
|
|
{
|
|
return Path.Combine(ApplicationPath, "StaticData");
|
|
}
|
|
else
|
|
{
|
|
return Path.Combine("..", "..", "StaticData");
|
|
}
|
|
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the gcode output folder
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GCodeOutputPath
|
|
{
|
|
get
|
|
{
|
|
string gcodeOutputPath = Path.Combine(ApplicationUserDataPath, "data", "gcode");
|
|
if (!Directory.Exists(gcodeOutputPath))
|
|
{
|
|
Directory.CreateDirectory(gcodeOutputPath);
|
|
}
|
|
return gcodeOutputPath;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns the path to the sqlite database
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string DatastorePath
|
|
{
|
|
get { return System.IO.Path.Combine(ApplicationUserDataPath, datastoreName); }
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return base.ToString();
|
|
}
|
|
}
|
|
|
|
class Datastore
|
|
{
|
|
bool TEST_FLAG = false;
|
|
static Datastore globalInstance;
|
|
static string datastoreLocation = ApplicationDataStorage.Instance.DatastorePath;
|
|
public bool ConnectionError = false;
|
|
List<Type> dataStoreTables = new List<Type> { typeof(PrintItemCollection), typeof(CustomCommands), typeof(SystemSetting), typeof(UserSetting), typeof(ApplicationSession), typeof(PrintItem), typeof(PrintTask), typeof(Printer), typeof(SliceSetting), typeof(SliceSettingsCollection) };
|
|
ApplicationSession activeSession;
|
|
public ISQLite dbSQLite;
|
|
|
|
public static Datastore Instance
|
|
{
|
|
get
|
|
{
|
|
if (globalInstance == null)
|
|
{
|
|
globalInstance = new Datastore();
|
|
}
|
|
return globalInstance;
|
|
}
|
|
}
|
|
|
|
public Datastore()
|
|
{
|
|
if (TEST_FLAG)
|
|
{
|
|
//In test mode - attempt to delete the database entirely
|
|
if (File.Exists(datastoreLocation))
|
|
{
|
|
try
|
|
{
|
|
File.Delete(datastoreLocation);
|
|
}
|
|
catch (IOException)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (MatterHackers.Agg.UI.WindowsFormsAbstract.GetOSType())
|
|
{
|
|
case Agg.UI.WindowsFormsAbstract.OSType.Windows:
|
|
dbSQLite = new SQLiteWin32.SQLiteConnection(datastoreLocation);
|
|
break;
|
|
|
|
case Agg.UI.WindowsFormsAbstract.OSType.Mac:
|
|
dbSQLite = new SQLiteUnix.SQLiteConnection(datastoreLocation);
|
|
break;
|
|
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
if (TEST_FLAG)
|
|
{
|
|
//In test mode - attempt to drop all tables (in case db was locked when we tried to delete it)
|
|
foreach (Type table in dataStoreTables)
|
|
{
|
|
try
|
|
{
|
|
this.dbSQLite.DropTable(table);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug.WriteLine(datastoreLocation);
|
|
}
|
|
|
|
public int RecordCount(string tableName)
|
|
{
|
|
string query = string.Format("SELECT COUNT(*) FROM {0};", tableName);
|
|
string result = Datastore.Instance.dbSQLite.ExecuteScalar<string>(query);
|
|
return Convert.ToInt32(result);
|
|
}
|
|
|
|
public void Initialize()
|
|
//Run initial checks and operations on sqlite datastore
|
|
{
|
|
|
|
if (TEST_FLAG)
|
|
{
|
|
ValidateSchema();
|
|
GenerateSampleData sampleData = new GenerateSampleData();
|
|
}
|
|
else
|
|
{
|
|
ValidateSchema();
|
|
}
|
|
StartSession();
|
|
}
|
|
|
|
void StartSession()
|
|
//Begins new application session record
|
|
{
|
|
activeSession = new ApplicationSession();
|
|
dbSQLite.Insert(activeSession);
|
|
}
|
|
|
|
void ValidateSchema()
|
|
// Checks if the datastore contains the appropriate tables - adds them if necessary
|
|
{
|
|
foreach (Type table in dataStoreTables)
|
|
{
|
|
|
|
dbSQLite.CreateTable(table);
|
|
|
|
//string query = string.Format("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='{0}';", table.Name);
|
|
////SQLiteCommand command = dbSQLite.CreateCommand(query);
|
|
|
|
//int RowCount = 0;
|
|
//string result = dbSQLite.ExecuteScalar<string>(query);
|
|
//RowCount = Convert.ToInt32(result);
|
|
//if (RowCount == 0)
|
|
//{
|
|
// dbSQLite.CreateTable(table);
|
|
//}
|
|
|
|
}
|
|
}
|
|
|
|
public void Exit()
|
|
{
|
|
this.activeSession.SessionEnd = DateTime.Now;
|
|
this.activeSession.Commit();
|
|
// lets wait a bit to make sure the commit has resolved.
|
|
Thread.Sleep(100);
|
|
try
|
|
{
|
|
dbSQLite.Close();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// we faild to close so lets wait a bit and try again
|
|
Thread.Sleep(1000);
|
|
try
|
|
{
|
|
dbSQLite.Close();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Entity
|
|
{
|
|
[PrimaryKey, AutoIncrement]
|
|
public int Id { get; set; }
|
|
|
|
protected bool isSaved;
|
|
protected int hashCode = 0;
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
IEnumerable<PropertyInfo> properties;
|
|
|
|
|
|
public Entity()
|
|
{
|
|
isSaved = false;
|
|
}
|
|
|
|
private void TryHandleInsert()
|
|
{
|
|
try
|
|
{
|
|
Datastore.Instance.dbSQLite.Insert(this);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
this.TryHandleInsert();
|
|
}
|
|
}
|
|
|
|
private void TryHandleUpdate()
|
|
{
|
|
try
|
|
{
|
|
Datastore.Instance.dbSQLite.Update(this);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
this.TryHandleUpdate();
|
|
}
|
|
}
|
|
|
|
public virtual void Commit()
|
|
{
|
|
//Assumes that autoincremented ids start with 1
|
|
if (this.Id == 0)
|
|
{
|
|
TryHandleInsert();
|
|
}
|
|
else
|
|
{
|
|
TryHandleUpdate();
|
|
}
|
|
}
|
|
|
|
public void Delete()
|
|
{
|
|
Datastore.Instance.dbSQLite.Delete(this);
|
|
}
|
|
|
|
protected void OnPropertyChanged(string name)
|
|
{
|
|
PropertyChangedEventHandler handler = PropertyChanged;
|
|
this.hashCode = 0;
|
|
if (handler != null)
|
|
{
|
|
handler(this, new PropertyChangedEventArgs(name));
|
|
}
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
StringBuilder bigStringForHashCode = new StringBuilder();
|
|
|
|
if (this.hashCode == 0)
|
|
{
|
|
properties = this.GetType()
|
|
.GetProperties(BindingFlags.Instance |
|
|
BindingFlags.Public)
|
|
// Ignore non-string properties
|
|
.Where(prop => prop.PropertyType == typeof(string) || prop.PropertyType == typeof(int))
|
|
// Ignore indexers
|
|
.Where(prop => prop.GetIndexParameters().Length == 0)
|
|
// Must be both readable and writable
|
|
.Where(prop => prop.CanWrite && prop.CanRead);
|
|
|
|
foreach (PropertyInfo prop in properties)
|
|
{
|
|
object objectHoldingValue = prop.GetValue(this, null);
|
|
if (objectHoldingValue != null)
|
|
{
|
|
string value = objectHoldingValue.ToString();
|
|
if (value != null)
|
|
{
|
|
bigStringForHashCode.Append(prop.Name);
|
|
bigStringForHashCode.Append(value);
|
|
}
|
|
}
|
|
}
|
|
this.hashCode = bigStringForHashCode.ToString().GetHashCode();
|
|
}
|
|
|
|
return this.hashCode;
|
|
}
|
|
}
|
|
|
|
public class ApplicationSession : Entity
|
|
{
|
|
public DateTime SessionStart { get; set; }
|
|
public DateTime SessionEnd { get; set; }
|
|
public int PrintCount { get; set; }
|
|
|
|
public ApplicationSession()
|
|
:base ()
|
|
{
|
|
SessionStart = DateTime.Now;
|
|
PrintCount = 0;
|
|
}
|
|
}
|
|
|
|
public class PrintItemCollection : Entity
|
|
{
|
|
public string Name { get; set; }
|
|
}
|
|
|
|
public class PrintItem : Entity
|
|
{
|
|
[Indexed]
|
|
public int PrintItemCollectionID { get; set; }
|
|
public string Name { get; set; }
|
|
public string FileLocation { get; set; }
|
|
public DateTime DateAdded { get; set; }
|
|
public int PrintCount { get; set; }
|
|
|
|
public PrintItem()
|
|
: this("", "")
|
|
{
|
|
}
|
|
|
|
public PrintItem(string name, string fileLocation)
|
|
{
|
|
this.Name = name;
|
|
this.FileLocation = fileLocation;
|
|
|
|
DateAdded = DateTime.Now;
|
|
PrintCount = 0;
|
|
}
|
|
}
|
|
|
|
public class SliceSettingsCollection : Entity
|
|
{
|
|
public string Name { get; set; }
|
|
|
|
// and the list of IDs
|
|
}
|
|
|
|
public class SliceSetting : Entity
|
|
{
|
|
[Indexed]
|
|
public int SettingsCollectionId { get; set; }
|
|
public string Name { get; set; }
|
|
public string Value { get; set; }
|
|
|
|
public SliceSetting()
|
|
: base()
|
|
{
|
|
}
|
|
}
|
|
|
|
public class PrintTask : Entity
|
|
{
|
|
[Indexed]
|
|
public int PrinterId { get; set; }
|
|
[Indexed]
|
|
public int PrintItemId { get; set; }
|
|
public DateTime PrintStart { get; set; }
|
|
public DateTime PrintEnd { get; set; }
|
|
public bool PrintComplete { get; set; }
|
|
|
|
public PrintTask()
|
|
: base()
|
|
{
|
|
PrintStart = DateTime.Now;
|
|
}
|
|
}
|
|
|
|
public class SystemSetting : Entity
|
|
{
|
|
[Indexed]
|
|
public string Name { get; set; }
|
|
public string Value { get; set; }
|
|
public DateTime DateLastModified { get; set; }
|
|
|
|
public override void Commit()
|
|
{
|
|
DateLastModified = DateTime.Now;
|
|
base.Commit();
|
|
}
|
|
}
|
|
|
|
public class UserSetting : Entity
|
|
{
|
|
[Indexed]
|
|
public string Name { get; set; }
|
|
public string Value { get; set; }
|
|
public DateTime DateLastModified { get; set; }
|
|
|
|
public override void Commit()
|
|
{
|
|
DateLastModified = DateTime.Now;
|
|
base.Commit();
|
|
}
|
|
}
|
|
|
|
public class CustomCommands : Entity
|
|
{
|
|
[Indexed]
|
|
public int PrinterId { get; set; }
|
|
public string Name { get; set; }
|
|
public string Value { get; set; }
|
|
public DateTime DateLastModified { get; set; }
|
|
|
|
public override void Commit()
|
|
{
|
|
DateLastModified = DateTime.Now;
|
|
base.Commit();
|
|
}
|
|
}
|
|
|
|
public class PrinterFeaturs
|
|
{
|
|
Dictionary<string, string> features = new Dictionary<string, string>();
|
|
public PrinterFeaturs(string features)
|
|
{
|
|
if (features != null)
|
|
{
|
|
string[] featuresArray = features.Split(',');
|
|
for (int i = 0; i < features.Length / 2; i++)
|
|
{
|
|
this.features.Add(featuresArray[i * 2], featuresArray[i * 2 + 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public string GetFeatuersString()
|
|
{
|
|
StringBuilder output = new StringBuilder();
|
|
|
|
bool first = true;
|
|
foreach(KeyValuePair<string, string> feature in features)
|
|
{
|
|
if (!first)
|
|
{
|
|
output.Append(",");
|
|
}
|
|
output.Append(feature.Key + "," + feature.Value);
|
|
first = false;
|
|
}
|
|
|
|
return output.ToString();
|
|
}
|
|
|
|
public bool HasFan()
|
|
{
|
|
if(features.ContainsKey("HasFan"))
|
|
{
|
|
return features["HasFan"] == "true";
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool HasSdCard()
|
|
{
|
|
if (features.ContainsKey("HasSdCard"))
|
|
{
|
|
return features["HasSdCard"] == "true";
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool HasHeatedBed()
|
|
{
|
|
if (features.ContainsKey("HasHeatedBed"))
|
|
{
|
|
return features["HasHeatedBed"] == "true";
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public int ExtruderCount()
|
|
{
|
|
if (features.ContainsKey("ExtruderCount"))
|
|
{
|
|
return int.Parse(features["ExtruderCount"]);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
public class Printer : Entity
|
|
{
|
|
public int DefaultSettingsCollectionId { get; set; }
|
|
public string Name { get; set; }
|
|
public string Make { get; set; }
|
|
public string Model { get; set; }
|
|
public string ComPort { get; set; }
|
|
public string BaudRate { get; set; }
|
|
public bool AutoConnectFlag { get; set; } //Auto connect to printer (if available)
|
|
public bool DoPrintLeveling { get; set; }
|
|
|
|
// features
|
|
public string _features { get; set; }
|
|
|
|
public string ManualMovementSpeeds { get; set; } // stored x,y,z,e1,e2,e3,...
|
|
|
|
public string CurrentSlicingEngine { get; set; }
|
|
|
|
/// <summary>
|
|
/// This stores the 3 bed probed positions as a string. 3 * (x, y, z) = 9 values.
|
|
/// </summary>
|
|
public string PrintLevelingProbePositions { get; set; }
|
|
|
|
protected PrinterFeaturs printerFeatures;
|
|
public PrinterFeaturs GetFeatures()
|
|
{
|
|
if (printerFeatures == null)
|
|
{
|
|
printerFeatures = new PrinterFeaturs(_features);
|
|
}
|
|
|
|
return printerFeatures;
|
|
}
|
|
|
|
public override void Commit()
|
|
{
|
|
if (printerFeatures != null)
|
|
{
|
|
_features = printerFeatures.GetFeatuersString();
|
|
}
|
|
|
|
base.Commit();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the 9 {3 * (x, y, z)} positions that were probed during the print leveling setup.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public double[] GetPrintLevelingPositions()
|
|
{
|
|
double[] positions = new double[9];
|
|
|
|
if (PrintLevelingProbePositions != null)
|
|
{
|
|
string[] lines = PrintLevelingProbePositions.Split(',');
|
|
if (lines.Length == 9)
|
|
{
|
|
for (int i = 0; i < 9; i++)
|
|
{
|
|
positions[i] = double.Parse(lines[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return positions;
|
|
}
|
|
|
|
public void SetPrintLevelingPositions(double[] printLevelingPositions3_xyz)
|
|
{
|
|
StringBuilder allValues = new StringBuilder();
|
|
bool first = true;
|
|
foreach(double position in printLevelingPositions3_xyz)
|
|
{
|
|
if(!first)
|
|
{
|
|
allValues.Append(",");
|
|
}
|
|
allValues.Append(position);
|
|
first = false;
|
|
}
|
|
|
|
PrintLevelingProbePositions = allValues.ToString();
|
|
}
|
|
|
|
public Printer()
|
|
: base()
|
|
{
|
|
this.Make = "Unknown";
|
|
this.Model = "Unknown";
|
|
}
|
|
}
|
|
}
|
|
|
|
|