Programming     Travel Logs     Life Is Good     Surfing Online     About Me
Labor means people working for you. It’s the oldest and most fought-over form of leverage. Labor leverage will impress your parents, but don’t waste your life chasing it.
-Naval Ravikant
2018-05-03 20:27:11

Copy this link when reproducing:
http://www.casperlee.com/en/y/blog/49

Since we have got ready the key class CFileHandler, the left work to do will be pretty much straightforward.

Before doing that, since I've been sticking to the "Supergirl" (a US TV series) recently, let's admire some photos first.

/Images/20161205/03.jpg

/Images/20161205/04.jpg

/Images/20161205/05.jpg

/Images/20161205/06.jpg

 

Ok, let's start.

I suddenly realized that I may need a feature which allows to import documents in batch, so let's make a little change to the AddResource form (in the main project) first.

/Images/20161205/00.jpg

Right next to the "Type" combobox, add a checkbox and named it "cbBatch".

 

To make the source code more flexible, I decided to introduce a new group of classes: ResourceHandler and FulltextResourceHandler (both of them are in the Bll project).

Here is the class diagram.

/Images/20161205/01.jpg

The FulltextResourceHandler class is inherited from the ResourceHandler class, and the ResourceBll holds an instance of ResourceHandler. I'll implement the fulltext search feature later, so I just created the class hierarchy here and keep the FulltextResourceHandler class the same behavior as its parent's.

Here is the code of the ResourceHandler class.

using System;
using System.Collections.Generic;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.IO;
using com.casperlee.Library;
using com.casperlee.ResourceManager.Dal;

namespace com.casperlee.ResourceManager.Bll
{
public class ResourceHandler
{
public class ResourceHandleEventArgs : EventArgs
{
private int progress;
public int Progress { get { return progress; } }

private int maximum;
public int Maximum { get { return maximum; } }

private string message;
public string Message { get { return message; } }

public ResourceHandleEventArgs(int aProgress,
int aMaximum, string aMessage)
{
this.progress = aProgress;
this.maximum = aMaximum;
this.message = aMessage;
}
}

public delegate void ResourceHandleEventDelegate(object sender, ResourceHandleEventArgs e);

public event ResourceHandleEventDelegate ResourceHandleEvent;

protected void OnResourceHandleEvent(ResourceHandleEventArgs e)
{
if (ResourceHandleEvent != null)
{
ResourceHandleEvent(this, e);
}
}

public void RaiseResourceHandleEvent(int aProgress,
int aMaximum, string aMessage)
{
ResourceHandleEventArgs e = new ResourceHandleEventArgs(
aProgress,
aMaximum,
aMessage);
OnResourceHandleEvent(e);
}
public enum FileHandleTypeEnum { fhtNone, fhtImport, fhtExport, fhtSearch};

private void OnResourceFileHandleEvent(
object sender,
CFileHandler.FileHandleEventArgs e,
FileHandleTypeEnum aFileHandleType)
{
string processName = "Unknown";
switch (aFileHandleType)
{
case FileHandleTypeEnum.fhtImport:
{
processName = "Importing";
break;
}
case FileHandleTypeEnum.fhtExport:
{
processName = "Exporting";
break;
}
case FileHandleTypeEnum.fhtSearch:
{
processName = "Searching";
break;
}
}
switch (e.WorkingState)
{
case CFileHandler.WorkingStateEnum.wsBegin:
{
RaiseResourceHandleEvent(
e.Handled,
e.Total,
processName + " process started.");
break;
}
case CFileHandler.WorkingStateEnum.wsEnd:
{
RaiseResourceHandleEvent(
e.Handled,
e.Total,
processName + " process stopped.");
break;
}
case CFileHandler.WorkingStateEnum.wsInprogress:
{
RaiseResourceHandleEvent(
e.Handled,
e.Total,
processName + " process is on progress...");
break;
}
default:
{
break;
}
}
}

private void Resource_FileImportEvent(object sender,
CFileHandler.FileHandleEventArgs e)
{
OnResourceFileHandleEvent(sender, e, FileHandleTypeEnum.fhtImport);
}

private void Resource_FileExportEvent(object sender,
CFileHandler.FileHandleEventArgs e)
{
OnResourceFileHandleEvent(sender, e, FileHandleTypeEnum.fhtExport);
}
public virtual void AddResource(ResourceEx aResource)
{
if (aResource.EntityType != ResourceEntityType.retRaw)
{
throw new CException(CException.EXP_WILL_NOT_HAPPEN, "aResource.EntityType != ResourceEntityType.retRaw");
}

if ((string.IsNullOrEmpty(aResource.Name))
|| (!File.Exists(aResource.FileName))
|| (aResource.ResourceTypeID <= 0))
{
throw new CException(CException.EXP_WILL_NOT_HAPPEN, "The information is not enough!");
}

Resource r = new Resource();
aResource.CopyTo(r);
using (ResourceManageEntities rme = new ResourceManageEntities())
{
rme.Resources.Add(r);

rme.SaveChanges();

r.Password = CEncoding.GetMD5String(aResource.Password + r.ID.ToString());
r.Keywords = CEncoding.Encode3Des(r.Keywords, aResource.Password);
r.Name = CEncoding.Encode3Des(r.Name, aResource.Password);

r.FileName = CEnvironment.GetNewFileName();

CFileHandler.Instance.FileHandleEvent += Resource_FileImportEvent;
try
{
CFileHandler.Instance.EncryptFile(
aResource.FileName,
r.FileName,
aResource.Password);
}
finally
{
CFileHandler.Instance.FileHandleEvent -= Resource_FileImportEvent;
}

try
{
rme.SaveChanges();
}
catch (DbEntityValidationException ex)
{
foreach (var validationErrors in ex.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}",
validationError.PropertyName,
validationError.ErrorMessage);
}
}
}
}
}
}
}

