Пример #1
0
		internal void ReorderEntries(PwObjectPool ppOrgStructure,
			PwObjectPool ppSrcStructure)
		{
			GroupHandler gh = delegate(PwGroup pg)
			{
				ReorderObjectList<PwEntry>(pg.Entries, ppOrgStructure,
					ppSrcStructure, true);
				return true;
			};

			ReorderObjectList<PwEntry>(m_pgRootGroup.Entries, ppOrgStructure,
				ppSrcStructure, true);
			m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, null);
		}
Пример #2
0
		internal void RelocateGroups(PwObjectPool ppOrgStructure,
			PwObjectPool ppSrcStructure)
		{
			PwObjectList<PwGroup> vGroups = m_pgRootGroup.GetGroups(true);

			foreach(PwGroup pg in vGroups)
			{
				if((m_slStatus != null) && !m_slStatus.ContinueWork()) break;

				// PwGroup pgOrg = pgOrgStructure.FindGroup(pg.Uuid, true);
				IStructureItem ptOrg = ppOrgStructure.Get(pg.Uuid);
				if(ptOrg == null) continue;
				// PwGroup pgSrc = pgSrcStructure.FindGroup(pg.Uuid, true);
				IStructureItem ptSrc = ppSrcStructure.Get(pg.Uuid);
				if(ptSrc == null) continue;

				PwGroup pgOrgParent = ptOrg.ParentGroup;
				PwGroup pgSrcParent = ptSrc.ParentGroup;
				if(pgOrgParent.Uuid.EqualsValue(pgSrcParent.Uuid))
				{
					pg.LocationChanged = ((ptSrc.LocationChanged > ptOrg.LocationChanged) ?
						ptSrc.LocationChanged : ptOrg.LocationChanged);
					continue;
				}

				if(ptSrc.LocationChanged > ptOrg.LocationChanged)
				{
					PwGroup pgLocal = m_pgRootGroup.FindGroup(pgSrcParent.Uuid, true);
					if(pgLocal == null) { Debug.Assert(false); continue; }

					if(pgLocal.IsContainedIn(pg)) continue;

					pg.ParentGroup.Groups.Remove(pg);
					pgLocal.AddGroup(pg, true);
					pg.LocationChanged = ptSrc.LocationChanged;
				}
				else
				{
					Debug.Assert(pg.ParentGroup.Uuid.EqualsValue(pgOrgParent.Uuid));
					Debug.Assert(pg.LocationChanged == ptOrg.LocationChanged);
				}
			}

			Debug.Assert(m_pgRootGroup.GetGroups(true).UCount == vGroups.UCount);
		}
Пример #3
0
		/// <summary>
		/// Method to check whether a reordering is required. This fast test
		/// allows to skip the reordering routine, resulting in a large
		/// performance increase.
		/// </summary>
		internal bool ObjectListRequiresReorder<T>(PwObjectList<T> vItems,
			PwObjectPool ppOrgStructure, PwObjectPool ppSrcStructure, bool bEntries)
			where T : class, IStructureItem, IDeepClonable<T>
		{
			Debug.Assert(ppOrgStructure.ContainsOnlyType(bEntries ? typeof(PwEntry) : typeof(PwGroup)));
			Debug.Assert(ppSrcStructure.ContainsOnlyType(bEntries ? typeof(PwEntry) : typeof(PwGroup)));
			if(vItems.UCount <= 1) return false;

			if((m_slStatus != null) && !m_slStatus.ContinueWork()) return false;

			T ptFirst = vItems.GetAt(0);
			// IStructureItem ptOrg = pgOrgStructure.FindObject(ptFirst.Uuid, true, bEntries);
			IStructureItem ptOrg = ppOrgStructure.Get(ptFirst.Uuid);
			if(ptOrg == null) return true;
			// IStructureItem ptSrc = pgSrcStructure.FindObject(ptFirst.Uuid, true, bEntries);
			IStructureItem ptSrc = ppSrcStructure.Get(ptFirst.Uuid);
			if(ptSrc == null) return true;

			if(ptFirst.ParentGroup == null) { Debug.Assert(false); return true; }
			PwGroup pgOrgParent = ptOrg.ParentGroup;
			if(pgOrgParent == null) return true; // Root might be in tree
			PwGroup pgSrcParent = ptSrc.ParentGroup;
			if(pgSrcParent == null) return true; // Root might be in tree

			if(!ptFirst.ParentGroup.Uuid.EqualsValue(pgOrgParent.Uuid)) return true;
			if(!pgOrgParent.Uuid.EqualsValue(pgSrcParent.Uuid)) return true;

			List<IStructureItem> lOrg = pgOrgParent.GetObjects(false, bEntries);
			List<IStructureItem> lSrc = pgSrcParent.GetObjects(false, bEntries);
			if(vItems.UCount != (uint)lOrg.Count) return true;
			if(lOrg.Count != lSrc.Count) return true;

			for(uint u = 0; u < vItems.UCount; ++u)
			{
				IStructureItem pt = vItems.GetAt(u);
				Debug.Assert(pt.ParentGroup == ptFirst.ParentGroup);

				if(!pt.Uuid.EqualsValue(lOrg[(int)u].Uuid)) return true;
				if(!pt.Uuid.EqualsValue(lSrc[(int)u].Uuid)) return true;
				if(pt.LocationChanged != lOrg[(int)u].LocationChanged) return true;
				if(pt.LocationChanged != lSrc[(int)u].LocationChanged) return true;
			}

			return false;
		}
