private void CheckForChangedContexts(string context_word, string context_backward, string context_surround, CitationCluster context_citation_cluster)
        {
            // Has text context changed?
            if (context_word != current_context_word || context_backward != current_context_backward || context_surround != current_context_surround)
            {
                current_context_word     = context_word;
                current_context_backward = context_backward;
                current_context_surround = context_surround;

                if (null != ContextChanged)
                {
                    ContextChanged(current_context_word, current_context_backward, current_context_surround);
                }
            }

            // Has citation context changed?
            if ((context_citation_cluster == null ? null : context_citation_cluster.cluster_id) != (current_context_citation_cluster == null ? null : current_context_citation_cluster.cluster_id))
            {
                current_context_citation_cluster = context_citation_cluster;
                if (null != CitationClusterChanged)
                {
                    CitationClusterChanged(current_context_citation_cluster);
                }
            }
        }
        public List <CitationCluster> GetAllCitationClustersFromCurrentDocument()
        {
            HashSet <string> used_cluster_ids = new HashSet <string>();

            List <CitationCluster> citation_clusters = new List <CitationCluster>();

            Document document = word_application.Selection.Document;

            List <Field> fields = GetDocumentFields(document);

            foreach (Field field in fields)
            {
                CitationCluster citation_cluster = GenerateCitationClusterFromField(field);
                if (null != citation_cluster)
                {
                    // Check that this cluster id has not already been used - that happens if they have copied and pasted a field.
                    if (used_cluster_ids.Contains(citation_cluster.cluster_id))
                    {
                        Logging.Info("A cluster has been copied, so we are regenerating a new cluster id for {0}", citation_cluster);
                        citation_cluster.cluster_id = CitationCluster.GetRandomClusterId();
                        PopulateFieldWithRawCitationCluster(field, citation_cluster);
                    }

                    used_cluster_ids.Add(citation_cluster.cluster_id);
                    citation_clusters.Add(citation_cluster);
                }
            }

            return(citation_clusters);
        }
        internal void AppendCitation(CitationCluster citation_cluster)
        {
            if (0 == citation_cluster.citation_items.Count)
            {
                Logging.Warn("Not appending zero citations");
                return;
            }

            CitationCluster existing_citation_cluster;
            Field           existing_field;

            GetCurrentlySelectedCitationCluster(out existing_citation_cluster, out existing_field);
            if (null != existing_citation_cluster)
            {
                existing_citation_cluster.citation_items.AddRange(citation_cluster.citation_items);
                PopulateFieldWithRawCitationCluster(existing_field, existing_citation_cluster);
                word_application.Activate();
            }
            else
            {
                // Shrink the selection to the end of it, so that we can add a citation after it...
                Range range = GetInsertionPointRange();
                Field field = range.Fields.Add(range, WdFieldType.wdFieldMergeField, citation_cluster.ToString(), true);
                field.Locked = true;
                PopulateFieldWithRawCitationCluster(field, citation_cluster);
                word_application.Activate();
            }
        }
        public static void CitePDFDocuments(List <PDFDocument> pdf_documents, bool separate_author_and_date)
        {
            try
            {
                foreach (var pdf_document in pdf_documents)
                {
                    if (String.IsNullOrEmpty(pdf_document.BibTex))
                    {
                        MessageBoxes.Warn("One or more of your documents have no associated BibTeX information.  Please add some or use the BibTeX Sniffer to locate it on the Internet.");
                        return;
                    }
                }

                CitationCluster citation_cluster = GenerateCitationClusterFromPDFDocuments(pdf_documents);
                citation_cluster.citation_items[0].SeparateAuthorsAndDate(separate_author_and_date);

                if (null != citation_cluster)
                {
                    WordConnector.Instance.WaitForAtLeastOneIteration();
                    WordConnector.Instance.AppendCitation(citation_cluster);
                }
            }
            catch (Exception ex)
            {
                Logging.Error(ex, "Exception while citing PDFDocument.");
                MessageBoxes.Error("There has been a problem while trying to add the citation.  Please check that Microsoft Word is running.\n\nIf the problem persists, perhaps open InCite from the Start Page as it may offer more details about the problem.");
            }
        }
        private void GetCurrentlySelectedCitationCluster(out CitationCluster return_citation_cluster, out Field return_field)
        {
            CitationCluster context_citation_cluster       = null;
            Field           context_field                  = null;
            int             context_citation_cluster_count = 0;

            // The current cursor position / selected
            Selection selection = word_application.Selection;

            if (null != selection)
            {
                Range range = selection.Range;

                // Widen around the current selection to sniff for fields that overlap our range
                Range range_to_scan = word_application.Selection.Range;
                range_to_scan.MoveStart(WdUnits.wdParagraph, -1);
                range_to_scan.MoveEnd(WdUnits.wdParagraph, +1);

                // Check each field
                foreach (Field field in range_to_scan.Fields)
                {
                    try
                    {
                        int field_start = Math.Min(field.Result.Start, field.Code.Start);
                        int field_end   = Math.Max(field.Result.End, field.Code.End);
                        // Skip all ranges that do not overlap
                        if (field_start > range.End + 1 || field_end < range.Start)
                        {
                            continue;
                        }

                        // We use the first one that does overlap
                        CitationCluster citation_cluster = GenerateCitationClusterFromField(field);
                        if (null != citation_cluster)
                        {
                            context_citation_cluster = citation_cluster;
                            context_field            = field;
                            ++context_citation_cluster_count;
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.Warn(ex, "Skipping field that can't be an InCite field.");
                        continue;
                    }
                }
            }

            // We only return a citation cluster if EXACTLY ONE has been selected
            if (1 == context_citation_cluster_count)
            {
                return_citation_cluster = context_citation_cluster;
                return_field            = context_field;
            }
            else
            {
                return_citation_cluster = null;
                return_field            = null;
            }
        }
        private void CmdApply_Click(object sender, RoutedEventArgs e)
        {
            CitationCluster citation_cluster = current_citation_cluster;

            if (null != citation_cluster)
            {
                // Make our stored citation cluster look like the GUI choices
                {
                    // Delete any items that were removed in the GUI
                    ObservableCollection <string> citation_item_keys = (ObservableCollection <string>)ObjCitationsInCluster.ItemsSource;
                    for (int i = citation_cluster.citation_items.Count - 1; i >= 0; --i)
                    {
                        if (!citation_item_keys.Contains(citation_cluster.citation_items[i].reference_key))
                        {
                            citation_cluster.citation_items.RemoveAt(i);
                        }
                    }

                    // And apply the other settings
                    List <string> specifier_locations = new List <string>(ObjSpecifierLocation.Text.Split(';'));
                    while (specifier_locations.Count < citation_cluster.citation_items.Count)
                    {
                        specifier_locations.Add("");
                    }
                    List <string> prefixes = new List <string>(ObjPrefix.Text.Split(';'));
                    while (prefixes.Count < citation_cluster.citation_items.Count)
                    {
                        prefixes.Add("");
                    }
                    List <string> suffixes = new List <string>(ObjSuffix.Text.Split(';'));
                    while (suffixes.Count < citation_cluster.citation_items.Count)
                    {
                        suffixes.Add("");
                    }

                    for (int i = 0; i < citation_cluster.citation_items.Count; ++i)
                    {
                        var citation_item = citation_cluster.citation_items[i];

                        // Separate author date?
                        citation_item.SeparateAuthorsAndDate(ObjCheckSeparateAuthorDate.IsChecked ?? false);

                        // Locator on page?
                        citation_item.SetParameter(CitationItem.PARAM_SPECIFIER_TYPE, ObjSpecifierType.Text);
                        citation_item.SetParameter(CitationItem.PARAM_SPECIFIER_LOCATION, specifier_locations[i]);

                        // Prefix/suffix?
                        citation_item.SetParameter(CitationItem.PARAM_PREFIX, prefixes[i]);
                        citation_item.SetParameter(CitationItem.PARAM_SUFFIX, suffixes[i]);
                    }
                }

                // And apply the modified cluster back to Word
                {
                    CitationClusterChanged?.Invoke(citation_cluster);
                }
            }
        }
        private void word_connector_CitationClusterChanged(CitationCluster context_citation_cluster)
        {
            Logging.Debug特("InCite: CitationClusterChanged: {0}", context_citation_cluster);

            Dispatcher.BeginInvoke(new Action(() =>
            {
                ObjCitationClusterEditorControl.SetCitationCluster(context_citation_cluster);
            }
                                              ));
        }
Esempio n. 8
0
        private void word_connector_CitationClusterChanged(CitationCluster context_citation_cluster)
        {
            Logging.Debug特("InCite: CitationClusterChanged: {0}", context_citation_cluster);

            WPFDoEvents.InvokeAsyncInUIThread(() =>
            {
                ObjCitationClusterEditorControl.SetCitationCluster(context_citation_cluster);
            }
                                              );
        }
        internal void ModifyCitation(CitationCluster citation_cluster)
        {
            Field           field;
            CitationCluster currently_selected_citation_cluster;

            GetCurrentlySelectedCitationCluster(out currently_selected_citation_cluster, out field);
            if (null != currently_selected_citation_cluster && currently_selected_citation_cluster.cluster_id == citation_cluster.cluster_id)
            {
                PopulateFieldWithRawCitationCluster(field, citation_cluster);
                word_application.Activate();
            }
            else
            {
                Logging.Warn("Throwing away modified citation cluster because it is no longer selected: " + citation_cluster);
            }
        }
Esempio n. 10
0
        public void FindCitationCluster(CitationCluster target_citation_cluster)
        {
            Document     document = word_application.Selection.Document;
            List <Field> fields   = GetDocumentFields(document);

            foreach (Field field in fields)
            {
                CitationCluster citation_cluster = GenerateCitationClusterFromField(field);
                if (null != citation_cluster)
                {
                    if (citation_cluster.cluster_id == target_citation_cluster.cluster_id)
                    {
                        field.Select();
                        break;
                    }
                }
            }
        }
        private void ButtonNewCitationSeparateAuthorYear_Click(object sender, RoutedEventArgs e)
        {
            FeatureTrackingManager.Instance.UseFeature(Features.InCite_AddNewCitation);

            // Check that they have picked the two important things...
            if (!CheckThatLibraryAndStyleHaveBeenSelected())
            {
                return;
            }

            CitationCluster citation_cluster = GenerateCitationClusterFromCurrentSelection();

            if (null != citation_cluster)
            {
                citation_cluster.citation_items[0].SeparateAuthorsAndDate(true);
                WordConnector.Instance.AppendCitation(citation_cluster);
            }
            e.Handled = true;
        }
Esempio n. 12
0
        private void CheckTheCurrentTextContext()
        {
            string context_word     = null;
            string context_backward = null;
            string context_surround = null;

            CitationCluster context_citation_cluster = null;

            // The textual context
            {
                Selection selection = word_application.Selection;
                if (null != selection)
                {
                    Range range = selection.Range;

                    range.MoveStart(WdUnits.wdWord, -1);
                    range.MoveEnd(WdUnits.wdWord, -1);
                    range.MoveEnd(WdUnits.wdWord, +1);
                    context_word = range.Text;

                    range.MoveStart(WdUnits.wdWord, -9);
                    context_backward = range.Text;

                    range.MoveEnd(WdUnits.wdWord, 9);
                    context_surround = range.Text;

                    //Logging.Info("context_word is    : {0}", context_word);
                    //Logging.Info("context_backward is: {0}", context_backward);
                    //Logging.Info("context_surround is: {0}", context_surround);
                }
            }

            // The citation context
            {
                // First check the selected region
                CitationCluster citation_cluster;
                Field           field;
                GetCurrentlySelectedCitationCluster(out citation_cluster, out field);
                context_citation_cluster = citation_cluster;
            }

            CheckForChangedContexts(context_word, context_backward, context_surround, context_citation_cluster);
        }
Esempio n. 13
0
        internal void RepopulateFromCSLProcessor_SUCCESS(CSLProcessorOutputConsumer ip, CSLProcessor.BrowserThreadPassThru passthru)
        {
            int MAX_DODGY_PASTE_RETRY_COUNT     = 5;
            int DODGY_PASTE_RETRY_SLEEP_TIME_MS = 200;
            int dodgy_paste_retry_count         = 0;

            try
            {
                // Suppress screen updates (for performance reasons)
                repopulating_clusters           = true;
                word_application.ScreenUpdating = false;

                Document document = word_application.Selection.Document;

                // Get all the fields out there
                Logging.Info("+Enumerating all fields");
                List <Field> fields = GetDocumentFields(document);
                Logging.Info("-Enumerating all fields");

                StatusManager.Instance.ClearCancelled("InCite");
                for (int f = 0; f < fields.Count; ++f)
                {
                    if (StatusManager.Instance.IsCancelled("InCite"))
                    {
                        Logging.Info("Updating of citations in Word has been cancelled by the user.");
                        break;
                    }

                    Field field = fields[f];

                    StatusManager.Instance.UpdateStatus("InCite", "Updating InCite fields in Word", f, fields.Count, true);
                    word_application.StatusBar = String.Format("Updating InCite field {0} of {1}...", f, fields.Count);

                    try
                    {
                        // Do we have a citation that we can fill?
                        CitationCluster citation_cluster = GenerateCitationClusterFromField(field);
                        if (null != citation_cluster)
                        {
                            string text_for_cluster = ip.GetTextForCluster(citation_cluster.cluster_id);
                            string rtf_hash         = GenerateRTFHash(passthru.is_note_format, text_for_cluster);

                            // Update this citation cluster only if it needs updating (if it has changed from what is currently stored in it)
                            if (!String.IsNullOrEmpty(text_for_cluster))
                            {
                                bool needs_update = false;

                                if (!needs_update)
                                {
                                    if (rtf_hash != citation_cluster.rtf_hash)
                                    {
                                        needs_update = true;
                                    }
                                }

                                if (!needs_update)
                                {
                                    string current_field_contents = field.Result.Text;
                                    if (current_field_contents.Contains("QIQQA"))
                                    {
                                        needs_update = true;
                                    }
                                }

                                if (needs_update)
                                {
                                    // Update the field with the new hash
                                    citation_cluster.rtf_hash = rtf_hash;
                                    PopulateFieldWithRawCitationCluster(field, citation_cluster);

                                    // Remember the font
                                    string font_name = field.Result.Font.Name;
                                    float  font_size = field.Result.Font.Size;

                                    string rtf = RTF_START + text_for_cluster + RTF_END;
                                    ClipboardTools.SetText(rtf, TextDataFormat.Rtf);

                                    if (passthru.is_note_format)
                                    {
                                        field.Result.Text = "";
                                        Footnote footnote = field.Result.Footnotes.Add(field.Result);
                                        footnote.Range.Text = " ";
                                        Range range = footnote.Range;
                                        range.Collapse(WdCollapseDirection.wdCollapseStart);
                                        range.PasteSpecial(DataType: WdPasteDataType.wdPasteRTF);
                                        footnote.Range.Font.Name = font_name;
                                        footnote.Range.Font.Size = font_size;
                                    }
                                    else
                                    {
                                        field.Result.Text = " ";
                                        Range range = field.Result;
                                        range.Collapse(WdCollapseDirection.wdCollapseStart);
                                        range.PasteSpecial(DataType: WdPasteDataType.wdPasteRTF);
                                        field.Result.Text      = field.Result.Text.Trim();
                                        field.Result.Font.Name = font_name;
                                        field.Result.Font.Size = font_size;
                                    }
                                }
                            }
                            else
                            {
                                citation_cluster.rtf_hash = rtf_hash;
                                PopulateFieldWithRawCitationCluster(field, citation_cluster);
                                field.Result.Text = String.Format("ERROR: Unable to find key {0} in the CSL output.", citation_cluster.cluster_id);
                            }

                            // If we get here, it must have worked!
                            dodgy_paste_retry_count = 0;

                            continue;
                        }

                        // Do we have a bibliography that we can fill?
                        if (IsFieldBibliography(field))
                        {
                            // Remember the font
                            string font_name = field.Result.Font.Name;
                            float  font_size = field.Result.Font.Size;

                            string formatted_bibliography_section = ip.GetFormattedBibliographySection();
                            if (String.IsNullOrEmpty(formatted_bibliography_section))
                            {
                                formatted_bibliography_section = "Either this CSL citation style does not produce a bibliography section or you have not yet added any citations to this document, so this bibliography is empty.";
                            }

                            string formatted_bibliography_section_wrapped = CSLProcessorOutputConsumer.RTF_START + formatted_bibliography_section + CSLProcessorOutputConsumer.RTF_END;

                            ClipboardTools.SetText(formatted_bibliography_section_wrapped, TextDataFormat.Rtf);

                            field.Result.Text = " ";
                            Range range = field.Result;
                            range.Collapse(WdCollapseDirection.wdCollapseStart);
                            range.PasteSpecial(DataType: WdPasteDataType.wdPasteRTF);
                            field.Result.Font.Name = font_name;
                            field.Result.Font.Size = font_size;

                            // If we get here, it must have worked!
                            dodgy_paste_retry_count = 0;

                            continue;
                        }

                        // Do we have a CSL stats region?
                        if (IsFieldCSLStats(field))
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.Append(RTF_START);
                            {
                                sb.AppendFormat("maxoffset={0}\\line\n", ip.max_offset);
                                sb.AppendFormat("entryspacing={0}\\line\n", ip.entry_spacing);
                                sb.AppendFormat("linespacing={0}\\line\n", ip.line_spacing);
                                sb.AppendFormat("hangingindent={0}\\line\n", ip.hanging_indent);
                                sb.AppendFormat("second_field_align={0}\\line\n", ip.second_field_align);
                            }
                            sb.Append(RTF_END);

                            Clipboard.SetText(sb.ToString(), TextDataFormat.Rtf);

                            field.Result.Text = " ";
                            Range range = field.Result;
                            range.Collapse(WdCollapseDirection.wdCollapseStart);
                            range.PasteSpecial(DataType: WdPasteDataType.wdPasteRTF);

                            // If we get here, it must have worked!
                            dodgy_paste_retry_count = 0;

                            continue;
                        }
                    }
                    catch (Exception ex)
                    {
                        ++dodgy_paste_retry_count;
                        if (dodgy_paste_retry_count < MAX_DODGY_PASTE_RETRY_COUNT)
                        {
                            Logging.Warn(ex, "Will try again (try {0}) because there was a problem updating a citation field: {1}", dodgy_paste_retry_count, field.Result.Text);

                            // Back up one field so we can try again
                            Thread.Sleep(DODGY_PASTE_RETRY_SLEEP_TIME_MS);
                            --f;
                            continue;
                        }
                        else
                        {
                            Logging.Error(ex, "Giving up because there was a problem updating a citation field: {0}", field.Result.Text);
                            dodgy_paste_retry_count = 0;
                            continue;
                        }
                    }
                }
            }
            finally
            {
                // Restore the screen updates
                repopulating_clusters           = false;
                word_application.ScreenUpdating = true;
                word_application.StatusBar      = "Updated InCite fields.";
            }
        }
        private static void Translate_CitationCluster(StringBuilder sb, CitationCluster citation_cluster, bool suppress_author, bool suppress_date)
        {
            sb.AppendLine("{");
            sb.AppendLine(String.Format("  \"citationID\": \"{0}\",", citation_cluster.cluster_id));
            sb.AppendLine("  \"citationItems\": [");
            bool is_additional_citation_item = false;

            foreach (CitationItem citation_item in citation_cluster.citation_items)
            {
                if (is_additional_citation_item)
                {
                    sb.AppendLine("    ,");
                }
                else
                {
                    is_additional_citation_item = true;
                }

                sb.AppendLine("    {");
                sb.AppendLine("      \"id\": \"" + citation_item.reference_key + "\"");

                if (suppress_author)
                {
                    sb.AppendLine("     ,\"suppress-author\": 1");
                }

                if (suppress_date)
                {
                    sb.AppendLine("     ,\"author-only\": 1");
                }

                string param_specifier_type = citation_item.GetParameter(CitationItem.PARAM_SPECIFIER_TYPE);
                if (!String.IsNullOrEmpty(param_specifier_type))
                {
                    string param_specifier_location = citation_item.GetParameter(CitationItem.PARAM_SPECIFIER_LOCATION);
                    sb.AppendFormat("     ,\"label\": \"{0}\"\n", param_specifier_type);
                    sb.AppendFormat("     ,\"locator\": \"{0}\"\n", param_specifier_location);
                }

                // Prefix and suffix
                {
                    string prefix = citation_item.GetParameter(CitationItem.PARAM_PREFIX);
                    if (!String.IsNullOrEmpty(prefix))
                    {
                        sb.AppendFormat("     ,\"prefix\": \"{0}\"\n", prefix);
                    }
                    string suffix = citation_item.GetParameter(CitationItem.PARAM_SUFFIX);
                    if (!String.IsNullOrEmpty(suffix))
                    {
                        sb.AppendFormat("     ,\"suffix\": \"{0}\"\n", suffix);
                    }
                }

                sb.AppendLine("    }");
            }

            sb.AppendLine("  ],");
            sb.AppendLine("  \"properties\": {");
            sb.AppendLine("    \"noteIndex\": 1");
            sb.AppendLine("  }");
            sb.AppendLine("}");
        }
 internal void SetCitationCluster(CitationCluster citation_cluster)
 {
     current_citation_cluster = citation_cluster;
     ReflectCitationCluster(current_citation_cluster);
 }
        private void ReflectCitationCluster(CitationCluster current_citation_cluster)
        {
            if (null == current_citation_cluster)
            {
                this.IsEnabled = false;
                this.ObjGridNoCitationSelectedInstructions.Visibility = Visibility.Visible;
                this.ObjGridNoCitationSelectedInstructions.Background = ThemeColours.Background_Brush_Blue_Dark;
                //this.ObjGridCitationSelectedPanel.Visibility = Visibility.Collapsed;

                ObjCitationsInCluster.ItemsSource    = null;
                ObjCheckSeparateAuthorDate.IsChecked = false;
                ObjSpecifierType.Text     = "";
                ObjSpecifierLocation.Text = "";
                ObjPrefix.Text            = "";
                ObjSuffix.Text            = "";
            }
            else
            {
                this.IsEnabled = true;
                this.ObjGridNoCitationSelectedInstructions.Visibility = Visibility.Collapsed;
                //this.ObjGridCitationSelectedPanel.Visibility = Visibility.Visible;

                // Populate the list of items
                ObservableCollection <string> citation_item_keys = new ObservableCollection <string>();
                foreach (var citation_item in current_citation_cluster.citation_items)
                {
                    citation_item_keys.Add(citation_item.reference_key);
                }
                ObjCitationsInCluster.ItemsSource = citation_item_keys;

                // Populate the options - we only use the first item's stuff...
                if (0 < current_citation_cluster.citation_items.Count)
                {
                    CitationItem citation_item = current_citation_cluster.citation_items[0];

                    // Separate author date?
                    string separate_author_date = citation_item.GetParameter(CitationItem.PARAM_SEPARATE_AUTHOR_DATE);
                    ObjCheckSeparateAuthorDate.IsChecked = (CitationItem.OPTION_SEPARATE_AUTHOR_DATE_TRUE == separate_author_date);

                    // Locator type?
                    string specifier_type = citation_item.GetParameter(CitationItem.PARAM_SPECIFIER_TYPE);
                    ObjSpecifierType.Text = specifier_type;

                    // For the actual specifier, lets allow multiple selections
                    string specifier_locations = "";
                    string prefixes            = "";
                    string suffixes            = "";
                    for (int i = 0; i < current_citation_cluster.citation_items.Count; ++i)
                    {
                        specifier_locations = specifier_locations + current_citation_cluster.citation_items[i].GetParameter(CitationItem.PARAM_SPECIFIER_LOCATION) + ";";
                        prefixes            = prefixes + current_citation_cluster.citation_items[i].GetParameter(CitationItem.PARAM_PREFIX) + ";";
                        suffixes            = suffixes + current_citation_cluster.citation_items[i].GetParameter(CitationItem.PARAM_SUFFIX) + ";";
                    }
                    specifier_locations       = specifier_locations.TrimEnd(';');
                    prefixes                  = prefixes.TrimEnd(';');
                    suffixes                  = suffixes.TrimEnd(';');
                    ObjSpecifierLocation.Text = specifier_locations;
                    ObjPrefix.Text            = prefixes;
                    ObjSuffix.Text            = suffixes;
                }
            }
        }
