- goalbook.zip
- GoalBook
- Dependencies
- CAG WPF 2
- Microsoft.Practices.Composite.dll
- Microsoft.Practices.Composite.Presentation.dll
- Microsoft.Practices.Composite.UnityExtensions.dll
- Microsoft.Practices.ObjectBuilder2.dll
- Microsoft.Practices.ServiceLocation.dll
- Microsoft.Practices.Unity.dll
- vssver2.scc
- CSLA
- Csla.dll
- Csla.XmlSerializers.dll
- vssver2.scc
- Infragistics
- Infragistics3.Wpf.DataPresenter.v9.1.Express.dll
- Infragistics3.Wpf.Editors.v9.1.Express.dll
- Infragistics3.Wpf.v9.1.Express.dll
- vssver2.scc
- WPFToolkit
- vssver2.scc
- WPFToolkit.dll
- GoalBook.Controls
- GoalBook.Goals
- GoalBook.Infrastructure
- GoalBook.Notes
- GoalBook.Public
- GoalBook.Shell
- App.ico
- App.xaml
- App.xaml.cs
- Bootstrapper.cs
- Commands
- GoalBook.Shell.csproj
- GoalBook.Shell.csproj.user
- Journal.ico
- Journal48.ico
- Misc
- Modules
- Properties
- Resources
- arrow_refresh.png
- arrow_undo.png
- checked.gif
- cross.png
- disk.png
- email.png
- erase.png
- error.png
- exclamation.png
- flag_red.png
- group.png
- help.png
- information.png
- magnifier.png
- page_red.png
- pencil.png
- printer.png
- user.png
- vssver2.scc
- Wave.jpg
- world.png
- world_link.png
- Services
- Splash.png
- Views
- vssver2.scc
- Windows
- GoalBook.sln
- GoalBook.snk
- GoalBook.Synchronisation
- GoalBook.Tasks
- License.txt
- ReadMe.txt
- SolutionInfo.cs
- vssver2.scc
|
//===============================================================================
// Goal Book.
// Copyright � 2009 Mark Brownsword.
//===============================================================================
#region Using Statements
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Xml.Linq;
using Csla;
using GoalBook.Infrastructure.Interfaces;
using GoalBook.Infrastructure.Properties;
#endregion
namespace GoalBook.Infrastructure.ObjectModel
{
[Serializable]
public sealed class FolderList : BusinessListBase<FolderList, Folder>, IXDocSerializable
{
#region Constants and Enums
private const string SERIALIZATION_ROOT = "FolderList";
private const string SERIALIZATION_NOTES = "Folders";
private const string SERIALIZATION_DELETED_FOLDERS = "DeletedFolders";
private const string SERIALIZATION_LAST_SERVER_FOLDER_EDIT = "LastServerFolderEdit";
#endregion
#region Inner Classes and Structures
#endregion
#region Delegates and Events
#endregion
#region Instance and Shared Fields
private List<Folder> _deleted;
private DateTime _lastServerFolderEdit;
private bool _lastServerFolderEditChanged = false;
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public FolderList()
{
AllowEdit =
AllowNew =
AllowRemove = true;
this.FolderKeyValueItemList = new KeyValueItemList();
this.FolderKeyValueItemList.Add(new KeyValueItem(Guid.Empty.ToString(), Resources.DefaultFolder, 0));
}
#endregion
#region Properties
/// <summary>
/// Expose the EditLevel so can call ApplyEdit the
/// correct number of times.
/// </summary>
public new int EditLevel { get { return base.EditLevel; } }
/// <summary>
/// Reference to LastServerFolderEdit. A timestamp that indicates
/// the last time an edit occurred on the server.
/// </summary>
public DateTime LastServerFolderEdit
{
get { return _lastServerFolderEdit;}
set { _lastServerFolderEdit = value; _lastServerFolderEditChanged = true; }
}
/// <summary>
/// Reference to SyncRequired. A flag indicating if any
/// notes have been edited and require synchronisation.
/// </summary>
public bool SyncRequired
{
get
{
foreach (Folder folder in this)
{
if (folder.SyncRequired) { return true; }
}
foreach (Folder folder in this.DeletedList)
{
if (folder.ExternalIdentifier > 0) { return true; }
}
if (this.DeletedPendingSync.Count > 0) { return true; }
return false;
}
}
/// <summary>
/// Deleted notes. For synchronisation.
/// </summary>
public List<Folder> DeletedPendingSync
{
get
{
if (_deleted == null) { DeletedPendingSync = new List<Folder>(); }
return _deleted;
}
set { _deleted = value; }
}
/// <summary>
/// Reference to FolderKeyValueItemList.
/// </summary>
public KeyValueItemList FolderKeyValueItemList { get; set; }
#endregion
#region Private and Protected Methods
/// <summary>
/// Get Folder FromElement.
/// </summary>
private Folder GetFolderFromElement(XElement element)
{
Guid folderID = new Guid(GetAttributeFromElement(element, Constants.FolderSerializationContants.SERIALIZATION_FOLDERID));
bool isPrivate = bool.Parse(GetAttributeFromElement(element, Constants.FolderSerializationContants.SERIALIZATION_ISPRIVATE));
bool archived = bool.Parse(GetAttributeFromElement(element, Constants.FolderSerializationContants.SERIALIZATION_ARCHIVED));
int order = int.Parse(GetAttributeFromElement(element, Constants.FolderSerializationContants.SERIALIZATION_ORDER));
string title = GetAttributeFromElement(element, Constants.FolderSerializationContants.SERIALIZATION_TITLE);
int externalIdentifier = int.Parse(GetAttributeFromElement(element, Constants.FolderSerializationContants.SERIALIZATION_EXTERNALIDENTIFIER));
Folder folder = new Folder(folderID, isPrivate, archived, order, title, externalIdentifier);
folder.SyncRequired = bool.Parse(GetAttributeFromElement(element, Constants.FolderSerializationContants.SERIALIZATION_SYNCREQUIRED));
return folder;
}
/// <summary>
/// Get Folder with the specified id.
/// </summary>
private Folder GetFolder(FolderList folderList, Guid id)
{
var targetList = from g in folderList where g.FolderID == id select g;
foreach (Folder folder in targetList)
{
return folder; //One only can exist.
}
return null;
}
/// <summary>
/// Get Attribute From Element.
/// </summary>
private string GetAttributeFromElement(XElement element, string attribute)
{
if (element.Attribute(attribute) == null) { return null; }
return element.Attribute(attribute).Value;
}
#endregion
#region Public and internal Methods
#region IXDocSerializable Members
/// <summary>
/// Get Folders List as XDocument.
/// </summary>
public XDocument GetXDocument()
{
//Serialize the FolderList Element.
XElement folderElement = new XElement(SERIALIZATION_NOTES, new XAttribute(SERIALIZATION_LAST_SERVER_FOLDER_EDIT,
LastServerFolderEdit.ToString()));
//Serialize the Folders.
foreach (Folder folder in this)
{
folderElement.Add(folder.SerializeAsXElement());
}
XElement deletedPendingSyncElement = new XElement(SERIALIZATION_DELETED_FOLDERS);
//Serialize the deleted Folders.
foreach (Folder folder in this.DeletedPendingSync)
{
deletedPendingSyncElement.Add(folder.SerializeAsXElement());
}
XElement rootElement = new XElement(SERIALIZATION_ROOT, folderElement, deletedPendingSyncElement);
return new XDocument(rootElement);
}
/// <summary>
/// Create NotesList From XDocument.
/// </summary>
public void CreateFromXDocument(XDocument xDoc)
{
if (xDoc == null) return;
XElement root = xDoc.Element(SERIALIZATION_ROOT);
XElement notes = root.Element(SERIALIZATION_NOTES);
XElement deletedFolders = root.Element(SERIALIZATION_DELETED_FOLDERS);
//LastServerFolderEdit
if (!string.IsNullOrEmpty(GetAttributeFromElement(notes, SERIALIZATION_LAST_SERVER_FOLDER_EDIT)))
{
this._lastServerFolderEdit = Convert.ToDateTime(GetAttributeFromElement(notes, SERIALIZATION_LAST_SERVER_FOLDER_EDIT));
}
//Load the Folders.
foreach (XElement element in notes.Descendants(Constants.FolderSerializationContants.SERIALIZATION_FOLDER))
{
this.Add(GetFolderFromElement(element));
}
//Load the deletedPendingSync Folders.
this.DeletedPendingSync.Clear();
foreach (XElement element in deletedFolders.Descendants(Constants.FolderSerializationContants.SERIALIZATION_FOLDER))
{
this.DeletedPendingSync.Add(GetFolderFromElement(element));
}
}
/// <summary>
/// MarkListOld. Mark all list items as old.
/// </summary>
public void MarkListOld()
{
//Wind back the EditLevel.
while (this.EditLevel > 0) { this.ApplyEdit(); }
//Mark each child as old (clean).
foreach (Folder folder in this) { folder.MarkFolderOld(); }
//Move the Deleted items with an ExternalIdentifier to the Deleted list. The DeletedList
//holds goals that have been deleted on the client but have not yet been synchronised.
var deleted = from g in DeletedList where g.ExternalIdentifier > 0 select g;
foreach (Folder folder in deleted)
{
if (DeletedPendingSync.Contains(folder)) { continue; }
DeletedPendingSync.Add(folder);
}
//The list remains dirty until the DeletedList is clear, so clear it now.
DeletedList.Clear();
//Set to true after sync, so set false during save.
_lastServerFolderEditChanged = false;
}
#endregion
/// <summary>
/// Merge folders. Synchronisation occurs in a cloned FolderList,
/// so need to merge changes back into the primary FolderList.
/// </summary>
public void Merge(FolderList syncFolders)
{
foreach (Folder folder in syncFolders)
{
Folder target = GetFolder(this, folder.FolderID);
if (target == null)
{
//Add
this.BeginEdit();
this.Add(folder);
this.EndNew(this.IndexOf(folder));
}
else
{
//Edit
if (folder.IsDirty) //Dirty means changes occured during sync.
{
this.BeginEdit();
target.MapFields(folder);
}
//Set SyncRequired flag (so client edits only get pushed to server once).
target.SyncRequired = folder.SyncRequired;
}
}
foreach (Folder folder in syncFolders.DeletedList)
{
//Remove
Folder target = GetFolder(this, folder.FolderID);
if (target != null)
{
this.Remove(target);
}
}
//Clear Deleted. Sync of Deleted items is complete.
if (this.DeletedList.Count > 0) { this.DeletedList.Clear(); }
this.DeletedPendingSync.Clear();
foreach (Folder folder in syncFolders.DeletedPendingSync)
{
//Folders remaining in syncFolders.DeletedPendingSync were not
//successfully deleted during the client changes synchronisation.
//These need to be retained so can attempt delete again.
this.DeletedPendingSync.Add(folder);
}
//Map LastServerFolderEdit.
if (syncFolders.LastServerFolderEdit > this.LastServerFolderEdit)
{
this.LastServerFolderEdit = syncFolders.LastServerFolderEdit;
}
}
#endregion
#region Event Handlers
#endregion
#region Base Class Overrides
/// <summary>
/// OnListChanged.
/// </summary>
/// <param name="e">ListChangedEventArgs parameter</param>
protected override void OnListChanged(ListChangedEventArgs e)
{
base.OnListChanged(e);
// Maintain FolderKeyValueItemList when items change.
switch (e.ListChangedType)
{
case ListChangedType.ItemAdded:
this.FolderKeyValueItemList.Add(new KeyValueItem(
this[e.NewIndex].FolderID.ToString(),
this[e.NewIndex].Title,
this[e.NewIndex].Order));
break;
case ListChangedType.ItemChanged:
foreach (KeyValueItem item in this.FolderKeyValueItemList)
{
if (item.Key == this[e.NewIndex].FolderID.ToString())
{
item.Value = this[e.NewIndex].Title;
item.Order = this[e.NewIndex].Order;
}
}
break;
case ListChangedType.ItemDeleted:
foreach (Folder folder in this.DeletedList)
{
foreach (KeyValueItem item in this.FolderKeyValueItemList.ToArray())
{
if (folder.FolderID.ToString() == item.Key)
{
this.FolderKeyValueItemList.Remove(item);
break;
}
}
}
break;
}
}
/// <summary>
/// AddNewCore. Initialises and adds a new Folder item to the List.
/// </summary>
protected override object AddNewCore()
{
Guid guid = Guid.NewGuid();
Folder folder = new Folder(guid);
Add(folder);
return folder;
}
/// <summary>
/// IsSavable.
/// </summary>
public override bool IsSavable
{
get
{
if (_lastServerFolderEditChanged)
{
return base.IsValid;
}
return base.IsSavable;
}
}
#endregion
}
}
|
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.
I've been working as a software developer since 2000 and hold a Bachelor of Business degree from The Open Polytechnic of New Zealand. Computers are for people and I aim to build applications for people that they would want to use.