Пример #4
0
		internal void RelocateEntries(PwObjectPool ppOrgStructure,
			PwObjectPool ppSrcStructure)
		{
			PwObjectList<PwEntry> vEntries = m_pgRootGroup.GetEntries(true);

			foreach(PwEntry pe in vEntries)
			{
				if((m_slStatus != null) && !m_slStatus.ContinueWork()) break;

				// PwEntry peOrg = pgOrgStructure.FindEntry(pe.Uuid, true);
				IStructureItem ptOrg = ppOrgStructure.Get(pe.Uuid);
				if(ptOrg == null) continue;
				// PwEntry peSrc = pgSrcStructure.FindEntry(pe.Uuid, true);
				IStructureItem ptSrc = ppSrcStructure.Get(pe.Uuid);
				if(ptSrc == null) continue;

				PwGroup pgOrg = ptOrg.ParentGroup;
				PwGroup pgSrc = ptSrc.ParentGroup;
				if(pgOrg.Uuid.EqualsValue(pgSrc.Uuid))
				{
					pe.LocationChanged = ((ptSrc.LocationChanged > ptOrg.LocationChanged) ?
						ptSrc.LocationChanged : ptOrg.LocationChanged);
					continue;
				}

				if(ptSrc.LocationChanged > ptOrg.LocationChanged)
				{
					PwGroup pgLocal = m_pgRootGroup.FindGroup(pgSrc.Uuid, true);
					if(pgLocal == null) { Debug.Assert(false); continue; }

					pe.ParentGroup.Entries.Remove(pe);
					pgLocal.AddEntry(pe, true);
					pe.LocationChanged = ptSrc.LocationChanged;
				}
				else
				{
					Debug.Assert(pe.ParentGroup.Uuid.EqualsValue(pgOrg.Uuid));
					Debug.Assert(pe.LocationChanged == ptOrg.LocationChanged);
				}
			}

			Debug.Assert(m_pgRootGroup.GetEntries(true).UCount == vEntries.UCount);
		}
Пример #5
0
		internal static uint FindLocationChangedPivot<T>(PwObjectList<T> vItems,
			KeyValuePair<uint, uint> kvpRange, PwObjectPool ppOrgStructure,
			PwObjectPool ppSrcStructure, Queue<PwUuid> qBefore, Queue<PwUuid> qAfter,
			bool bEntries)
			where T : class, IStructureItem, IDeepClonable<T>
		{
			uint uPosMax = kvpRange.Key;
			DateTime dtMax = DateTime.MinValue;
			List<IStructureItem> vNeighborSrc = null;

			for(uint u = kvpRange.Key; u <= kvpRange.Value; ++u)
			{
				T pt = vItems.GetAt(u);

				// IStructureItem ptOrg = pgOrgStructure.FindObject(pt.Uuid, true, bEntries);
				IStructureItem ptOrg = ppOrgStructure.Get(pt.Uuid);
				if((ptOrg != null) && (ptOrg.LocationChanged > dtMax))
				{
					uPosMax = u;
					dtMax = ptOrg.LocationChanged; // No 'continue'
					vNeighborSrc = ptOrg.ParentGroup.GetObjects(false, bEntries);
				}

				// IStructureItem ptSrc = pgSrcStructure.FindObject(pt.Uuid, true, bEntries);
				IStructureItem ptSrc = ppSrcStructure.Get(pt.Uuid);
				if((ptSrc != null) && (ptSrc.LocationChanged > dtMax))
				{
					uPosMax = u;
					dtMax = ptSrc.LocationChanged; // No 'continue'
					vNeighborSrc = ptSrc.ParentGroup.GetObjects(false, bEntries);
				}
			}

			GetNeighborItems(vNeighborSrc, vItems.GetAt(uPosMax).Uuid, qBefore, qAfter);
			return uPosMax;
		}
