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"
20 #include "bufferparams.h"
24 #include "support/LAssert.h"
28 extern int tex_code_break_column;
31 // Initialization of the counter for the paragraph id's,
32 unsigned int Paragraph::Pimpl::paragraph_id = 0;
34 // Initialize static member.
35 ShareContainer<LyXFont> Paragraph::Pimpl::FontTable::container;
38 Paragraph::Pimpl::Pimpl(Paragraph * owner)
46 Paragraph::Pimpl::Pimpl(Pimpl const & p, Paragraph * owner, bool same_ids)
47 : params(p.params), owner_(owner)
49 inset_owner = p.inset_owner;
51 fontlist = p.fontlist;
59 void Paragraph::Pimpl::clear()
65 void Paragraph::Pimpl::setContentsFromPar(Paragraph const * par)
68 text = par->pimpl_->text;
72 Paragraph::value_type Paragraph::Pimpl::getChar(pos_type pos) const
74 lyx::Assert(pos <= size());
75 // This is stronger, and I belive that this is the assertion
76 // that we should really use. (Lgb)
77 //Assert(pos < size());
79 // Then this has no meaning. (Lgb)
80 if (!size() || pos == size()) return '\0';
86 void Paragraph::Pimpl::setChar(pos_type pos, value_type c)
92 void Paragraph::Pimpl::insertChar(pos_type pos, value_type c,
95 lyx::Assert(pos <= size());
97 text.insert(text.begin() + pos, c);
99 // Update the font table.
100 FontTable search_font(pos, LyXFont());
101 for (FontList::iterator it = std::lower_bound(fontlist.begin(),
103 search_font, matchFT());
104 it != fontlist.end(); ++it)
106 it->pos(it->pos() + 1);
109 // Update the inset table.
110 InsetTable search_inset(pos, 0);
111 for (InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
112 owner_->insetlist.end(),
113 search_inset, matchIT());
114 it != owner_->insetlist.end(); ++it)
118 owner_->setFont(pos, font);
122 void Paragraph::Pimpl::insertInset(pos_type pos,
123 Inset * inset, LyXFont const & font)
126 lyx::Assert(pos <= size());
128 insertChar(pos, META_INSET, font);
129 lyx::Assert(text[pos] == META_INSET);
131 // Add a new entry in the inset table.
132 InsetTable search_inset(pos, 0);
133 InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
134 owner_->insetlist.end(),
135 search_inset, matchIT());
136 if (it != owner_->insetlist.end() && it->pos == pos) {
137 lyxerr << "ERROR (Paragraph::InsertInset): "
138 "there is an inset in position: " << pos << std::endl;
140 owner_->insetlist.insert(it, InsetTable(pos, inset));
144 inset->setOwner(inset_owner);
148 void Paragraph::Pimpl::erase(pos_type pos)
150 lyx::Assert(pos < size());
151 // if it is an inset, delete the inset entry
152 if (text[pos] == Paragraph::META_INSET) {
154 InsetTable search_inset(pos, 0);
155 InsetList::iterator it =
156 std::lower_bound(owner_->insetlist.begin(),
157 owner_->insetlist.end(),
158 search_inset, matchIT());
159 if (it != owner_->insetlist.end() && it->pos == pos) {
161 owner_->insetlist.erase(it);
165 text.erase(text.begin() + pos);
167 // Erase entries in the tables.
168 FontTable search_font(pos, LyXFont());
170 FontList::iterator it =
171 std::lower_bound(fontlist.begin(),
173 search_font, matchFT());
174 if (it != fontlist.end() && it->pos() == pos &&
176 (it != fontlist.begin()
177 && boost::prior(it)->pos() == pos - 1))) {
178 // If it is a multi-character font
179 // entry, we just make it smaller
180 // (see update below), otherwise we
182 unsigned int const i = it - fontlist.begin();
183 fontlist.erase(fontlist.begin() + i);
184 it = fontlist.begin() + i;
185 if (i > 0 && i < fontlist.size() &&
186 fontlist[i - 1].font() == fontlist[i].font()) {
187 fontlist.erase(fontlist.begin() + i - 1);
188 it = fontlist.begin() + i - 1;
192 // Update all other entries.
193 FontList::iterator fend = fontlist.end();
194 for (; it != fend; ++it)
195 it->pos(it->pos() - 1);
197 // Update the inset table.
198 InsetTable search_inset(pos, 0);
199 InsetList::iterator lend = owner_->insetlist.end();
200 for (InsetList::iterator it =
201 std::upper_bound(owner_->insetlist.begin(),
203 search_inset, matchIT());
209 void Paragraph::Pimpl::simpleTeXBlanks(std::ostream & os, TexRow & texrow,
211 int & column, LyXFont const & font,
212 LyXLayout const & style)
214 if (style.pass_thru) return;
215 if (column > tex_code_break_column
217 && getChar(i - 1) != ' '
219 // same in FreeSpacing mode
220 && !style.free_spacing
221 // In typewriter mode, we want to avoid
222 // ! . ? : at the end of a line
223 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
224 && (getChar(i - 1) == '.'
225 || getChar(i - 1) == '?'
226 || getChar(i - 1) == ':'
227 || getChar(i - 1) == '!'))) {
228 if (tex_code_break_column == 0) {
229 // in batchmode we need LaTeX to still
230 // see it as a space not as an extra '\n'
236 texrow.start(owner_, i + 1);
238 } else if (style.free_spacing) {
246 bool Paragraph::Pimpl::isTextAt(string const & str, pos_type pos)
248 for (int i=0; i < str.length(); ++i) {
249 if (pos + i >= size())
251 if (str[i] != getChar(pos + i))
258 void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
259 BufferParams const & bparams,
264 LyXFont & running_font,
267 LyXLayout const & style,
272 if (style.pass_thru) {
273 if (c != '\0') os << c;
276 // Two major modes: LaTeX or plain
277 // Handle here those cases common to both modes
278 // and then split to handle the two modes separately.
280 case Paragraph::META_INSET: {
281 Inset * inset = owner_->getInset(i);
284 int const len = os.tellp();
285 //ostream::pos_type const len = os.tellp();
286 if ((inset->lyxCode() == Inset::GRAPHICS_CODE
287 || inset->lyxCode() == Inset::MATH_CODE
288 || inset->lyxCode() == Inset::URL_CODE)
289 && running_font.isRightToLeft()) {
294 int tmp = inset->latex(buf, os, moving_arg,
301 for (int j = 0; j < tmp; ++j) {
304 texrow.start(owner_, i + 1);
307 column += int(os.tellp()) - len;
313 case Paragraph::META_NEWLINE:
315 column += running_font.latexWriteEndChanges(os,
320 basefont = owner_->getLayoutFont(bparams);
321 running_font = basefont;
324 case Paragraph::META_HFILL:
330 // And now for the special cases within each mode
334 os << "\\textbackslash{}";
338 case '°': case '±': case '²': case '³':
339 case '×': case '÷': case '¹': case 'ª':
340 case 'º': case '¬': case 'µ':
341 if ((bparams.inputenc == "latin1" ||
342 bparams.inputenc == "latin9") ||
343 (bparams.inputenc == "auto" &&
344 (font.language()->encoding()->LatexName()
346 font.language()->encoding()->LatexName()
348 os << "\\ensuremath{"
357 case '|': case '<': case '>':
358 // In T1 encoding, these characters exist
359 if (lyxrc.fontenc == "T1") {
361 //... but we should avoid ligatures
362 if ((c == '>' || c == '<')
364 && getChar(i + 1) == c) {
365 //os << "\\textcompwordmark{}";
366 // Jean-Marc, have a look at
367 // this. I think this works
375 // Typewriter font also has them
376 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
380 // Otherwise, we use what LaTeX
384 os << "\\textless{}";
388 os << "\\textgreater{}";
398 case '-': // "--" in Typewriter mode -> "-{}-"
400 && getChar(i + 1) == '-'
401 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
410 os << "\\char`\\\"{}";
415 if (bparams.inputenc == "default") {
424 case '%': case '#': case '{':
431 os << "\\textasciitilde{}";
436 os << "\\textasciicircum{}";
440 case '*': case '[': case ']':
441 // avoid being mistaken for optional arguments
442 os << '{' << c << '}';
447 // Blanks are printed before font switching.
448 // Sure? I am not! (try nice-latex)
449 // I am sure it's correct. LyX might be smarter
450 // in the future, but for now, nothing wrong is
456 // I assume this is hack treating typewriter as verbatim
457 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
464 if (isTextAt("LyX", i)) {
468 } else if (isTextAt("TeX", i)) {
472 } else if (isTextAt("LaTeX2e", i)) {
476 } else if (isTextAt("LaTeX", i)) {
480 // do we really try to print out '\0' ?
481 } else if (c != '\0') {
491 Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf,
492 BufferParams const & bparams,
493 std::ostream & os, TexRow & texrow)
495 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << std::endl;
496 Paragraph * par = owner_;
498 while (par && par->params().depth() == owner_->params().depth()) {
499 if (textclasslist.Style(bparams.textclass,
500 par->layout).isEnvironment()) {
501 par = par->TeXEnvironment(buf, bparams,
504 par = par->TeXOnePar(buf, bparams,
508 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << std::endl;
514 Paragraph * Paragraph::Pimpl::getParFromID(int id) const
516 InsetList::const_iterator cit = owner_->insetlist.begin();
517 InsetList::const_iterator lend = owner_->insetlist.end();
519 for (; cit != lend; ++cit) {
520 if ((result = cit->inset->getParFromID(id)))
527 LyXFont const Paragraph::Pimpl::realizeFont(LyXFont const & font,
528 BufferParams const & bparams) const
530 LyXFont tmpfont(font);
532 // check for environment font information
533 char par_depth = owner_->getDepth();
534 Paragraph const * par = owner_;
535 while (par && par->getDepth() && !tmpfont.resolved()) {
536 par = par->outerHook();
538 tmpfont.realize(textclasslist.
539 Style(bparams.textclass,
540 par->getLayout()).font
541 #ifdef INHERIT_LANGUAGE
545 par_depth = par->getDepth();
549 tmpfont.realize(textclasslist.TextClass(bparams.textclass)
551 #ifdef INHERIT_LANGUAGE