bool searchwords_find_fast (const ustring& text, const vector <ustring>& searchwords, const vector <bool>& wholewords, const vector <bool>& casesensitives, vector <size_t>& startpositions, vector <size_t>& lengths) // Finds occurrences of searchwords in the text. // text: Text to be looked through. // searchwords: Search words to look for. // wholewords / casesensitives: Attributes of the searchwords. // startpositions: If non-NULL, will be filled with the positions that each searchword starts at. // lengths: If non-NULL, will be filled with the lengths of the searchwords found. // Returns whether one or more searchwords were found in the text. { // Clear output containers. startpositions.clear(); lengths.clear(); // A textbuffer makes searching text easier in this case. GtkTextBuffer * textbuffer = gtk_text_buffer_new (NULL); gtk_text_buffer_set_text (textbuffer, text.c_str(), -1); GtkTextIter startiter; gtk_text_buffer_get_start_iter(textbuffer, &startiter); bool found = false; // Go through all words to look for. for (unsigned int i2 = 0; i2 < searchwords.size(); i2++) { // Define this search word and its parameters. ustring searchword = searchwords[i2]; bool wholeword = wholewords[i2]; bool casesensitive = casesensitives[i2]; // Handle case sensitivity. ustring mytext; ustring mysearchword; if (casesensitive) { mytext = text; mysearchword = searchword; } else { mytext = text.casefold(); mysearchword = searchword.casefold(); } // Find all occurrences of the word. size_t position = mytext.find(mysearchword); while (position != string::npos) { bool temporally_approved = true; GtkTextIter approvedstart = startiter; GtkTextIter approvedend; gtk_text_iter_forward_chars(&approvedstart, position); approvedend = approvedstart; gtk_text_iter_forward_chars(&approvedend, searchword.length()); if (wholeword) { if (!gtk_text_iter_starts_word(&approvedstart)) temporally_approved = false; if (!gtk_text_iter_ends_word(&approvedend)) temporally_approved = false; } if (temporally_approved) { found = true; startpositions.push_back (position); lengths.push_back (searchword.length()); } position = mytext.find(mysearchword, ++position); } } // Free textbuffer used. g_object_unref (textbuffer); if (found) { // Sort the output. quick_sort (startpositions, lengths, 0, (unsigned int)startpositions.size()); // Overlapping items need to be combined to avoid crashes. xml_combine_overlaps (startpositions, lengths); } // Return true if anything was found. return found; }
void WindowCheckKeyterms::html_write_keyterms (HtmlWriter2& htmlwriter, unsigned int keyword_id) { // Get data about the project. extern Settings *settings; ustring project = settings->genconfig.project_get(); ProjectConfiguration *projectconfig = settings->projectconfig(project); ustring versification = projectconfig->versification_get(); // Add action links. htmlwriter.paragraph_open (); htmlwriter.hyperlink_add ("index", "[Index]"); htmlwriter.text_add (" "); htmlwriter.hyperlink_add ("send", _("[Send to references window]")); htmlwriter.paragraph_close (); // Add the keyterm itself. ustring keyterm; keyterms_get_term(keyword_id, keyterm); htmlwriter.heading_open (3); htmlwriter.text_add (keyterm); htmlwriter.heading_close(); // Retrieve the renderings. vector <ustring> renderings; vector <bool> wholewords; vector <bool> casesensitives; get_renderings(renderings, wholewords, casesensitives); // Get the data for the keyword identifier. ustring dummy; ustring information; keyterms_get_data(keyword_id, dummy, information, references); // Divide the information into lines. ParseLine parseline (information); // Write the information. for (unsigned int i = 0; i < parseline.lines.size(); i++) { information = parseline.lines[i]; htmlwriter.paragraph_open (); size_t pos = information.find (keyterms_reference_start_markup ()); while (pos != string::npos) { htmlwriter.text_add (information.substr (0, pos)); information.erase (0, pos + keyterms_reference_start_markup ().length()); pos = information.find (keyterms_reference_end_markup ()); if (pos != string::npos) { // Extract the reference. htmlwriter.paragraph_close (); ustring original_reference_text = information.substr (0, pos); Reference reference = get_reference (original_reference_text); // Remap the reference. { Mapping mapping(versification, reference.book_get()); vector <int> chapters; vector <int> verses; mapping.original_to_me(reference.chapter_get(), reference.verse_get(), chapters, verses); if (!chapters.empty()) { reference.chapter_set(chapters[0]); reference.verse_set(convert_to_string (verses[0])); } } ustring remapped_reference_text = reference.human_readable (""); ustring displayed_reference_text (remapped_reference_text); if (remapped_reference_text != original_reference_text) { displayed_reference_text.append (" ("); displayed_reference_text.append (original_reference_text); displayed_reference_text.append (")"); } // Add the reference with hyperlink. htmlwriter.hyperlink_add ("goto " + remapped_reference_text, remapped_reference_text); information.erase (0, pos + keyterms_reference_end_markup ().length()); // Add the reference's text. ustring verse = project_retrieve_verse(project, reference); if (verse.empty()) { verse.append(_("<empty>")); } else { CategorizeLine cl(verse); cl.remove_verse_number(reference.verse_get()); verse = cl.verse; } htmlwriter.text_add (" "); // Add the verse plus markup for approved text. vector <size_t> startpositions; vector <size_t> lengths; size_t processposition = 0; if (find_renderings (verse, renderings, wholewords, casesensitives, &startpositions, &lengths)) { quick_sort (startpositions, lengths, 0, startpositions.size()); // Overlapping items need to be combined to avoid crashes. xml_combine_overlaps (startpositions, lengths); for (unsigned int i = 0; i < startpositions.size(); i++) { htmlwriter.text_add (verse.substr (0, startpositions[i] - processposition)); htmlwriter.bold_open(); htmlwriter.text_add (verse.substr (startpositions[i] - processposition, lengths[i])); htmlwriter.bold_close(); verse.erase (0, startpositions[i] - processposition + lengths[i]); processposition = startpositions[i] + lengths[i]; } // Add whatever is left over of the verse. This could be the full verse in case it wasn't processed. htmlwriter.text_add (verse); } else { htmlwriter.highlight_open(); htmlwriter.text_add (verse); htmlwriter.highlight_close(); } // Proceed to next. htmlwriter.paragraph_open (); pos = information.find (keyterms_reference_start_markup ()); } } htmlwriter.text_add (information); htmlwriter.paragraph_close (); } }
void view_parallel_references_pdf(ProjectMemory & main_project, vector < ustring > *extra_projects, vector < Reference > references, bool keep_verses_together_within_page, vector < ustring > *remarks, bool highlight) /* Formats the references in "references", and highlights all words in "session->highlights*" and shows them in a pdf viewer. There is a pointer to a list of "remarks". Any remarks will be printed first. */ { // Log. gw_message(_("Printing parallel references")); // Progress system. ProgressWindow progresswindow(_("Printing Parallel References"), false); progresswindow.set_iterate(0, 1, references.size()); // Configuration extern Settings *settings; ProjectConfiguration *projectconfig = settings->projectconfig(main_project.name); ustring stylesheet = stylesheet_get_actual (); // Store the additional projects to print. vector < ustring > additional_projects; if (extra_projects) additional_projects = *extra_projects; settings->session.additional_printing_projects = additional_projects; // Prepare for mapping. Mapping mapping(projectconfig->versification_get(), 0); // The converter. Text2Pdf text2pdf(gw_build_filename(Directories->get_temp(), "document.pdf"), settings->genconfig.print_engine_use_intermediate_text_get()); // Page. text2pdf.page_size_set(settings->genconfig.paper_width_get(), settings->genconfig.paper_height_get()); text2pdf.page_margins_set(settings->genconfig.paper_inside_margin_get(), settings->genconfig.paper_outside_margin_get(), settings->genconfig.paper_top_margin_get(), settings->genconfig.paper_bottom_margin_get()); text2pdf.page_one_column_only(); // Headers. if (settings->genconfig.printdate_get()) { text2pdf.print_date_in_header(); } // Font, etc., of main project. ustring main_font = projectconfig->editor_font_name_get(); unsigned int main_line_spacing = projectconfig->text_line_height_get(); if (projectconfig->editor_font_default_get()) { main_font.clear(); main_line_spacing = 100; } text2pdf.set_font(main_font); text2pdf.set_line_spacing(main_line_spacing); bool main_right_to_left = projectconfig->right_to_left_get(); text2pdf.set_right_to_left(main_right_to_left); // Start off with inserting any remarks. if (remarks) { for (unsigned int r = 0; r < remarks->size(); r++) { text2pdf.open_paragraph(); text2pdf.paragraph_set_column_count(1); text2pdf.add_text(remarks->at(r)); text2pdf.close_paragraph(); } } // Some variables to avoid excessive session access during highlighting. vector < bool > highlight_casesensitives; vector < ustring > highlight_words; if (highlight) { for (unsigned int hl = 0; hl < settings->session.highlights.size(); hl++) { highlight_casesensitives.push_back(settings->session.highlights[hl].casesensitive); highlight_words.push_back(settings->session.highlights[hl].word); } } // All the projects to be put in this parallel Bible, together with // their related information, like mapping, fonts. vector < ustring > project_names; vector < ProjectMemory > project_memories; vector < Mapping > mapping_s; vector < ustring > fonts; vector < unsigned int >line_spacings; vector < bool > right_to_lefts; if (extra_projects) { vector < ustring > project_s_raw = *extra_projects; for (unsigned int i = 0; i < project_s_raw.size(); i++) { ProjectMemory projectmemory(project_s_raw[i], true); project_memories.push_back(projectmemory); ProjectConfiguration *projectconfig = settings->projectconfig(project_s_raw[i]); project_names.push_back(project_s_raw[i]); Mapping mapping(projectconfig->versification_get(), 0); mapping_s.push_back(mapping); ustring font = projectconfig->editor_font_name_get(); unsigned int line_spacing = projectconfig->text_line_height_get(); if (projectconfig->editor_font_default_get()) { font.clear(); line_spacing = 100; } fonts.push_back(font); line_spacings.push_back(line_spacing); right_to_lefts.push_back(projectconfig->right_to_left_get()); } } // Produce chunks for all references. for (unsigned int rf = 0; rf < references.size(); rf++) { // Update progress bar. progresswindow.iterate(); // Whether to keep things on one page. if (keep_verses_together_within_page) { text2pdf.open_keep_together(); } // Set main font, etc. text2pdf.set_font(main_font); text2pdf.set_line_spacing(main_line_spacing); text2pdf.set_right_to_left(main_right_to_left); // Add the reference to the text. text2pdf.add_text(references[rf].human_readable("")); // Map this verse to the original, that is, to Hebrew or Greek. vector <int> hebrew_greek_chapters; vector <int> hebrew_greek_verses; mapping.book_change(references[rf].book); mapping.me_to_original(references[rf].chapter, references[rf].verse, hebrew_greek_chapters, hebrew_greek_verses); // Get verse text for each version. for (unsigned int vsn = 0; vsn <= project_names.size(); vsn++) { // Add the font, etc., for each project. ustring font(main_font); unsigned int line_spacing = main_line_spacing; bool right_to_left = main_right_to_left; if (vsn > 0) { font = fonts[vsn - 1]; line_spacing = line_spacings[vsn - 1]; right_to_left = right_to_lefts[vsn - 1]; } text2pdf.set_font(font); text2pdf.set_line_spacing(line_spacing); text2pdf.set_right_to_left(right_to_left); // Get the verse text. ustring line; if (vsn == 0) { // First version. ProjectBook *projectbook = main_project.get_book_pointer(references[rf].book); if (projectbook) { ProjectChapter *projectchapter = projectbook->get_chapter_pointer(references[rf].chapter); if (projectchapter) { ProjectVerse *projectverse = projectchapter->get_verse_pointer(references[rf].verse); if (projectverse) { line = projectverse->data; } } } } else { // Other versions. // Get mapped chapters / verses. line.clear(); vector <int> mychapters; vector <int> myverses; mapping_s[vsn - 1].book_change(references[rf].book); mapping_s[vsn - 1].original_to_me(hebrew_greek_chapters, hebrew_greek_verses, mychapters, myverses); // Get text of any of the mapped verses. for (unsigned int mp = 0; mp < mychapters.size(); mp++) { // Get the verse and add it to the usfm code. ProjectBook *projectbook = project_memories[vsn - 1].get_book_pointer(references[rf].book); if (projectbook) { ProjectChapter *projectchapter = projectbook->get_chapter_pointer(mychapters[mp]); if (projectchapter) { ProjectVerse *projectverse = projectchapter->get_verse_pointer(convert_to_string(myverses[mp])); if (projectverse) { if (!line.empty()) line.append (" "); line.append (projectverse->data); } } } } } // Add the project name if there are more than one. if (!project_names.empty()) { ustring project; if (vsn == 0) project = main_project.name; else project = project_names[vsn - 1]; text2pdf.open_paragraph(); text2pdf.inline_set_font_size_percentage(65); text2pdf.add_text(project); text2pdf.inline_clear_font_size_percentage(); text2pdf.add_text(" "); } else { text2pdf.open_paragraph(); } // Do text replacement. text_replacement(line); // Positions in the line, and lengths to highlight. vector < size_t > highlight_positions; vector < size_t > highlight_lengths; // Go through all the words to highlight. for (unsigned int i2 = 0; i2 < highlight_casesensitives.size(); i2++) { // Word to highlight ustring highlightword; if (highlight_casesensitives[i2]) highlightword = highlight_words[i2]; else highlightword = highlight_words[i2].casefold(); // Variabele s holds a shadow string. ustring s; if (highlight_casesensitives[i2]) s = line; else s = line.casefold(); // Find positions for highlighting. size_t offposition = s.find(highlightword); while (offposition != string::npos) { // Store position and length. highlight_positions.push_back(offposition); highlight_lengths.push_back(highlightword.length()); // Look for possible next word to highlight. offposition = offposition + highlightword.length() + 1; // There is something like a bug in s.find. If the offposition // is greater than the length of s, then s.find will return // a value below offposition, instead of string::npos as is // expected. Workaround. if (offposition > s.length()) break; offposition = s.find(highlightword, offposition); } } // Sort the positions from small to bigger. xml_sort_positions(highlight_positions, highlight_lengths); // Combine overlapping positions. xml_combine_overlaps(highlight_positions, highlight_lengths); // Insert the code for highlighting. for (int i = highlight_positions.size () - 1; i >= 0; i--) { for (int i2 = highlight_lengths.size() - 1; i2 >= 0; i2--) { line.insert (highlight_positions[i] + i2, INSERTION_FLAG); } } // Add usfm converter to the layout engine, and set various things. Usfm2Text usfm2text(&text2pdf, false); usfm2text.add_styles(usfm2xslfo_read_stylesheet(stylesheet)); usfm2text.no_bold(); usfm2text.no_space_before_or_after(); usfm2text.no_new_page(); usfm2text.add_usfm_code(line); usfm2text.process(); } // Add a bit of space. text2pdf.close_paragraph(); text2pdf.add_text(" "); text2pdf.close_paragraph(); // Whether to close code keeping things on one page. if (keep_verses_together_within_page) { text2pdf.close_keep_together(); } } // Hide progeressbar. progresswindow.hide(); // Process the data. text2pdf.run(); // Display the pdf file. text2pdf.view(); // Log: ready. gw_message(_("Ready printing the parallel references")); }