/// <summary> /// Gets all books that need to be deleted. /// </summary> private IEnumerable <int> GetBooksToDelete(TextType textType, IEnumerable <int> existingBooks) { string projectPath = GetProjectPath(textType); var booksToDelete = new HashSet <int>(_fileSystemService.DirectoryExists(projectPath) ? _fileSystemService.EnumerateFiles(projectPath) .Select(p => Canon.BookIdToNumber(Path.GetFileNameWithoutExtension(p))) : Enumerable.Empty <int>()); booksToDelete.ExceptWith(existingBooks); return(booksToDelete); }
public void ParseChapterVerseLine() { versification.ParseChapterVerseLine("HAB 1:17 2:20 3:19"); int bookId = Canon.BookIdToNumber("HAB"); List <int[]> bookList = versification.bookList(); Assert.AreEqual(bookList.Count, bookId); Assert.AreEqual(bookList[bookId - 1], new [] { 17, 20, 19 }); Assert.AreEqual(bookId, versification.GetLastBook(), "HAB should be the last book in the versification"); Assert.AreEqual(3, versification.GetLastChapter(bookId), "HAB has three chapters"); Assert.AreEqual(17, versification.GetLastVerse(bookId, 1), "HAB 1 has 17 verses"); Assert.AreEqual(20, versification.GetLastVerse(bookId, 2), "HAB 2 has 20 verses"); Assert.AreEqual(19, versification.GetLastVerse(bookId, 3), "HAB 3 has 19 verses"); }
public void ProcessVersLine_Custom_ChapterRemoved() { versification.ProcessVersLine("HAB 1:17 2:20 3:19"); // Add a custom line that updates the original chapter-verse versification for Habakkuk versification.ProcessVersLine("HAB 2:0"); // Confirm that the custom versification overrides the original int bookId = Canon.BookIdToNumber("HAB"); List <int[]> bookList = versification.bookList(); Assert.AreEqual(bookList.Count, bookId); Assert.AreEqual(bookList[bookId - 1], new int[] { 17, 0, 19 }); Assert.AreEqual(3, versification.GetLastChapter(bookId), "The customized version of HAB should still have three chapters"); Assert.AreEqual(17, versification.GetLastVerse(bookId, 1)); Assert.AreEqual(0, versification.GetLastVerse(bookId, 2)); Assert.AreEqual(19, versification.GetLastVerse(bookId, 3)); }
public void ProcessVersLine_Custom_SingleChapter() { versification.ProcessVersLine("HAB 1:17 2:20 3:19"); // Add a custom line that updates a single chapter in Habakkuk versification.ProcessVersLine("HAB 2:55"); // Confirm that the custom versification overrides the original int bookId = Canon.BookIdToNumber("HAB"); List <int[]> bookList = versification.bookList(); Assert.AreEqual(bookList.Count, bookId); Assert.AreEqual(bookList[bookId - 1], new int[] { 17, 55, 19 }); Assert.AreEqual(3, versification.GetLastChapter(bookId), "The customized version of HAB should have three chapters"); Assert.AreEqual(17, versification.GetLastVerse(bookId, 1), "Custom HAB 1 has 17 verses"); Assert.AreEqual(55, versification.GetLastVerse(bookId, 2), "Custom HAB 2 has 55 verses"); Assert.AreEqual(19, versification.GetLastVerse(bookId, 3), "Custom HAB 3 has 19 verses"); }
public void ProcessVersLine_Custom_ChapterVerseUpdated() { versification.ProcessVersLine("HAB 1:17 2:20 3:19"); // Add a custom line that updates the original chapter-verse versification for Habakkuk versification.ProcessVersLine("HAB 1:15 2:13 3:22 4:21"); // Confirm that the custom versification overrides the original int bookId = Canon.BookIdToNumber("HAB"); List <int[]> bookList = versification.bookList(); Assert.AreEqual(bookList.Count, bookId); Assert.AreEqual(bookList[bookId - 1], new int[] { 15, 13, 22, 21 }); Assert.AreEqual(4, versification.GetLastChapter(bookId), "The customized version of HAB should have four chapters"); Assert.AreEqual(15, versification.GetLastVerse(bookId, 1), "Custom HAB 1 has 15 verses"); Assert.AreEqual(13, versification.GetLastVerse(bookId, 2), "Custom HAB 2 has 13 verses"); Assert.AreEqual(22, versification.GetLastVerse(bookId, 3), "Custom HAB 3 has 22 verses"); Assert.AreEqual(21, versification.GetLastVerse(bookId, 4), "Custom HAB 4 has 21 verses"); }
public void RemoveAllUnknownVersifications() { Assert.IsFalse(Versification.Table.Implementation.Exists("ModifiedRuth")); using (TextReader reader = new StringReader("RUT 5:91")) Versification.Table.Implementation.Load(reader, "", ScrVers.English, "ModifiedRuth"); Assert.IsTrue(Versification.Table.Implementation.Exists("ModifiedRuth")); ScrVers modRuth = new ScrVers("ModifiedRuth"); Assert.AreEqual(5, modRuth.GetLastChapter(Canon.BookIdToNumber("RUT"))); Assert.AreEqual(91, modRuth.GetLastVerse(Canon.BookIdToNumber("RUT"), 5)); Versification.Table.Implementation.RemoveAllUnknownVersifications(); Assert.IsFalse(Versification.Table.Implementation.Exists("ModifiedRuth")); modRuth = new ScrVers("ModifiedRuth"); Assert.AreEqual(4, modRuth.GetLastChapter(Canon.BookIdToNumber("RUT"))); Assert.AreEqual(22, modRuth.GetLastVerse(Canon.BookIdToNumber("RUT"), 4)); }
public void ProcessVersLine_Custom_ChapterNotInOriginal() { versification.ProcessVersLine("HAB 1:17 2:20 3:19"); // Add a custom line that updates the original chapter-verse versification for Habakkuk versification.ProcessVersLine("HAB 7:55"); // Confirm that the custom versification overrides the original int bookId = Canon.BookIdToNumber("HAB"); List <int[]> bookList = versification.bookList(); Assert.AreEqual(bookList.Count, bookId); Assert.AreEqual(bookList[bookId - 1], new int[] { 17, 20, 19, 1, 1, 1, 55 }); Assert.AreEqual(7, versification.GetLastChapter(bookId)); Assert.AreEqual(17, versification.GetLastVerse(bookId, 1)); Assert.AreEqual(20, versification.GetLastVerse(bookId, 2)); Assert.AreEqual(19, versification.GetLastVerse(bookId, 3)); Assert.AreEqual(1, versification.GetLastVerse(bookId, 4)); Assert.AreEqual(1, versification.GetLastVerse(bookId, 5)); Assert.AreEqual(1, versification.GetLastVerse(bookId, 6)); Assert.AreEqual(55, versification.GetLastVerse(bookId, 7)); }
static void Main(string[] args) { if (args.Length < 2 || args.Length > 3) { BadArguments(); } if (args.Length == 3 && args[0] != "-usfm2") { BadArguments(); } int bookArg = args.Length == 2 ? 0 : 1; int bookNum = Canon.BookIdToNumber(args[bookArg]); if (bookNum <= 0) { BadArguments(); } string textFile = args[bookArg + 1]; if (!File.Exists(textFile)) { BadArguments(); } // allow USFM 3 markers to be used if not turned off MarkerCheck check = new MarkerCheck(args.Length == 2); if (check.Run(bookNum, File.ReadAllText(textFile))) { Console.WriteLine("MarkerCheck: file had errors"); Environment.Exit(1); } }
/// <summary> /// Processes a single token /// </summary> /// <returns>false if there were no more tokens process</returns> public bool ProcessToken() { // If past end if (index >= tokens.Count - 1) { return(false); } // Move to next token index++; // Update verse offset with previous token (since verse offset is from start of current token) if (index > 0) { State.VerseOffset += tokens[index - 1].GetLength(false, !tokensPreserveWhitespace); } // Skip over tokens that are to be skipped, ensuring that // SpecialToken state is true. if (skip > 0) { skip--; State.SpecialToken = true; return(true); } // Reset special token and figure status State.SpecialToken = false; UsfmToken token = tokens[index]; // Switch unknown types to either character or paragraph UsfmTokenType tokenType = token.Type; if (tokenType == UsfmTokenType.Unknown) { tokenType = DetermineUnknownTokenType(); } if (sink != null && !string.IsNullOrEmpty(token.Marker)) { sink.GotMarker(State, token.Marker); } // Close open elements switch (tokenType) { case UsfmTokenType.Book: case UsfmTokenType.Chapter: CloseAll(); break; case UsfmTokenType.Paragraph: // Handle special case of table rows if (token.Marker == "tr") { // Close all but table and sidebar while (State.Stack.Count > 0 && Peek().Type != UsfmElementTypes.Table && Peek().Type != UsfmElementTypes.Sidebar) { CloseElement(); } break; } // Handle special case of sidebars if (token.Marker == "esb") { // Close all CloseAll(); break; } // Close all but sidebar while (State.Stack.Count > 0 && Peek().Type != UsfmElementTypes.Sidebar) { CloseElement(); } break; case UsfmTokenType.Character: // Handle special case of table cell if (IsCell(token)) { // Close until row while (Peek().Type != UsfmElementTypes.Row) { CloseElement(); } break; } // Handle refs if (IsRef(token)) { // Refs don't close anything break; } // If non-nested character style, close all character styles if (!token.Marker.StartsWith("+")) { CloseCharStyles(); } break; case UsfmTokenType.Verse: CloseNote(); break; case UsfmTokenType.Note: CloseNote(); break; case UsfmTokenType.End: // If end marker for an active note if (State.Stack.Exists(e => e.Type == UsfmElementTypes.Note && (e.Marker + "*" == token.Marker))) { CloseNote(); break; } // If end marker for a character style on stack, close it // If no matching end marker, close all character styles on top of stack UsfmParserElement elem; bool unmatched = true; while (State.Stack.Count > 0) { elem = Peek(); if (elem.Type != UsfmElementTypes.Char) { break; } CloseElement(); // Determine if a + prefix is needed to close it (was nested char style) bool plusPrefix = (State.Stack.Count > 0 && Peek().Type == UsfmElementTypes.Char); // If is a match if ((plusPrefix ? "+" : "") + elem.Marker + "*" == token.Marker) { unmatched = false; break; } } // Unmatched end marker if (unmatched) { if (sink != null) { sink.Unmatched(State, token.Marker); } } break; } // Handle tokens switch (tokenType) { case UsfmTokenType.Book: State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Book, token.Marker)); // Code is always upper case string code = token.Data[0].ToUpperInvariant(); // Update verse ref. Leave book alone if not empty to prevent parsing errors // on books with bad id lines. if (State.VerseRef.Book == "" && Canon.BookIdToNumber(code) != 0) { State.VerseRef.Book = code; } State.VerseRef.ChapterNum = 1; State.VerseRef.VerseNum = 0; State.VerseOffset = 0; // Book start. if (sink != null) { sink.StartBook(State, token.Marker, code); } break; case UsfmTokenType.Chapter: // Get alternate chapter number string altChapter = null; string pubChapter = null; if (!InventoryMode) { if (index < tokens.Count - 3 && tokens[index + 1].Marker == "ca" && tokens[index + 2].Text != null && tokens[index + 3].Marker == "ca*") { altChapter = tokens[index + 2].Text.Trim(); skip += 3; // Skip blank space after if present if (index + skip < tokens.Count - 1 && tokens[index + skip + 1].Text != null && tokens[index + skip + 1].Text.Trim().Length == 0) { skip++; } } // Get publishable chapter number if (index + skip < tokens.Count - 2 && tokens[index + skip + 1].Marker == "cp" && tokens[index + skip + 2].Text != null) { pubChapter = tokens[index + skip + 2].Text.Trim(); skip += 2; } } // Chapter State.VerseRef.Chapter = token.Data[0]; State.VerseRef.VerseNum = 0; // Verse offset is not zeroed for chapter 1, as it is part of intro if (State.VerseRef.ChapterNum != 1) { State.VerseOffset = 0; } if (sink != null) { sink.Chapter(State, token.Data[0], token.Marker, altChapter, pubChapter); } break; case UsfmTokenType.Verse: string pubVerse = null; string altVerse = null; if (!InventoryMode) { if (index < tokens.Count - 3 && tokens[index + 1].Marker == "va" && tokens[index + 2].Text != null && tokens[index + 3].Marker == "va*") { // Get alternate verse number altVerse = tokens[index + 2].Text.Trim(); skip += 3; } if (index + skip < tokens.Count - 3 && tokens[index + skip + 1].Marker == "vp" && tokens[index + skip + 2].Text != null && tokens[index + skip + 3].Marker == "vp*") { // Get publishable verse number pubVerse = tokens[index + skip + 2].Text.Trim(); skip += 3; } } // Verse State.VerseRef.Verse = token.Data[0]; State.VerseOffset = 0; if (sink != null) { sink.Verse(State, token.Data[0], token.Marker, altVerse, pubVerse); } break; case UsfmTokenType.Paragraph: // Handle special case of table rows if (token.Marker == "tr") { // Start table if not open if (State.Stack.TrueForAll(e => e.Type != UsfmElementTypes.Table)) { State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Table, null)); if (sink != null) { sink.StartTable(State); } } State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Row, token.Marker)); // Row start if (sink != null) { sink.StartRow(State, token.Marker); } break; } // Handle special case of sidebars if (token.Marker == "esb") { bool isClosed = IsStudyBibleItemClosed("esb", "esbe"); // TODO - see FB 23934 // Would like to only add start sidebar if it is closed - adding unclosed marker will cause // an end marker to be created in an unexpected place in the editor. // if (isClosed) State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Sidebar, token.Marker)); // Look for category string sidebarCategory = null; if (index < tokens.Count - 3 && tokens[index + 1].Marker == "cat" && tokens[index + 2].Text != null && tokens[index + 3].Marker == "cat*") { // Get category sidebarCategory = tokens[index + 2].Text.Trim(); skip += 3; } if (sink != null) { sink.StartSidebar(State, token.Marker, sidebarCategory, isClosed); } break; } // Close sidebar if in sidebar if (token.Marker == "esbe") { if (State.Stack.Exists(e => e.Type == UsfmElementTypes.Sidebar)) { CloseAll(); } else if (sink != null) { sink.Unmatched(State, token.Marker); } break; } State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Para, token.Marker)); // Paragraph opening if (sink != null) { sink.StartPara(State, token.Marker, token.Type == UsfmTokenType.Unknown); } break; case UsfmTokenType.Character: // Handle special case of table cells (treated as special character style) if (IsCell(token)) { string align = "start"; if (token.Marker.Length > 2 && token.Marker[2] == 'c') { align = "center"; } else if (token.Marker.Length > 2 && token.Marker[2] == 'r') { align = "end"; } State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Cell, token.Marker)); if (sink != null) { sink.StartCell(State, token.Marker, align); } break; } if (IsRef(token)) { // xrefs are special tokens (they do not stand alone) State.SpecialToken = true; string display; string target; ParseDisplayAndTarget(out display, out target); skip += 2; if (sink != null) { sink.Ref(State, token.Marker, display, target); } break; } string actualMarker; bool invalidMarker = false; if (token.Marker.StartsWith("+")) { // Only strip + if properly nested actualMarker = state.CharTag != null?token.Marker.TrimStart('+') : token.Marker; invalidMarker = state.CharTag == null; } else { actualMarker = token.Marker; } State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Char, actualMarker, tokens[index].Attributes)); if (sink != null) { bool charIsClosed = IsTokenClosed(); State.Stack.Last().IsClosed = charIsClosed; // save for attribute check in Text method sink.StartChar(State, actualMarker, charIsClosed, token.Type == UsfmTokenType.Unknown || invalidMarker, tokens[index].Attributes); } break; case UsfmTokenType.Note: // Look for category string noteCategory = null; if (index < tokens.Count - 3 && tokens[index + 1].Marker == "cat" && tokens[index + 2].Text != null && tokens[index + 3].Marker == "cat*") { // Get category noteCategory = tokens[index + 2].Text.Trim(); skip += 3; } State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Note, token.Marker)); if (sink != null) { sink.StartNote(State, token.Marker, token.Data[0], noteCategory, IsTokenClosed()); } break; case UsfmTokenType.Text: string text = token.Text; // If last token before a paragraph, book or chapter, esb, esbe (both are paragraph types), // or at very end, strip final space // This is because USFM requires these to be on a new line, therefore adding whitespace if ((index == tokens.Count - 1 || tokens[index + 1].Type == UsfmTokenType.Paragraph || tokens[index + 1].Type == UsfmTokenType.Book || tokens[index + 1].Type == UsfmTokenType.Chapter) && text.Length > 0 && text[text.Length - 1] == ' ') { text = text.Substring(0, text.Length - 1); } if (sink != null) { // Replace ~ with nbsp text = text.Replace('~', '\u00A0'); // Replace // with <optbreak/> foreach (string str in optBreakSplitter.Split(text)) { if (str == "//") { sink.OptBreak(state); } else { sink.Text(state, str); } } } break; case UsfmTokenType.Milestone: case UsfmTokenType.MilestoneEnd: // currently, parse state doesn't need to be update, so just inform the sink about the milestone. sink?.Milestone(state, token.Marker, token.Type == UsfmTokenType.Milestone, token.Attributes); break; } return(true); }
public async Task RunAsync(string projectId, string userId, bool trainEngine) { try { if (!await InitAsync(projectId, userId)) { await CompleteSync(false); return; } string targetParatextId = _projectDoc.Data.ParatextId; string sourceParatextId = _projectDoc.Data.TranslateConfig.Source?.ParatextId; var targetBooks = new HashSet <int>((await _paratextService.GetBooksAsync(_userSecret, targetParatextId)).Select(bookId => Canon.BookIdToNumber(bookId))); var sourceBooks = new HashSet <int>(TranslationSuggestionsEnabled ? (await _paratextService.GetBooksAsync(_userSecret, sourceParatextId)) .Select(bookId => Canon.BookIdToNumber(bookId)) : Enumerable.Empty <int>()); sourceBooks.IntersectWith(targetBooks); var targetBooksToDelete = new HashSet <int>(GetBooksToDelete(TextType.Target, targetBooks)); var sourceBooksToDelete = new HashSet <int>(TranslationSuggestionsEnabled ? GetBooksToDelete(TextType.Source, sourceBooks) : Enumerable.Empty <int>()); _step = 0; _stepCount = (targetBooks.Count * (CheckingEnabled ? 3 : 2)) + (sourceBooks.Count * 2); if (targetBooksToDelete.Count > 0 || sourceBooksToDelete.Count > 0) { _stepCount += 1; // delete source books foreach (int bookNum in sourceBooksToDelete) { TextInfo text = _projectDoc.Data.Texts.First(t => t.BookNum == bookNum); await DeleteAllTextDataForBookAsync(text, TextType.Source); } // delete target books foreach (int bookNum in targetBooksToDelete) { int textIndex = _projectDoc.Data.Texts.FindIndex(t => t.BookNum == bookNum); TextInfo text = _projectDoc.Data.Texts[textIndex]; await _projectDoc.SubmitJson0OpAsync(op => op.Remove(pd => pd.Texts, textIndex)); await DeleteAllTextDataForBookAsync(text, TextType.Target); await DeleteAllQuestionsDocsForBookAsync(text); } await UpdateProgress(); } // sync source and target books foreach (int bookNum in targetBooks) { bool hasSource = sourceBooks.Contains(bookNum); int textIndex = _projectDoc.Data.Texts.FindIndex(t => t.BookNum == bookNum); TextInfo text; if (textIndex == -1) { text = new TextInfo { BookNum = bookNum, HasSource = hasSource } } ; else { text = _projectDoc.Data.Texts[textIndex]; } List <Chapter> newChapters = await SyncOrCloneBookUsxAsync(text, TextType.Target, targetParatextId, false); if (newChapters != null) { if (hasSource) { var chaptersToInclude = new HashSet <int>(newChapters.Select(c => c.Number)); await SyncOrCloneBookUsxAsync(text, TextType.Source, sourceParatextId, true, chaptersToInclude); } await UpdateNotesData(text, newChapters); await _projectDoc.SubmitJson0OpAsync(op => { if (textIndex == -1) { // insert text info for new text text.Chapters = newChapters; op.Add(pd => pd.Texts, text); } else { // update text info op.Set(pd => pd.Texts[textIndex].Chapters, newChapters, ChapterListEqualityComparer); op.Set(pd => pd.Texts[textIndex].HasSource, hasSource); } }); } } if (TranslationSuggestionsEnabled && trainEngine) { // start training Machine engine await _engineService.StartBuildByProjectIdAsync(projectId); } await CompleteSync(true); } catch (Exception e) { _logger.LogError(e, "Error occurred while executing Paratext sync for project '{Project}'", projectId); await CompleteSync(false); } finally { CloseConnection(); } }
public IEnumerable <string> GetCheckFailuresForBook(string bookId) { return(m_bookInfo.GetFailedChecks(Canon.BookIdToNumber(bookId))); }
internal ParatextUsxBookList GetUsxDocumentsForIncludedParatextBooks(ISet <int> subset = null) { // Getting the checksum and the checking status at the same time and returning them together ensures that they are really // in sync, rather than relying on the caller to get them at the same time. var list = new ParatextUsxBookList(); foreach (var bookNum in GlyssenDblTextMetadata.AvailableBooks.Where(ab => ab.IncludeInScript).Select(ib => Canon.BookIdToNumber(ib.Code))) { if (subset != null && !subset.Contains(bookNum)) { continue; } list.Add(bookNum, GetUsxDocumentForBook(bookNum), UnderlyingScrText.GetBookCheckSum(bookNum), m_bookInfo.GetState(bookNum) == ParatextProjectBookInfo.BookState.NoProblem); } return(list); }
/// <summary> /// This method should be used any time the user takes an action that would result in marking a book /// for inclusion in the project. (It does not need to be called when a book is being removed.) /// Currently, this can be either when they click a check-box for an individual book or when they use one of /// the "select all" menu items. There are several quick-return paths, but in the "interesting" case, /// the purpose of this method is to check whether the book in question is currently in a state (as reported /// by Paratext) where the required basic checks all pass. If not, the user needs to confirm that they indeed /// wish to include the book and thus override this requirement. /// </summary> /// <param name="grid">Either the OT grid or the NT grid</param> /// <param name="rowIndex">The row index in the grid also corresponds to an entry in the available OT or /// NT books list.</param> /// <returns></returns> private bool IsValidToIncludeBook(DataGridView grid, int rowIndex) { if (!m_project.IsLiveParatextProject) { return(true); } var books = grid.Equals(m_otBooksGrid) ? m_availableOtBooks : m_availableNtBooks; var book = books[rowIndex]; if (book.IncludeInScript) { return(true); // Always valid to exclude } var bookCode = book.Code; if (m_project.DoesBookScriptFileExist(bookCode)) { return(true); // Might try to get an updated version later but this one is valid. } GetParatextScrTextWrapperIfNeeded(); var bookNum = Canon.BookIdToNumber(bookCode); if (!m_paratextScrTextWrapper.CanonicalBookNumbersInProject.Contains(bookNum)) { ReportParatextBookNoLongerAvailable(bookCode); grid.CurrentRow.DefaultCellStyle.ForeColor = GlyssenColorPalette.ColorScheme.Warning; return(false); } else if (grid.CurrentRow.DefaultCellStyle.ForeColor == GlyssenColorPalette.ColorScheme.Warning) { grid.CurrentRow.DefaultCellStyle.ForeColor = grid.DefaultCellStyle.ForeColor; } if (m_paratextScrTextWrapper.DoesBookPassChecks(bookNum, true)) { return(true); } var failureMessage = Format(LocalizationManager.GetString("DialogBoxes.ScriptureRangeSelectionDlg.FailedChecksForBook", "{0} is not reporting a current successful status for {1} in project {2} for the following basic checks " + "that {3} usually requires to pass:\r\n{4}", "Param 0: \")Paratext\" (product name); " + "Param 1: 3-letter Scripture book code; " + "Param 2: Paratext project short name (unique project identifier); " + "Param 3: \"Glyssen\" (product name); " + "Param 4: List of failing Paratext check names"), ParatextScrTextWrapper.kParatextProgramName, bookCode, m_project.ParatextProjectName, GlyssenInfo.kProduct, Join(", ", m_paratextScrTextWrapper.GetCheckFailuresForBook(bookCode))); var msg = failureMessage + Environment.NewLine + Environment.NewLine + Format(LocalizationManager.GetString("DialogBoxes.ScriptureRangeSelectionDlg.ConfirmInclusionOfParatextBookThatDoesNotPassChecks", "Depending on the specific errors, {0} might fail to process the data for this book properly, which could " + "give the appearance of data loss or corruption and could even cause {0} to stop responding. " + "Do you want to include this book in the {1} project anyway?", "Param 0: \"Glyssen\" (product name); " + "Param 1: Glyssen recording project name"), GlyssenInfo.kProduct, m_project.Name); if (DialogResult.No == MessageBox.Show(this, msg, GlyssenInfo.kProduct, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation)) { return(false); } Logger.WriteEvent($"Including book {bookCode} even though " + failureMessage); return(true); }
private void btnOk_Click(object sender, EventArgs e) { var bookNumsToAddFromParatext = new HashSet <int>(); foreach (var book in m_project.AvailableBooks) { bool includingThisBook = m_includeInScript[book.Code]; if (!includingThisBook) { book.IncludeInScript = false; continue; } if (!m_project.IsLiveParatextProject) { book.IncludeInScript = true; } var existingBookScript = m_project.IncludedBooks.SingleOrDefault(b => b.BookId == book.Code); if (existingBookScript != null) { bool prevSingleVoiceValue = existingBookScript.SingleVoice; existingBookScript.SingleVoice = !m_multiVoice[existingBookScript.BookId]; if (prevSingleVoiceValue != existingBookScript.SingleVoice) { Analytics.Track("SetSingleVoice", new Dictionary <string, string> { { "book", existingBookScript.BookId }, { "singleVoice", existingBookScript.SingleVoice.ToString() }, { "method", "ScriptureRangeSelectionDlg.m_btnOk_Click" } }); } continue; } Debug.Assert(m_project.IsLiveParatextProject); book.IncludeInScript = true; BookScript bookScriptFromExistingFile = m_project.FluffUpBookFromFileIfPossible(book.Code); if (bookScriptFromExistingFile == null || UserWantsUpdatedContent(bookScriptFromExistingFile)) { bookNumsToAddFromParatext.Add(Canon.BookIdToNumber(book.Code)); } else { bookScriptFromExistingFile.SingleVoice = !m_multiVoice[book.Code]; m_project.IncludeExistingBook(bookScriptFromExistingFile); Analytics.Track("IncludeExistingBook", new Dictionary <string, string> { { "book", bookScriptFromExistingFile.BookId }, { "singleVoice", bookScriptFromExistingFile.SingleVoice.ToString() } }); } } if (bookNumsToAddFromParatext.Any()) { GetParatextScrTextWrapperIfNeeded(); m_project.IncludeBooksFromParatext(m_paratextScrTextWrapper, bookNumsToAddFromParatext, bookScript => { bookScript.SingleVoice = !m_multiVoice[bookScript.BookId]; Analytics.Track("SetSingleVoice", new Dictionary <string, string> { { "book", bookScript.BookId }, { "singleVoice", bookScript.SingleVoice.ToString() }, { "method", "postParseAction anonymous delegate from ScriptureRangeSelectionDlg.m_btnOk_Click" } }); }); } m_project.BookSelectionStatus = BookSelectionStatus.Reviewed; Analytics.Track("SelectBooks", new Dictionary <string, string> { { "bookSummary", m_project.BookSelectionSummary } }); }