/// <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;
		}
Example #2
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>
        public void MergeIn(PwDatabase pwSource, PwMergeMethod mm)
        {
            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);

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

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

                return(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);

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

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

                return(true);
            };

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

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