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 == "auto" &&
328 font.language()->encoding()->LatexName()
330 os << "\\ensuremath{"
339 case '|': case '<': case '>':
340 // In T1 encoding, these characters exist
341 if (lyxrc.fontenc == "T1") {
343 //... but we should avoid ligatures
344 if ((c == '>' || c == '<')
346 && getChar(i + 1) == c) {
347 //os << "\\textcompwordmark{}";
348 // Jean-Marc, have a look at
349 // this. I think this works
357 // Typewriter font also has them
358 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
362 // Otherwise, we use what LaTeX
366 os << "\\textless{}";
370 os << "\\textgreater{}";
380 case '-': // "--" in Typewriter mode -> "-{}-"
382 && getChar(i + 1) == '-'
383 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
392 os << "\\char`\\\"{}";
397 if (bparams.inputenc == "default") {
406 case '%': case '#': case '{':
413 os << "\\textasciitilde{}";
418 os << "\\textasciicircum{}";
422 case '*': case '[': case ']':
423 // avoid being mistaken for optional arguments
424 os << '{' << c << '}';
429 // Blanks are printed before font switching.
430 // Sure? I am not! (try nice-latex)
431 // I am sure it's correct. LyX might be smarter
432 // in the future, but for now, nothing wrong is
437 /* idea for labels --- begin*/
441 && font.family() != LyXFont::TYPEWRITER_FAMILY
442 && getChar(i + 1) == 'y'
443 && getChar(i + 2) == 'X') {
451 && font.family() != LyXFont::TYPEWRITER_FAMILY
452 && getChar(i + 1) == 'e'
453 && getChar(i + 2) == 'X') {
458 // Check for "LaTeX2e"
461 && font.family() != LyXFont::TYPEWRITER_FAMILY
462 && getChar(i + 1) == 'a'
463 && getChar(i + 2) == 'T'
464 && getChar(i + 3) == 'e'
465 && getChar(i + 4) == 'X'
466 && getChar(i + 5) == '2'
467 && getChar(i + 6) == 'e') {
475 && font.family() != LyXFont::TYPEWRITER_FAMILY
476 && getChar(i + 1) == 'a'
477 && getChar(i + 2) == 'T'
478 && getChar(i + 3) == 'e'
479 && getChar(i + 4) == 'X') {
483 /* idea for labels --- end*/
484 } else if (c != '\0') {
494 Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf,
495 BufferParams const & bparams,
496 std::ostream & os, TexRow & texrow)
498 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << std::endl;
499 Paragraph * par = owner_;
501 while (par && par->params().depth() == owner_->params().depth()) {
502 if (textclasslist.Style(bparams.textclass,
503 par->layout).isEnvironment()) {
504 par = par->TeXEnvironment(buf, bparams,
507 par = par->TeXOnePar(buf, bparams,
511 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << std::endl;
517 Paragraph * Paragraph::Pimpl::getParFromID(int id) const
519 InsetList::const_iterator cit = owner_->insetlist.begin();
520 InsetList::const_iterator lend = owner_->insetlist.end();
522 for (; cit != lend; ++cit) {
523 if ((result = cit->inset->getParFromID(id)))
530 LyXFont const Paragraph::Pimpl::realizeFont(LyXFont const & font,
531 BufferParams const & bparams) const
533 LyXFont tmpfont(font);
535 // check for environment font information
536 char par_depth = owner_->getDepth();
537 Paragraph const * par = owner_;
538 while (par && par->getDepth() && !tmpfont.resolved()) {
539 par = par->outerHook();
541 #ifndef INHERIT_LANGUAGE
542 tmpfont.realize(textclasslist.
543 Style(bparams.textclass,
544 par->getLayout()).font);
546 tmpfont.realize(textclasslist.
547 Style(bparams.textclass,
548 par->getLayout()).font, bparams.language);
550 par_depth = par->getDepth();
554 #ifndef INHERIT_LANGUAGE
555 tmpfont.realize(textclasslist.TextClass(bparams.textclass)
558 tmpfont.realize(textclasslist.TextClass(bparams.textclass)
559 .defaultfont(), bparams.language);