Here is the code of the FulltextResourceHandler class.

using System.Collections.Generic;

namespace com.casperlee.ResourceManager.Bll
{
public class FulltextResourceHandler: ResourceHandler
{
public override void AddResource(ResourceEx aResource)
{
base.AddResource(aResource);
}
}
}

 

These 2 classes will use an enhanced class "ResourceEx" instead of the auto created class "Resource". Here is the source code of the ResourceEx class in the Bll project.

using com.casperlee.ResourceManager.Dal;
using com.casperlee.Library;

namespace com.casperlee.ResourceManager.Bll
{
public class ResourceEx: Resource
{
public ResourceEx()
{
EntityType = ResourceEntityType.retNone;
Encrypted = false;
}
public ResourceEntityType EntityType { get; set; }

public bool Encrypted { get; set; }

public ResourceTypeEx ResourceTypeEx { get; set; }
public void CopyFrom(Resource aResource)
{
this.ID = aResource.ID;
this.FileName = aResource.FileName;
this.Keywords = aResource.Keywords;
this.Name = aResource.Name;
this.Password = aResource.Password;
this.ResourceTypeID = aResource.ResourceTypeID;
this.ResourceType = aResource.ResourceType;
if (this.ResourceTypeEx == null)
{
this.ResourceTypeEx = new ResourceTypeEx();
}

this.ResourceTypeEx.CopyFrom(aResource.ResourceType);
}

public void CopyTo(Resource aResource)
{
aResource.ID = this.ID;
aResource.FileName = this.FileName;
aResource.Keywords = this.Keywords;
aResource.Name = this.Name;
aResource.Password = this.Password;
aResource.ResourceTypeID = this.ResourceTypeID;
}

public void Encrypt(string aPassword)
{
if (this.Encrypted)
{
throw new CException(CException.EXP_WILL_NOT_HAPPEN,
"The resource has been encrypted.");
}

this.Password = CEncoding.GetMD5String(aPassword + this.ID.ToString());
this.Keywords = CEncoding.Encode3Des(this.Keywords, aPassword);
this.Name = CEncoding.Encode3Des(this.Name, aPassword);
this.Encrypted = true;
}

public void Decrypt(string aPassword)
{
if (!this.Encrypted)
{
throw new CException(CException.EXP_WILL_NOT_HAPPEN,
"The resource has not been encrypted yet.");
}

this.Keywords = CEncoding.Decode3Des(this.Keywords, aPassword);
this.Name = CEncoding.Decode3Des(this.Name, aPassword);
this.Encrypted = false;
}
}
}

Here is the source code of the ResourceEntityType enum which is used by the ResourceEx class.

namespace com.casperlee.ResourceManager.Bll
{
public enum ResourceEntityType
{
retNone,
retRaw,
retDB
}
}

Besides these classes, we need to add 2 properties and 1 function to the CEnvironment class in the Bll project.

        public static string BinPath
{
get
{
return Environment.CurrentDirectory;
}
}

public static string DataPath
{
get
{
return Path.Combine(BinPath, "Data");
}
}

public static string GetNewFileName()
{
string[] subPaths = {DataPath,
DateTime.Now.Year.ToString(),
DateTime.Now.Month.ToString("D2"),
Guid.NewGuid().ToString()};
string fileName = Path.Combine(subPaths);
string folder = Path.GetDirectoryName(fileName);
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}

while (File.Exists(fileName))
{
fileName += "_1";
}

return fileName;
}

Here is the source code of the ResourceBll class in the Bll project.

using System.Collections.Generic;