Пример #6
0
		internal void ReorderObjectList<T>(PwObjectList<T> vItems,
			PwObjectPool ppOrgStructure, PwObjectPool ppSrcStructure, bool bEntries)
			where T : class, IStructureItem, IDeepClonable<T>
		{
			if(!ObjectListRequiresReorder<T>(vItems, ppOrgStructure, ppSrcStructure,
				bEntries)) return;

#if DEBUG
			PwObjectList<T> vOrgListItems = vItems.CloneShallow();
#endif

			Queue<KeyValuePair<uint, uint>> qToDo = new Queue<KeyValuePair<uint, uint>>();
			qToDo.Enqueue(new KeyValuePair<uint, uint>(0, vItems.UCount - 1));

			while(qToDo.Count > 0)
			{
				if((m_slStatus != null) && !m_slStatus.ContinueWork()) break;

				KeyValuePair<uint, uint> kvp = qToDo.Dequeue();
				if(kvp.Value <= kvp.Key) { Debug.Assert(false); continue; }

				Queue<PwUuid> qRelBefore = new Queue<PwUuid>();
				Queue<PwUuid> qRelAfter = new Queue<PwUuid>();
				uint uPivot = FindLocationChangedPivot<T>(vItems, kvp, ppOrgStructure,
					ppSrcStructure, qRelBefore, qRelAfter, bEntries);
				T ptPivot = vItems.GetAt(uPivot);

				List<T> vToSort = vItems.GetRange(kvp.Key, kvp.Value);
				Queue<T> qBefore = new Queue<T>();
				Queue<T> qAfter = new Queue<T>();
				bool bBefore = true;

				foreach(T pt in vToSort)
				{
					if(pt == ptPivot) { bBefore = false; continue; }

					bool bAdded = false;
					foreach(PwUuid puBefore in qRelBefore)
					{
						if(puBefore.EqualsValue(pt.Uuid))
						{
							qBefore.Enqueue(pt);
							bAdded = true;
							break;
						}
					}
					if(bAdded) continue;

					foreach(PwUuid puAfter in qRelAfter)
					{
						if(puAfter.EqualsValue(pt.Uuid))
						{
							qAfter.Enqueue(pt);
							bAdded = true;
							break;
						}
					}
					if(bAdded) continue;

					if(bBefore) qBefore.Enqueue(pt);
					else qAfter.Enqueue(pt);
				}
				Debug.Assert(bBefore == false);

				uint uPos = kvp.Key;
				while(qBefore.Count > 0) vItems.SetAt(uPos++, qBefore.Dequeue());
				vItems.SetAt(uPos++, ptPivot);
				while(qAfter.Count > 0) vItems.SetAt(uPos++, qAfter.Dequeue());
				Debug.Assert(uPos == (kvp.Value + 1));

				int iNewPivot = vItems.IndexOf(ptPivot);
				if((iNewPivot < (int)kvp.Key) || (iNewPivot > (int)kvp.Value))
				{
					Debug.Assert(false);
					continue;
				}

				if((iNewPivot - 1) > (int)kvp.Key)
					qToDo.Enqueue(new KeyValuePair<uint, uint>(kvp.Key,
						(uint)(iNewPivot - 1)));

				if((iNewPivot + 1) < (int)kvp.Value)
					qToDo.Enqueue(new KeyValuePair<uint, uint>((uint)(iNewPivot + 1),
						kvp.Value));
			}

#if DEBUG
			foreach(T ptItem in vOrgListItems)
			{
				Debug.Assert(vItems.IndexOf(ptItem) >= 0);
			}
#endif
		}