Esempio n. 17
0
 private static void PopulateFieldWithRawCitationCluster(Field field, CitationCluster citation_cluster)
 {
     citation_cluster.rtf_hash = null;
     field.Code.Text           = citation_cluster.ToCodedString();
     field.Result.Text         = citation_cluster.GetBibTeXKeySummary();
 }
        public static CitationCluster GenerateCitationClusterFromPDFDocuments(List <PDFDocument> selected_pdf_documents)
        {
            foreach (PDFDocument pdf_document in selected_pdf_documents)
            {
                pdf_document.DateLastCited = DateTime.UtcNow;
            }

            // Check if any of these documents have duplicated BibTeX keys...
            foreach (PDFDocument pdf_document in selected_pdf_documents)
            {
                string key = pdf_document.BibTexKey;
                if (!String.IsNullOrEmpty(key))
                {
                    foreach (PDFDocument pdf_document_other in pdf_document.Library.PDFDocuments)
                    {
                        if (pdf_document_other != pdf_document)
                        {
                            if (!String.IsNullOrEmpty(pdf_document_other.BibTex) && pdf_document_other.BibTex.Contains(key))
                            {
                                if (pdf_document_other.BibTexKey == key)
                                {
                                    MessageBoxes.Warn(String.Format("There are several document in your library with the same BibTeX key '{0}'.  Unless they are the same PDF, you should give them different keys or else InCite will just pick the first matching document.", key));
                                }
                            }
                        }
                    }
                }
            }

            // Check if any of these documents have no BibTeX key...
            foreach (PDFDocument pdf_document in selected_pdf_documents)
            {
                string key = pdf_document.BibTexKey;
                if (String.IsNullOrEmpty(key))
                {
                    MessageBoxes.Warn(String.Format("Some of your documents (e.g. with title, '{0}') have no BibTeX key.  Without a unique BibTeX key, Qiqqa has no way of referencing this document from Word, and they will show up in Word as either [ ] or a blank when you wave the magic wand.  Please add any missing keys and try again!", pdf_document.TitleCombined));
                }
            }

            if (0 < selected_pdf_documents.Count)
            {
                CitationCluster cc = new CitationCluster();
                foreach (PDFDocument selected_pdf_document in selected_pdf_documents)
                {
                    string reference_key = selected_pdf_document.BibTexKey;
                    if (null != reference_key)
                    {
                        string       reference_library = selected_pdf_document.Library.WebLibraryDetail.Id;
                        CitationItem ci = new CitationItem(reference_key, reference_library);
                        cc.citation_items.Add(ci);
                    }
                    else
                    {
                        MessageBoxes.Warn("Could not add document '{0}' because it doesn't have valid BibTeX or a valid BibTeX key.", selected_pdf_document.TitleCombined);
                    }
                }

                return(cc);
            }

            MessageBoxes.Warn("You have not selected any document(s) to cite.");
            return(null);
        }
        private void ObjCitationClusterEditorControl_CitationClusterChanged(CitationCluster citation_cluster)
        {
            FeatureTrackingManager.Instance.UseFeature(Features.InCite_EditCitationCluster);

            WordConnector.Instance.ModifyCitation(citation_cluster);
        }