/// <summary>
        /// Sorts the work items that were in the last run of a query.
        /// </summary>
        /// <remarks>
        /// Takes account of the physical order of the bookmarks in the document.
        /// </remarks>
        /// <param name="queryWorkItemsBefore">The query to work item association data from before the refresh.</param>
        /// <param name="queryWorkItemsAfter">The query to work item association data as a result of the refresh.</param>
        /// <param name="bookmarkNamingFunction">A function to return the bookmark to use for the given work item, given the work item id.</param>
        /// <param name="cancellationToken">Used to cancel the refresh.</param>
        private void SortExistingWorkItems(QueryWorkItems queryWorkItemsBefore, QueryWorkItems queryWorkItemsAfter, Func <int, string> bookmarkNamingFunction, CancellationToken cancellationToken)
        {
            this.logger.Log(TraceEventType.Verbose, "Sorting existing work items");
            cancellationToken.ThrowIfCancellationRequested();
            int[] currentIds = queryWorkItemsBefore.WorkItemIds.OrderBy((int id) => this.FindBookmark(bookmarkNamingFunction(id)).Start)
                               .ToArray();                                 // sort into physical order
            int[] afterIds      = queryWorkItemsAfter.WorkItemIds.Intersect(currentIds).ToArray();
            int   afterIdsLen   = afterIds.Length;
            int   currentIdsLen = currentIds.Length;

            for (int i = 0; i < afterIdsLen - 1; i++)
            {
                if (afterIds[i] != currentIds[i])
                {
                    this.wordDocument.MoveBookmarkAndContentToBefore(bookmarkNamingFunction(afterIds[i]), bookmarkNamingFunction(currentIds[i]));
                    int oldPosOfMovedItem = -1;
                    for (int k = i + 1; k < currentIdsLen; k++)
                    {
                        if (currentIds[k] == afterIds[i])
                        {
                            oldPosOfMovedItem = k;
                            break;
                        }
                    }

                    for (int j = oldPosOfMovedItem; j > i; j--)
                    {
                        currentIds[j] = currentIds[j - 1];
                    }

                    currentIds[i] = afterIds[i];
                }
            }
        }
 /// <summary>
 /// Adds the new work items that were not in the last run of a query.
 /// </summary>
 /// <remarks>
 /// If the current work items have been manually sorted then new items are just added to the end, otherwise they are added in the new sort order.
 /// </remarks>
 /// <param name="queryWorkItemsBefore">The query to work item association data from before the refresh.</param>
 /// <param name="queryWorkItemsAfter">The query to work item association data as a result of the refresh.</param>
 /// <param name="workItemLayout">The work item layout associated with the query.</param>
 /// <param name="customXMLPart">The custom XML part that contains the work item data.</param>
 /// <param name="bookmarkNamingFunction">A function to return the bookmark to use for the given work item, given the work item id.</param>
 /// <param name="isManuallySorted">Indicates if the current work items are manually sorted.</param>
 /// <param name="cancellationToken">Used to cancel the refresh.</param>
 private void AddNewWorkItems(QueryWorkItems queryWorkItemsBefore, QueryWorkItems queryWorkItemsAfter, IWorkItemLayout workItemLayout, CustomXMLPart customXMLPart, Func <int, string> bookmarkNamingFunction, bool isManuallySorted, CancellationToken cancellationToken)
 {
     this.logger.Log(TraceEventType.Verbose, "Adding new work items");
     cancellationToken.ThrowIfCancellationRequested();
     int[] newIds = queryWorkItemsAfter.WorkItemIds.Except(queryWorkItemsBefore.WorkItemIds).ToArray();
     if (newIds.Length > 0)
     {
         // We have some new work items that were not present last time the query was executed.
         int[] beforeIds          = queryWorkItemsBefore.WorkItemIds.ToArray();
         int[] afterIds           = queryWorkItemsAfter.WorkItemIds.ToArray();
         WorkItemTreeNode[] nodes = queryWorkItemsAfter.WorkItemTreeNodes.ToArray();
         Debug.Assert(afterIds.Length == nodes.Length, "Number of after nodes must match number of after ids.");
         if (isManuallySorted)
         {
             this.AddAllNewWorkItemsAfterLastExisting(newIds, this.GetLastPhysicalWorkItem(beforeIds, bookmarkNamingFunction), nodes, workItemLayout, customXMLPart, bookmarkNamingFunction);
         }
         else if (afterIds.Intersect(beforeIds).Count() > 0)
         {
             this.AddNewWorkItemsBeforeExisting(newIds, beforeIds, afterIds, nodes, workItemLayout, customXMLPart, (int id) => bookmarkNamingFunction(id));
             this.AddNewWorkItemsAfterExisting(newIds, beforeIds, afterIds, nodes, workItemLayout, customXMLPart, (int id) => bookmarkNamingFunction(id));
         }
         else
         {
             this.AddNewWorkItemsWhenNoneBefore(afterIds, nodes, workItemLayout, customXMLPart, (int id) => bookmarkNamingFunction(id));
         }
     }
 }
        /// <summary>
        /// Refreshes the work items in the document.
        /// </summary>
        /// <remarks>
        /// <para>Deletes work items that are no longer returned, adds work items that are now returned, and re-orders work items that have changed position in query results.</para>
        /// <para>This call will also update the rich text content controls which are not bound to the Custom XML Parts.</para>
        /// </remarks>
        /// <param name="refreshData">The data needed for a refresh.</param>
        /// <param name="bookmarkNamingFunction">A function to return the bookmark to use for the given work item, first parameter is query index, second is work item id.</param>
        /// <param name="cancellationToken">Used to cancel the refresh.</param>
        public void RefreshWorkItems(FormatterRefreshData refreshData, Func <int, int, string> bookmarkNamingFunction, CancellationToken cancellationToken)
        {
            if (refreshData == null)
            {
                throw new ArgumentNullException("refreshData");
            }

            Debug.Assert(refreshData.QueryWorkItemsBefore.Count() == refreshData.QueryWorkItemsAfter.Count(), "Before and after data have different numbers of queries");
            Debug.Assert(refreshData.QueryWorkItemsBefore.Count() == refreshData.Layouts.Count(), "Number of layouts does not match number of queries");
            Debug.Assert(refreshData.QueryWorkItemsBefore.Count() == refreshData.QueryIsFlat.Count(), "Number of QueryIsFlat values does not match number of queries");

            DateTime start = DateTime.Now;

            CustomXMLPart part = this.wordDocument.GetXmlPart(Constants.WorkItemNamespace);

            int n = refreshData.QueryWorkItemsBefore.Count();

            QueryWorkItems[]    queryWorkItemsBefore = refreshData.QueryWorkItemsBefore.ToArray();
            QueryWorkItems[]    queryWorkItemsAfter  = refreshData.QueryWorkItemsAfter.ToArray();
            bool[]              queryIsFlat          = refreshData.QueryIsFlat.ToArray();
            LayoutInformation[] layouts = refreshData.Layouts.ToArray();
            for (int queryIndex = 0; queryIndex < n; queryIndex++)
            {
                Func <int, string> queryBookmarkNamingFunction = (int id) => bookmarkNamingFunction(queryIndex, id);
                this.logger.Log(TraceEventType.Verbose, "Refreshing query {0}", queryIndex);

                // Compute the actual before work items that are still in the document.
                QueryWorkItems actualBeforeWorkItems = new QueryWorkItems(queryIndex, queryWorkItemsBefore[queryIndex].WorkItemIds.Where(id => this.FindBookmark(queryBookmarkNamingFunction(id)) != null).ToArray());

                bool isManuallySorted = this.IsManuallySorted(queryWorkItemsBefore[queryIndex].WorkItemIds, queryBookmarkNamingFunction);
                if (!queryIsFlat[queryIndex] || (queryIsFlat[queryIndex] && !isManuallySorted))
                {
                    this.SortExistingWorkItems(actualBeforeWorkItems, queryWorkItemsAfter[queryIndex], queryBookmarkNamingFunction, cancellationToken);
                    isManuallySorted = false;
                }

                IWorkItemLayout workItemLayout = new WorkItemLayout(layouts[queryIndex], this.teamProjectTemplate);
                this.AddNewWorkItems(actualBeforeWorkItems, queryWorkItemsAfter[queryIndex], workItemLayout, part, queryBookmarkNamingFunction, isManuallySorted, cancellationToken);
            }

            this.RefreshDeleteRemovedWorkItems(refreshData.QueryWorkItemsBefore.ToArray(), refreshData.QueryWorkItemsAfter.ToArray(), bookmarkNamingFunction, cancellationToken);
            this.RefreshRichTextContentControls(refreshData.WorkItemManager, cancellationToken);

            DateTime end = DateTime.Now;

            this.logger.Log(TraceEventType.Information, "Elapsed time to refresh was {0} seconds", (end - start).TotalSeconds);
        }
Exemple #4
0
        /// <summary>
        /// Loads the work items associated with a query.
        /// </summary>
        /// <param name="index">The query index.</param>
        /// <param name="xml">The XML for the work item ids for a particular query.</param>
        /// <returns>A <see cref="QueryWorkItems"/> object for the query and its associated work items.</returns>
        private QueryWorkItems LoadWorkItemsForQuery(int index, XElement xml)
        {
            QueryWorkItems ans = new QueryWorkItems(index, xml.Descendants(this.queryWorkItemAssociationIdXName).Select(e => int.Parse(e.Attribute("Id").Value, CultureInfo.InvariantCulture)).ToArray());

            return(ans);
        }