|
using System;
using System.Collections.Generic;
using System.Text;
using PasswordSafe.Xml;
using Fluid.Controls;
using PasswordSafe.Properties;
namespace PasswordSafe.Classes
{
/// <summary>
/// Builds lists from data retreived from a PasswordReader to be used in ListBoxes.
/// </summary>
public class ListBuilder : IComparer<PasswordData>, IComparer<object>
{
private PasswordReader reader;
private PasswordCategory defaultCategory;
public PasswordCategory DefaultCategory
{
get
{
if (defaultCategory == null)
{
CreateDefaultCategory();
}
return defaultCategory;
}
}
/// <summary>
/// Creates a new ListBuilder instance with data from a PasswordReader.
/// </summary>
/// <param name="reader">The PasswordReader class from which to retreive the data.</param>
public ListBuilder(PasswordReader reader)
{
this.reader = reader;
}
private void CreateDefaultCategory()
{
PasswordCategory c = new PasswordCategory("Not Specified");
c.IsDefault = true;
c.Fields.Add(new FieldInfo("user", "Username"));
c.Fields.Add(new FieldInfo("password", "Password"));
c.Fields.Add(new FieldInfo("email", "EMail"));
c.Fields.Add(new FieldInfo("url", "Url"));
c.Fields.Add(new Separator());
c.Fields.Add(new FieldInfo("info", "Info"));
defaultCategory = c;
}
private NotifyList listBoxCategories;
/// <summary>
/// Gets an enumeration of all PasswordCategories.
/// </summary>
public IEnumerable<PasswordCategory> Categories
{
get
{
foreach (object item in listBoxCategories)
{
PasswordCategory category = item as PasswordCategory;
if (category != null) yield return category;
}
}
}
/// <summary>
/// Gets the list of categories including group headers for listboxes.
/// </summary>
public NotifyList ListBoxCategories
{
get { return GetCategories(); }
}
private NotifyList GetCategories()
{
if (listBoxCategories != null) return listBoxCategories;
List<object> sortList = new List<object>();
listBoxCategories = new NotifyList();
foreach (PasswordCategory c in reader.Categories)
{
sortList.Add(c);
}
sortList.Add(DefaultCategory);
sortList.Sort(this);
foreach (object o in sortList) listBoxCategories.Add(o);
all = new PasswordCategory("all");
all.passwords = this.Passwords;
all.ReadOnly = true;
all.Title = "All Passwords";
all.IsDefault = true;
listBoxCategories.Insert(0, all);
listBoxCategories.Insert(1, new GroupHeader());
listBoxCategories.ModifyChanged += new EventHandler(ListModifyChanged);
return listBoxCategories;
}
private PasswordCategory all;
private List<PasswordData> passwords;
public List<PasswordData> Passwords
{
get
{
EnsurePasswordList();
return passwords;
}
}
private bool modified;
/// <summary>
/// Gets if the data was modified and needs to be saved.
/// </summary>
public bool Modified
{
get { return modified; }
set
{
if (modified != value)
{
modified = value;
OnModifiedChanged();
}
}
}
private void OnModifiedChanged()
{
if (ModifiedChanged != null) ModifiedChanged(this, EventArgs.Empty);
}
public event EventHandler ModifiedChanged;
void EnsurePasswordList()
{
if (passwords == null)
{
passwords = new List<PasswordData>();
PasswordCategory defautCategory = DefaultCategory;
foreach (PasswordData d in reader.Passwords)
{
if (d.Category == null)
{
d.Category = defaultCategory;
}
passwords.Add(d);
}
passwords.Sort(this);
}
}
private NotifyList currentPasswords;
private List<object> passwordCopy = new List<object>();
public NotifyList GetPasswords(PasswordCategory category, bool headers)
{
if (category == all) category = null;
EnsurePasswordList();
List<PasswordData> passwords = new List<PasswordData>();
foreach (PasswordData d in this.passwords)
{
if (category == null || d.Category == category)
{
passwords.Add(d);
}
}
passwords.Sort(this);
NotifyList sorted = new NotifyList();
foreach (PasswordData d in passwords)
{
sorted.Add(d);
}
passwords.Clear();
if (headers && sorted.Count > 3) sorted = AddHeaders(sorted);
sorted.ModifyChanged += new EventHandler(ListModifyChanged);
currentPasswords = sorted;
passwordCopy.Clear();
foreach (var p in sorted)
{
passwordCopy.Add(p);
}
return sorted;
}
void ListModifyChanged(object sender, EventArgs e)
{
Modified = true;
}
private NotifyList AddHeaders(NotifyList passwords)
{
NotifyList list = new NotifyList();
string current = "";
foreach (PasswordData d in passwords)
{
string c = d.Name.Substring(0, 1).ToUpper();
if (current != c)
{
current = c;
list.Add(new GroupHeader(c));
}
list.Add(d);
}
list.ModifyChanged += new EventHandler(ListModifyChanged);
return list;
}
#region IComparer<PasswordData> Members
int IComparer<PasswordData>.Compare(PasswordData x, PasswordData y)
{
return x.Name.CompareTo(y.Name);
}
#endregion
#region IComparer<object> Members
int IComparer<object>.Compare(object x, object y)
{
PasswordCategory a = x as PasswordCategory;
if (a != null)
{
PasswordCategory b = y as PasswordCategory;
return a.Name.CompareTo(b.Name);
}
return 0;
}
#endregion
/// <summary>
/// Gets or sets the instance for global use.
/// </summary>
/// <remarks>
/// The main form sets the instance while other controls access the instance.
/// </remarks>
public static ListBuilder Instance;
/// <summary>
/// Creates a list of details of a password.
/// </summary>
/// <param name="password">the data of the password.</param>
/// <param name="newItem">true if this password is new, otherwise false.</param>
/// <returns></returns>
public NotifyList GetDetails(PasswordData password, bool newItem)
{
NotifyList list = new NotifyList();
PasswordCategory c = password.Category;
if (c.Fields.Count == 0) c = DefaultCategory;
foreach (FieldInfo field in c.Fields)
{
Separator separator = field as Separator;
if (separator == null)
{
string name = field.Name;
string value = password.Values[name];
PWNameValue item = new PWNameValue(field.Title + ":", field.Name, password);
list.Add(item);
}
else
{
GroupHeader header = new GroupHeader(separator.Title);
list.Add(header);
}
}
if (newItem)
{
PWNameValue nameValue = new PWNameValue("Name", "name", password);
list.Insert(0, nameValue);
GroupHeader gh = list[1] as GroupHeader;
if (gh == null)
{
list.Insert(1, new GroupHeader());
}
}
list.Modified = false;
list.ModifyChanged += new EventHandler(ListModifyChanged);
return list;
}
public PasswordData CreateNewPassword(PasswordCategory category)
{
EnsurePasswordList();
PasswordData data = new PasswordData();
data.Category = category;
passwords.Add(data);
return data;
}
public void DeletePassword(PasswordData password)
{
password.Category = null;
Passwords.Remove(password);
}
public void AddCategory(PasswordCategory category)
{
string text = category.Title;
for (int i = 2; i < listBoxCategories.Count; i++)
{
PasswordCategory c = listBoxCategories[i] as PasswordCategory;
if (c != null)
{
if (c.Name == category.Name) return; //already in list, so return.
if (c.Title.CompareTo(text) > 0)
{
listBoxCategories.Insert(i, category);
return;
}
}
}
listBoxCategories.Add(category);
}
public void RemoveCategory(PasswordCategory category)
{
listBoxCategories.Remove(category);
}
private List<CategoryListBoxItem> defaultCategories;
/// <summary>
/// Gets the list of all default categories.
/// </summary>
public List<CategoryListBoxItem> DefaultCategories
{
get
{
return GetDefaultCategories();
}
}
private List<CategoryListBoxItem> GetDefaultCategories()
{
if (defaultCategories == null)
{
defaultCategories = new List<CategoryListBoxItem>();
string xml = Resources.Categories;
foreach (PasswordCategory c in PasswordReader.ReadCategories(xml))
{
bool isUsed = false;
CategoryListBoxItem item = new CategoryListBoxItem { Category = c, IsUsed = isUsed };
defaultCategories.Add(item);
}
}
foreach (var c in defaultCategories)
{
c.IsUsed = IsCategoryUsed(c.Category.Name);
}
return defaultCategories;
}
private bool IsCategoryUsed(string categoryName)
{
foreach (var c in Categories)
{
if (c.Name.Equals(categoryName, StringComparison.InvariantCultureIgnoreCase)) return true;
}
return false;
}
internal void AddCategories(List<CategoryListBoxItem> categories)
{
listBoxCategories.RaiseListChangedEvents = false;
foreach (var item in categories)
{
if (item.IsUsed)
{
AddCategory(item.Category);
}
else
{
PasswordCategory category = GetCategory(item.Category.Name);
if (category != null) RemoveCategory(category);
}
}
listBoxCategories.RaiseListChangedEvents = true;
listBoxCategories.ResetBindings();
}
private PasswordCategory GetCategory(string name)
{
foreach (var c in this.Categories)
{
if (c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) return c;
}
return null;
}
char[] matrix;
private char[] EnsureMatrix()
{
if (matrix == null)
{
matrix = new char[256];
for (int i = 0; i <= 255; i++)
{
char c = Char.ToLower(Convert.ToChar(i));
if ("1".IndexOf(c) >= 0) c = '1';
else if ("2abc".IndexOf(c) >= 0) c = '2';
else if ("3def".IndexOf(c) >= 0) c = '3';
else if ("3ghi".IndexOf(c) >= 0) c = '4';
else if ("5jkl".IndexOf(c) >= 0) c = '5';
else if ("6mno".IndexOf(c) >= 0) c = '6';
else if ("7pqrs".IndexOf(c) >= 0) c = '7';
else if ("8tuv".IndexOf(c) >= 0) c = '8';
else if ("9wxyz".IndexOf(c) >= 0) c = '9';
else if ("# ".IndexOf(c) >= 0) c = '#';
else if ("0+".IndexOf(c) >= 0) c = '0';
else if (c == '*') c = '*';
else c = '\0';
matrix[i] = c;
}
}
return matrix;
}
private string MakeSearchable(string text)
{
StringBuilder sb = new StringBuilder();
char[] matrix = EnsureMatrix();
foreach (char c in text)
{
int i = (int)c;
if (i > 255) i = 255;
char mc = matrix[i];
if (mc != '\0')
{
sb.Append(mc);
}
}
return sb.ToString();
}
public void Filter(string text)
{
if (currentPasswords == null) return;
bool modified = this.Modified;
bool empty = string.IsNullOrEmpty(text);
List<object> toAdd = new List<object>();
foreach (object o in passwordCopy)
{
bool match = empty;
if (!match)
{
PasswordData p = o as PasswordData;
if (p != null)
{
string compare = MakeSearchable(p.Name);
match = compare.IndexOf(text) >= 0;
}
}
if (match)
{
toAdd.Add(o);
}
}
currentPasswords.RaiseListChangedEvents = false;
currentPasswords.Clear();
foreach (object o in toAdd)
{
currentPasswords.Add(o);
}
currentPasswords.RaiseListChangedEvents = true;
currentPasswords.ResetBindings();
// do not accidantely mark the data as begin modified:
this.Modified = modified;
}
public void UnModified()
{
Modified = false;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.