namespace com.casperlee.ResourceManager.Bll
{
public class ResourceBll
{
private static ResourceBll instance;

private ResourceBll()
{
}

public static ResourceBll Instance
{
get
{
if (instance == null)
{
instance = new ResourceBll();
}

return instance;
}
}
private void CreateHandler(bool aSupportFulltextSearch)
{
if ((handler == null)
|| (handler is FulltextResourceHandler != aSupportFulltextSearch))
{
handler = aSupportFulltextSearch ?
new FulltextResourceHandler() : new ResourceHandler();
}
}
public void AddResource(
ResourceEx aResource,
bool aSupportFulltextSearch,
ResourceHandler.ResourceHandleEventDelegate aHandler)
{
CreateHandler(aSupportFulltextSearch);
handler.ResourceHandleEvent += aHandler;
try
{
handler.AddResource(aResource);
}
finally
{
handler.ResourceHandleEvent -= aHandler;
}
}

public void AddResource(
ResourceEx aResource,
ResourceHandler.ResourceHandleEventDelegate aHandler)
{
AddResource(aResource, false, aHandler);
}

public void DelResource(int aResourceID)
{
throw new System.NotImplementedException();
}

public void ExportResource(int aResourceID)
{
throw new System.NotImplementedException();
}

private ResourceHandler handler;

public ResourceHandler Handler
{
get
{
return handler;
}
}
}
}

Here is the source code in the AddResource form.

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using com.casperlee.ResourceManager.Bll;

namespace com.casperlee.ResourceManager
{
public partial class frmAddResource : Form
{
public frmAddResource()
{
InitializeComponent();
this.selectedResourceFiles = new List<string>();
this.selectedResourceNames = new List<string>();
}
private List<string> selectedResourceFiles;

private List<string> selectedResourceNames;
private bool ValidateInput()
{
if (cbBatch.Checked)
{
if ((this.selectedResourceFiles.Count <= 0)
|| (this.selectedResourceNames.Count <= 0))
{
MessageBox.Show(this, "Please at least select a file!");
return false;
}
}
else
{
if ((!File.Exists(tbFile.Text)
|| (string.IsNullOrEmpty(tbName.Text))))
{
MessageBox.Show(this, "Please offer at least the Name and specify a file!");
return false;
}
}

return true;
}

private ResourceEx ReadFromUI()
{
ResourceEx r = new ResourceEx();
r.FileName = tbFile.Text;
r.Keywords = tbKeywords.Text;
r.Name = tbName.Text;
r.Password = tbPassword.Text;
r.ResourceTypeID = ((ResourceTypeEx)cbType.SelectedItem).ID;
r.EntityType = ResourceEntityType.retRaw;
return r;
}

private ResourceEx ReadFromUI(int aFileIndex)
{
ResourceEx r = new ResourceEx();
r.FileName = this.selectedResourceFiles[aFileIndex];
r.Keywords = tbKeywords.Text;
r.Name = this.selectedResourceNames[aFileIndex];
r.Password = tbPassword.Text;
r.ResourceTypeID = ((ResourceTypeEx)cbType.SelectedItem).ID;
r.EntityType = ResourceEntityType.retRaw;
return r;
}

private void InitializeResourceTypes()
{
cbType.Items.Clear();
List<ResourceTypeEx> items = new List<ResourceTypeEx>();
ResourceTypeBll.QueryAll(items);
foreach (ResourceTypeEx rte in items)
{
cbType.Items.Add(rte);
}

if (cbType.Items.Count > 0)
{
cbType.SelectedIndex = 0;
}
}
private void ResourceBll_ResourceHandle(
object sender,
ResourceHandler.ResourceHandleEventArgs e)
{
}

private void btnOk_Click(object sender, EventArgs e)
{
if (!ValidateInput())
{
return;
}

if (cbBatch.Checked)
{
for (int i = 0; i < this.selectedResourceFiles.Count; i++)
{
ResourceEx r = ReadFromUI(i);
ResourceBll.Instance.AddResource(r, ResourceBll_ResourceHandle);
}
}
else
{
ResourceEx r = ReadFromUI();
ResourceBll.Instance.AddResource(r, ResourceBll_ResourceHandle);
}

MessageBox.Show(this, "Done!");
Close();
}

private void frmAddResource_Load(object sender, EventArgs e)
{
InitializeResourceTypes();
tbPassword.Text = CEnvironment.CurrentPassword;
}

private void btnSelectFile_Click(object sender, EventArgs e)
{
OpenFileDialog fd = new OpenFileDialog();
fd.Multiselect = cbBatch.Checked;
if (fd.ShowDialog(this) == DialogResult.OK)
{
if (!fd.Multiselect)
{
tbFile.Text = fd.FileName;
tbName.Text = Path.GetFileName(tbFile.Text);
}
else
{
tbFile.Text = string.Empty;
tbName.Text = string.Empty;
this.selectedResourceFiles.Clear();
this.selectedResourceNames.Clear();
for (int i = 0; i < fd.FileNames.Length; i++)
{
this.selectedResourceFiles.Add(fd.FileNames[i]);
this.selectedResourceNames.Add(Path.GetFileName(fd.FileNames[i]));
}
}
}
}

private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}

private void cbBatch_CheckedChanged(object sender, EventArgs e)
{
tbName.ReadOnly = cbBatch.Checked;
}
}
}