2014-02-17 16:35:24 -08:00
/ *
Copyright ( c ) 2014 , Lars Brubaker
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
1. Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies ,
either expressed or implied , of the FreeBSD Project .
* /
using System ;
2014-01-29 19:09:30 -08:00
using System.Collections ;
using System.Linq ;
using System.Text ;
using System.Xml ;
using System.Reflection ;
using System.IO ;
2014-12-03 15:29:11 -08:00
using System.IO.Compression ;
2014-01-29 19:09:30 -08:00
using System.Diagnostics ;
using System.Collections.Generic ;
2014-10-30 17:37:28 -07:00
using MatterHackers.PolygonMesh.Processors ;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg.UI ;
using MatterHackers.MatterControl.DataStorage ;
2014-10-11 14:48:10 -07:00
using MatterHackers.MatterControl.PrintQueue ;
2014-01-29 19:09:30 -08:00
using Newtonsoft.Json ;
using Newtonsoft.Json.Converters ;
using Newtonsoft.Json.Serialization ;
using Newtonsoft.Json.Utilities ;
namespace MatterHackers.MatterControl
{
class ManifestItem
{
public int ItemQuantity { get ; set ; }
public string Name { get ; set ; }
public string FileName { get ; set ; }
}
class Project
{
List < ManifestItem > projectFiles ;
string projectName = "Test Project" ;
string projectDateCreated ;
public Project ( )
{
DateTime now = DateTime . Now ;
projectDateCreated = now . ToString ( "s" ) ;
}
public List < ManifestItem > ProjectFiles
{
get
{
return projectFiles ;
}
set
{
projectFiles = value ;
}
}
public string ProjectName
{
get
{
return projectName ;
}
set
{
projectName = value ;
}
}
public string ProjectDateCreated
{
get
{
return projectDateCreated ;
}
set
{
projectDateCreated = value ;
}
}
}
class ProjectFileHandler
{
Project project ;
Dictionary < string , ManifestItem > sourceFiles = new Dictionary < string , ManifestItem > ( ) ;
HashSet < string > addedFileNames = new HashSet < string > ( ) ;
public ProjectFileHandler ( List < PrintItem > projectFiles )
{
if ( projectFiles ! = null )
{
project = new Project ( ) ;
foreach ( PrintItem item in projectFiles )
{
if ( sourceFiles . ContainsKey ( item . FileLocation ) )
{
sourceFiles [ item . FileLocation ] . ItemQuantity = sourceFiles [ item . FileLocation ] . ItemQuantity + 1 ;
}
else
{
string fileNameOnly = Path . GetFileName ( item . FileLocation ) ;
if ( addedFileNames . Contains ( fileNameOnly ) )
{
2014-10-21 21:20:09 -07:00
StyledMessageBox . ShowMessageBox ( null , string . Format ( "Duplicate file name found but in a different folder '{0}'. This part will not be added to the collection.\n\n{1}" , fileNameOnly , item . FileLocation ) , "Duplicate File" ) ;
2014-01-29 19:09:30 -08:00
continue ;
}
addedFileNames . Add ( fileNameOnly ) ;
ManifestItem manifestItem = new ManifestItem ( ) ;
manifestItem . ItemQuantity = 1 ;
manifestItem . Name = item . Name ;
manifestItem . FileName = Path . GetFileName ( item . FileLocation ) ;
sourceFiles . Add ( item . FileLocation , manifestItem ) ;
}
}
List < ManifestItem > manifestFiles = sourceFiles . Values . ToList ( ) ;
project . ProjectFiles = manifestFiles ;
}
}
//Opens Save file dialog and outputs current queue as a project
public void SaveAs ( )
{
2014-12-06 11:12:05 -08:00
SaveFileDialogParams saveParams = new SaveFileDialogParams ( "Save Project|*.zip" ) ;
2014-01-29 19:09:30 -08:00
2014-10-11 15:11:26 -07:00
FileDialog . SaveFileDialog ( saveParams , onSaveFileSelected ) ;
2014-01-29 19:09:30 -08:00
}
2014-10-11 15:11:26 -07:00
void onSaveFileSelected ( SaveFileDialogParams saveParams )
{
if ( saveParams . FileName ! = null )
{
ExportToProjectArchive ( saveParams . FileName ) ;
}
}
2014-01-29 19:09:30 -08:00
static string applicationDataPath = ApplicationDataStorage . Instance . ApplicationUserDataPath ;
2014-12-03 15:29:11 -08:00
static string archiveStagingFolder = Path . Combine ( applicationDataPath , "data" , "temp" , "project-assembly" ) ;
static string defaultManifestPathAndFileName = Path . Combine ( archiveStagingFolder , "manifest.json" ) ;
2014-04-15 18:13:27 -07:00
static string defaultProjectPathAndFileName = Path . Combine ( applicationDataPath , "data" , "default.zip" ) ;
2014-01-29 19:09:30 -08:00
public static void EmptyFolder ( System . IO . DirectoryInfo directory )
{
foreach ( System . IO . FileInfo file in directory . GetFiles ( ) ) file . Delete ( ) ;
foreach ( System . IO . DirectoryInfo subDirectory in directory . GetDirectories ( ) ) subDirectory . Delete ( true ) ;
}
public void ExportToProjectArchive ( string savedFileName = null )
{
if ( savedFileName = = null )
{
savedFileName = defaultProjectPathAndFileName ;
}
//If the temp folder doesn't exist - create it, otherwise clear it
2014-12-03 15:29:11 -08:00
if ( ! Directory . Exists ( archiveStagingFolder ) )
2014-01-29 19:09:30 -08:00
{
2014-12-03 15:29:11 -08:00
Directory . CreateDirectory ( archiveStagingFolder ) ;
2014-01-29 19:09:30 -08:00
}
else
{
2014-12-03 15:29:11 -08:00
System . IO . DirectoryInfo directory = new System . IO . DirectoryInfo ( @archiveStagingFolder ) ;
2014-01-29 19:09:30 -08:00
EmptyFolder ( directory ) ;
}
2015-02-09 19:26:37 -08:00
//Create and save the project manifest file into the temp directory
File . WriteAllText ( defaultManifestPathAndFileName , JsonConvert . SerializeObject ( this . project , Newtonsoft . Json . Formatting . Indented ) ) ;
2014-03-07 10:12:55 -08:00
2014-12-03 15:29:11 -08:00
foreach ( KeyValuePair < string , ManifestItem > item in this . sourceFiles )
{
CopyFileToTempFolder ( item . Key , item . Value . FileName ) ;
}
2015-02-09 19:26:37 -08:00
2015-02-10 10:56:56 -08:00
// Delete or move existing file out of the way as CreateFromDirectory will not overwrite and thows an exception
if ( File . Exists ( savedFileName ) )
{
try
{
File . Delete ( savedFileName ) ;
}
catch ( Exception ex )
{
string directory = Path . GetDirectoryName ( savedFileName ) ;
string fileName = Path . GetFileNameWithoutExtension ( savedFileName ) ;
string extension = Path . GetExtension ( savedFileName ) ;
string candidatePath ;
for ( int i = 1 ; i < 20 ; i + + )
{
candidatePath = Path . Combine ( directory , string . Format ( "{0}({1}){2}" , fileName , i , extension ) ) ;
if ( ! File . Exists ( candidatePath ) )
{
File . Move ( savedFileName , candidatePath ) ;
break ;
}
}
}
}
2015-02-09 19:26:37 -08:00
ZipFile . CreateFromDirectory ( archiveStagingFolder , savedFileName , CompressionLevel . Optimal , true ) ;
}
2014-03-07 10:12:55 -08:00
2014-12-03 15:29:11 -08:00
private static void CopyFileToTempFolder ( string sourceFile , string fileName )
2014-03-07 10:12:55 -08:00
{
if ( File . Exists ( sourceFile ) )
{
2014-12-03 15:29:11 -08:00
try
{
// Will not overwrite if the destination file already exists.
File . Copy ( sourceFile , Path . Combine ( archiveStagingFolder , fileName ) ) ;
}
2014-03-07 10:12:55 -08:00
2014-12-03 15:29:11 -08:00
// Catch exception if the file was already copied.
catch ( IOException copyError )
{
Console . WriteLine ( copyError . Message ) ;
}
2014-01-29 19:09:30 -08:00
}
}
2014-10-12 08:22:17 -07:00
public void OpenFromDialog ( )
2014-01-29 19:09:30 -08:00
{
OpenFileDialogParams openParams = new OpenFileDialogParams ( "Zip file|*.zip" ) ;
2014-10-11 14:48:10 -07:00
FileDialog . OpenFileDialog ( openParams , onProjectArchiveLoad ) ;
2014-01-29 19:09:30 -08:00
}
2014-10-11 14:48:10 -07:00
void onProjectArchiveLoad ( OpenFileDialogParams openParams )
{
List < PrintItem > partFiles ;
if ( openParams . FileNames ! = null )
{
string loadedFileName = openParams . FileName ;
partFiles = ImportFromProjectArchive ( loadedFileName ) ;
if ( partFiles ! = null )
{
foreach ( PrintItem part in partFiles )
{
QueueData . Instance . AddItem ( new PrintItemWrapper ( new PrintItem ( part . Name , part . FileLocation ) ) ) ;
}
}
}
}
2014-01-29 19:09:30 -08:00
public List < PrintItem > ImportFromProjectArchive ( string loadedFileName = null )
{
if ( loadedFileName = = null )
{
loadedFileName = defaultProjectPathAndFileName ;
}
if ( System . IO . File . Exists ( loadedFileName ) )
2014-03-07 10:12:55 -08:00
{
FileStream fs = File . OpenRead ( loadedFileName ) ;
2014-12-10 10:55:42 -08:00
ZipArchive zip = new ZipArchive ( fs ) ;
2014-01-29 19:09:30 -08:00
int projectHashCode = zip . GetHashCode ( ) ;
2014-12-10 10:55:42 -08:00
2014-01-29 19:09:30 -08:00
//If the temp folder doesn't exist - create it, otherwise clear it
string stagingFolder = Path . Combine ( applicationDataPath , "data" , "temp" , "project-extract" , projectHashCode . ToString ( ) ) ;
if ( ! Directory . Exists ( stagingFolder ) )
{
Directory . CreateDirectory ( stagingFolder ) ;
}
else
{
System . IO . DirectoryInfo directory = new System . IO . DirectoryInfo ( @stagingFolder ) ;
EmptyFolder ( directory ) ;
}
List < PrintItem > printItemList = new List < PrintItem > ( ) ;
Project projectManifest = null ;
2014-12-10 10:55:42 -08:00
foreach ( ZipArchiveEntry zipEntry in zip . Entries )
2014-03-07 10:12:55 -08:00
{
2014-10-30 17:37:28 -07:00
string sourceExtension = Path . GetExtension ( zipEntry . Name ) . ToUpper ( ) ;
2014-12-10 10:55:42 -08:00
// Note: directories have empty Name properties
//
// Only process ZipEntries that are:
// - not directories and
// - are in the ValidFileExtension list or
// - have a .GCODE extension or
// - are named manifest.json
if ( ! string . IsNullOrWhiteSpace ( zipEntry . Name ) & &
( zipEntry . Name = = "manifest.json"
2014-10-30 17:37:28 -07:00
| | MeshFileIo . ValidFileExtensions ( ) . Contains ( sourceExtension )
2014-12-10 10:55:42 -08:00
| | sourceExtension = = ".GCODE" ) )
2014-01-29 19:09:30 -08:00
{
2014-12-10 10:55:42 -08:00
string extractedFileName = Path . Combine ( stagingFolder , zipEntry . Name ) ;
2014-12-06 11:38:35 -08:00
2014-12-10 10:55:42 -08:00
string neededPathForZip = Path . GetDirectoryName ( extractedFileName ) ;
if ( ! Directory . Exists ( neededPathForZip ) )
{
Directory . CreateDirectory ( neededPathForZip ) ;
}
2014-12-06 11:38:35 -08:00
2014-12-10 10:55:42 -08:00
using ( Stream zipStream = zipEntry . Open ( ) )
using ( FileStream streamWriter = File . Create ( extractedFileName ) )
{
zipStream . CopyTo ( streamWriter ) ;
}
2014-12-06 11:38:35 -08:00
2014-12-10 10:55:42 -08:00
if ( zipEntry . Name = = "manifest.json" )
{
using ( StreamReader sr = new System . IO . StreamReader ( extractedFileName ) )
2014-12-06 11:38:35 -08:00
{
projectManifest = ( Project ) Newtonsoft . Json . JsonConvert . DeserializeObject ( sr . ReadToEnd ( ) , typeof ( Project ) ) ;
}
2014-03-07 10:12:55 -08:00
}
2014-01-29 19:09:30 -08:00
}
}
if ( projectManifest ! = null )
{
foreach ( ManifestItem item in projectManifest . ProjectFiles )
{
for ( int i = 1 ; i < = item . ItemQuantity ; i + + )
{
printItemList . Add ( this . GetPrintItemFromFile ( Path . Combine ( stagingFolder , item . FileName ) , item . Name ) ) ;
}
}
}
else
{
string [ ] files = Directory . GetFiles ( stagingFolder , "*.*" , SearchOption . AllDirectories ) ;
foreach ( string fileName in files )
{
printItemList . Add ( this . GetPrintItemFromFile ( fileName , Path . GetFileNameWithoutExtension ( fileName ) ) ) ;
}
}
return printItemList ;
}
else
{
return null ;
}
}
private PrintItem GetPrintItemFromFile ( string fileName , string displayName )
{
PrintItem item = new PrintItem ( ) ;
item . FileLocation = fileName ;
item . Name = displayName ;
return item ;
}
}
}