Пример #7
0
		/// <summary>
		/// Synchronize the current database with another one.
		/// </summary>
		/// <param name="pwSource">Input database to synchronize with. This input
		/// database is used to update the current one, but is not modified! You
		/// must copy the current object if you want a second instance of the
		/// synchronized database. The input database must not be seen as valid
		/// database any more after calling <c>Synchronize</c>.</param>
		/// <param name="mm">Merge method.</param>
		/// <param name="slStatus">Logger to report status messages to.
		/// May be <c>null</c>.</param>
		public void MergeIn(PwDatabase pwSource, PwMergeMethod mm,
			IStatusLogger slStatus)
		{
			if(pwSource == null) throw new ArgumentNullException("pwSource");

			PwGroup pgOrgStructure = m_pgRootGroup.CloneStructure();
			PwGroup pgSrcStructure = pwSource.m_pgRootGroup.CloneStructure();

			if(mm == PwMergeMethod.CreateNewUuids)
				pwSource.RootGroup.CreateNewItemUuids(true, true, true);

			GroupHandler gh = delegate(PwGroup pg)
			{
				if(pg == pwSource.m_pgRootGroup) return true;

				PwGroup pgLocal = m_pgRootGroup.FindGroup(pg.Uuid, true);
				if(pgLocal == null)
				{
					PwGroup pgSourceParent = pg.ParentGroup;
					PwGroup pgLocalContainer;
					if(pgSourceParent == pwSource.m_pgRootGroup)
						pgLocalContainer = m_pgRootGroup;
					else
						pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true);
					Debug.Assert(pgLocalContainer != null);
					if(pgLocalContainer == null) pgLocalContainer = m_pgRootGroup;

					PwGroup pgNew = new PwGroup(false, false);
					pgNew.Uuid = pg.Uuid;
					pgNew.AssignProperties(pg, false, true);
					pgLocalContainer.AddGroup(pgNew, true);
				}
				else // pgLocal != null
				{
					Debug.Assert(mm != PwMergeMethod.CreateNewUuids);

					if(mm == PwMergeMethod.OverwriteExisting)
						pgLocal.AssignProperties(pg, false, false);
					else if((mm == PwMergeMethod.OverwriteIfNewer) ||
						(mm == PwMergeMethod.Synchronize))
					{
						pgLocal.AssignProperties(pg, true, false);
					}
					// else if(mm == PwMergeMethod.KeepExisting) ...
				}

				return ((slStatus != null) ? slStatus.ContinueWork() : true);
			};

			EntryHandler eh = delegate(PwEntry pe)
			{
				PwEntry peLocal = m_pgRootGroup.FindEntry(pe.Uuid, true);
				if(peLocal == null)
				{
					PwGroup pgSourceParent = pe.ParentGroup;
					PwGroup pgLocalContainer;
					if(pgSourceParent == pwSource.m_pgRootGroup)
						pgLocalContainer = m_pgRootGroup;
					else
						pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true);
					Debug.Assert(pgLocalContainer != null);
					if(pgLocalContainer == null) pgLocalContainer = m_pgRootGroup;

					PwEntry peNew = new PwEntry(false, false);
					peNew.Uuid = pe.Uuid;
					peNew.AssignProperties(pe, false, true, true);
					pgLocalContainer.AddEntry(peNew, true);
				}
				else // peLocal != null
				{
					Debug.Assert(mm != PwMergeMethod.CreateNewUuids);

					bool bEquals = peLocal.EqualsEntry(pe, true, false, true,
						true, false);

					bool bOrgBackup = !bEquals;
					if(mm != PwMergeMethod.OverwriteExisting)
						bOrgBackup &= (pe.LastModificationTime > peLocal.LastModificationTime);
					bOrgBackup &= !pe.HasBackupOfData(peLocal, false, true);
					if(bOrgBackup) peLocal.CreateBackup();

					bool bSrcBackup = !bEquals && (mm != PwMergeMethod.OverwriteExisting);
					bSrcBackup &= (peLocal.LastModificationTime > pe.LastModificationTime);
					bSrcBackup &= !peLocal.HasBackupOfData(pe, false, true);
					if(bSrcBackup) pe.CreateBackup();

					if(mm == PwMergeMethod.OverwriteExisting)
						peLocal.AssignProperties(pe, false, false, false);
					else if((mm == PwMergeMethod.OverwriteIfNewer) ||
						(mm == PwMergeMethod.Synchronize))
					{
						peLocal.AssignProperties(pe, true, false, false);
					}
					// else if(mm == PwMergeMethod.KeepExisting) ...

					MergeEntryHistory(peLocal, pe, mm);
				}

				return ((slStatus != null) ? slStatus.ContinueWork() : true);
			};

			if(!pwSource.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh))
				throw new InvalidOperationException();

			IStatusLogger slPrevStatus = m_slStatus;
			m_slStatus = slStatus;

			if(mm == PwMergeMethod.Synchronize)
			{
				ApplyDeletions(pwSource.m_vDeletedObjects, true);
				ApplyDeletions(m_vDeletedObjects, false);

				PwObjectPool ppOrgGroups = PwObjectPool.FromGroupRecursive(
					pgOrgStructure, false);
				PwObjectPool ppSrcGroups = PwObjectPool.FromGroupRecursive(
					pgSrcStructure, false);
				PwObjectPool ppOrgEntries = PwObjectPool.FromGroupRecursive(
					pgOrgStructure, true);
				PwObjectPool ppSrcEntries = PwObjectPool.FromGroupRecursive(
					pgSrcStructure, true);

				RelocateGroups(ppOrgGroups, ppSrcGroups);
				ReorderGroups(ppOrgGroups, ppSrcGroups);
				RelocateEntries(ppOrgEntries, ppSrcEntries);
				ReorderEntries(ppOrgEntries, ppSrcEntries);
				Debug.Assert(ValidateUuidUniqueness());
			}

			// Must be called *after* merging groups, because group UUIDs
			// are required for recycle bin and entry template UUIDs
			MergeInDbProperties(pwSource, mm);

			MergeInCustomIcons(pwSource);

			m_slStatus = slPrevStatus;
		}