1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2001 The LyX Team.
9 * ====================================================== */
14 #pragma implementation
17 #include "paragraph_pimpl.h"
19 #include "bufferparams.h"
23 #include "support/LAssert.h"
25 extern int tex_code_break_column;
28 // Initialization of the counter for the paragraph id's,
29 unsigned int Paragraph::Pimpl::paragraph_id = 0;
31 // Initialize static member.
32 ShareContainer<LyXFont> Paragraph::Pimpl::FontTable::container;
35 Paragraph::Pimpl::Pimpl(Paragraph * owner)
43 Paragraph::Pimpl::Pimpl(Paragraph::Pimpl const & p, Paragraph * owner,
45 : params(p.params), owner_(owner)
47 inset_owner = p.inset_owner;
49 fontlist = p.fontlist;
57 void Paragraph::Pimpl::clear()
63 void Paragraph::Pimpl::setContentsFromPar(Paragraph const * par)
66 text = par->pimpl_->text;
71 Paragraph::Pimpl::getChar(Paragraph::size_type pos) const
73 lyx::Assert(pos <= size());
74 // This is stronger, and I belive that this is the assertion
75 // that we should really use. (Lgb)
76 //Assert(pos < size());
78 // Then this has no meaning. (Lgb)
79 if (!size() || pos == size()) return '\0';
85 void Paragraph::Pimpl::setChar(Paragraph::size_type pos,
86 Paragraph::value_type c)
92 void Paragraph::Pimpl::insertChar(Paragraph::size_type pos,
93 Paragraph::value_type c,
96 lyx::Assert(pos <= size());
98 text.insert(text.begin() + pos, c);
100 // Update the font table.
101 FontTable search_font(pos, LyXFont());
102 for (FontList::iterator it = std::lower_bound(fontlist.begin(),
104 search_font, matchFT());
105 it != fontlist.end(); ++it)
106 it->pos(it->pos() + 1);
108 // Update the inset table.
109 InsetTable search_inset(pos, 0);
110 for (InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
111 owner_->insetlist.end(),
112 search_inset, matchIT());
113 it != owner_->insetlist.end(); ++it)
116 owner_->setFont(pos, font);
120 void Paragraph::Pimpl::insertInset(Paragraph::size_type pos,
121 Inset * inset, LyXFont const & font)
124 lyx::Assert(pos <= size());
126 insertChar(pos, META_INSET, font);
127 lyx::Assert(text[pos] == META_INSET);
129 // Add a new entry in the inset table.
130 InsetTable search_inset(pos, 0);
131 InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
132 owner_->insetlist.end(),
133 search_inset, matchIT());
134 if (it != owner_->insetlist.end() && it->pos == pos) {
135 lyxerr << "ERROR (Paragraph::InsertInset): "
136 "there is an inset in position: " << pos << std::endl;
138 owner_->insetlist.insert(it, InsetTable(pos, inset));
142 inset->setOwner(inset_owner);
146 void Paragraph::Pimpl::erase(Paragraph::size_type pos)
148 lyx::Assert(pos < size());
149 // if it is an inset, delete the inset entry
150 if (text[pos] == Paragraph::META_INSET) {
152 InsetTable search_inset(pos, 0);
153 InsetList::iterator it =
154 std::lower_bound(owner_->insetlist.begin(),
155 owner_->insetlist.end(),
156 search_inset, matchIT());
157 if (it != owner_->insetlist.end() && it->pos == pos) {
159 owner_->insetlist.erase(it);
163 text.erase(text.begin() + pos);
165 // Erase entries in the tables.
166 FontTable search_font(pos, LyXFont());
168 FontList::iterator it =
169 std::lower_bound(fontlist.begin(),
171 search_font, matchFT());
172 if (it != fontlist.end() && it->pos() == pos &&
174 (it != fontlist.begin()
175 && boost::prior(it)->pos() == pos - 1))) {
176 // If it is a multi-character font
177 // entry, we just make it smaller
178 // (see update below), otherwise we
180 unsigned int const i = it - fontlist.begin();
181 fontlist.erase(fontlist.begin() + i);
182 it = fontlist.begin() + i;
183 if (i > 0 && i < fontlist.size() &&
184 fontlist[i - 1].font() == fontlist[i].font()) {
185 fontlist.erase(fontlist.begin() + i - 1);
186 it = fontlist.begin() + i - 1;
190 // Update all other entries.
191 FontList::iterator fend = fontlist.end();
192 for (; it != fend; ++it)
193 it->pos(it->pos() - 1);
195 // Update the inset table.
196 InsetTable search_inset(pos, 0);
197 InsetList::iterator lend = owner_->insetlist.end();
198 for (InsetList::iterator it =
199 std::upper_bound(owner_->insetlist.begin(),
201 search_inset, matchIT());
207 void Paragraph::Pimpl::simpleTeXBlanks(std::ostream & os, TexRow & texrow,
208 Paragraph::size_type const i,
209 int & column, LyXFont const & font,
210 LyXLayout const & style)
212 if (style.pass_thru) return;
213 if (column > tex_code_break_column
215 && getChar(i - 1) != ' '
217 // same in FreeSpacing mode
218 && !style.free_spacing
219 // In typewriter mode, we want to avoid
220 // ! . ? : at the end of a line
221 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
222 && (getChar(i - 1) == '.'
223 || getChar(i - 1) == '?'
224 || getChar(i - 1) == ':'
225 || getChar(i - 1) == '!'))) {
226 if (tex_code_break_column == 0) {
227 // in batchmode we need LaTeX to still
228 // see it as a space not as an extra '\n'
234 texrow.start(owner_, i + 1);
236 } else if (style.free_spacing) {
244 void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
245 BufferParams const & bparams,
250 LyXFont & running_font,
253 LyXLayout const & style,
254 Paragraph::size_type & i,
256 Paragraph::value_type const c)
258 if (style.pass_thru) {
259 if (c != '\0') os << c;
262 // Two major modes: LaTeX or plain
263 // Handle here those cases common to both modes
264 // and then split to handle the two modes separately.
266 case Paragraph::META_INSET: {
267 Inset * inset = owner_->getInset(i);
270 int const len = os.tellp();
271 //ostream::pos_type const len = os.tellp();
272 if ((inset->lyxCode() == Inset::GRAPHICS_CODE
273 || inset->lyxCode() == Inset::MATH_CODE
274 || inset->lyxCode() == Inset::URL_CODE)
275 && running_font.isRightToLeft()) {
280 int tmp = inset->latex(buf, os, moving_arg,
289 column += int(os.tellp()) - len;
298 case Paragraph::META_NEWLINE:
300 column += running_font.latexWriteEndChanges(os,
305 basefont = owner_->getLayoutFont(bparams);
306 running_font = basefont;
309 case Paragraph::META_HFILL:
315 // And now for the special cases within each mode
319 os << "\\textbackslash{}";
323 case '°': case '±': case '²': case '³':
324 case '×': case '÷': case '¹': case 'ª':
325 case 'º': case '¬': case 'µ':
326 if ((bparams.inputenc == "latin1" ||
327 bparams.inputenc == "latin9") ||
328 (bparams.inputenc == "auto" &&
329 (font.language()->encoding()->LatexName()
331 font.language()->encoding()->LatexName()
333 os << "\\ensuremath{"
342 case '|': case '<': case '>':
343 // In T1 encoding, these characters exist
344 if (lyxrc.fontenc == "T1") {
346 //... but we should avoid ligatures
347 if ((c == '>' || c == '<')
349 && getChar(i + 1) == c) {
350 //os << "\\textcompwordmark{}";
351 // Jean-Marc, have a look at
352 // this. I think this works
360 // Typewriter font also has them
361 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
365 // Otherwise, we use what LaTeX
369 os << "\\textless{}";
373 os << "\\textgreater{}";
383 case '-': // "--" in Typewriter mode -> "-{}-"
385 && getChar(i + 1) == '-'
386 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
395 os << "\\char`\\\"{}";
400 if (bparams.inputenc == "default") {
409 case '%': case '#': case '{':
416 os << "\\textasciitilde{}";
421 os << "\\textasciicircum{}";
425 case '*': case '[': case ']':
426 // avoid being mistaken for optional arguments
427 os << '{' << c << '}';
432 // Blanks are printed before font switching.
433 // Sure? I am not! (try nice-latex)
434 // I am sure it's correct. LyX might be smarter
435 // in the future, but for now, nothing wrong is
440 /* idea for labels --- begin*/
444 && font.family() != LyXFont::TYPEWRITER_FAMILY
445 && getChar(i + 1) == 'y'
446 && getChar(i + 2) == 'X') {
454 && font.family() != LyXFont::TYPEWRITER_FAMILY
455 && getChar(i + 1) == 'e'
456 && getChar(i + 2) == 'X') {
461 // Check for "LaTeX2e"
464 && font.family() != LyXFont::TYPEWRITER_FAMILY
465 && getChar(i + 1) == 'a'
466 && getChar(i + 2) == 'T'
467 && getChar(i + 3) == 'e'
468 && getChar(i + 4) == 'X'
469 && getChar(i + 5) == '2'
470 && getChar(i + 6) == 'e') {
478 && font.family() != LyXFont::TYPEWRITER_FAMILY
479 && getChar(i + 1) == 'a'
480 && getChar(i + 2) == 'T'
481 && getChar(i + 3) == 'e'
482 && getChar(i + 4) == 'X') {
486 /* idea for labels --- end*/
487 } else if (c != '\0') {
497 Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf,
498 BufferParams const & bparams,
499 std::ostream & os, TexRow & texrow)
501 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << std::endl;
502 Paragraph * par = owner_;
504 while (par && par->params().depth() == owner_->params().depth()) {
505 if (textclasslist.Style(bparams.textclass,
506 par->layout).isEnvironment()) {
507 par = par->TeXEnvironment(buf, bparams,
510 par = par->TeXOnePar(buf, bparams,
514 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << std::endl;
520 Paragraph * Paragraph::Pimpl::getParFromID(int id) const
522 InsetList::const_iterator cit = owner_->insetlist.begin();
523 InsetList::const_iterator lend = owner_->insetlist.end();
525 for (; cit != lend; ++cit) {
526 if ((result = cit->inset->getParFromID(id)))
533 LyXFont const Paragraph::Pimpl::realizeFont(LyXFont const & font,
534 BufferParams const & bparams) const
536 LyXFont tmpfont(font);
538 // check for environment font information
539 char par_depth = owner_->getDepth();
540 Paragraph const * par = owner_;
541 while (par && par->getDepth() && !tmpfont.resolved()) {
542 par = par->outerHook();
544 #ifndef INHERIT_LANGUAGE
545 tmpfont.realize(textclasslist.
546 Style(bparams.textclass,
547 par->getLayout()).font);
549 tmpfont.realize(textclasslist.
550 Style(bparams.textclass,
551 par->getLayout()).font, bparams.language);
553 par_depth = par->getDepth();
557 #ifndef INHERIT_LANGUAGE
558 tmpfont.realize(textclasslist.TextClass(bparams.textclass)
561 tmpfont.realize(textclasslist.TextClass(bparams.textclass)
562 .defaultfont(), bparams.language);