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)
107 it->pos(it->pos() + 1);
110 // Update the inset table.
111 InsetTable search_inset(pos, 0);
112 for (InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
113 owner_->insetlist.end(),
114 search_inset, matchIT());
115 it != owner_->insetlist.end(); ++it)
119 owner_->setFont(pos, font);
123 void Paragraph::Pimpl::insertInset(Paragraph::size_type pos,
124 Inset * inset, LyXFont const & font)
127 lyx::Assert(pos <= size());
129 insertChar(pos, META_INSET, font);
130 lyx::Assert(text[pos] == META_INSET);
132 // Add a new entry in the inset table.
133 InsetTable search_inset(pos, 0);
134 InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
135 owner_->insetlist.end(),
136 search_inset, matchIT());
137 if (it != owner_->insetlist.end() && it->pos == pos) {
138 lyxerr << "ERROR (Paragraph::InsertInset): "
139 "there is an inset in position: " << pos << std::endl;
141 owner_->insetlist.insert(it, InsetTable(pos, inset));
145 inset->setOwner(inset_owner);
149 void Paragraph::Pimpl::erase(Paragraph::size_type pos)
151 lyx::Assert(pos < size());
152 // if it is an inset, delete the inset entry
153 if (text[pos] == Paragraph::META_INSET) {
155 InsetTable search_inset(pos, 0);
156 InsetList::iterator it =
157 std::lower_bound(owner_->insetlist.begin(),
158 owner_->insetlist.end(),
159 search_inset, matchIT());
160 if (it != owner_->insetlist.end() && it->pos == pos) {
162 owner_->insetlist.erase(it);
166 text.erase(text.begin() + pos);
168 // Erase entries in the tables.
169 FontTable search_font(pos, LyXFont());
171 FontList::iterator it =
172 std::lower_bound(fontlist.begin(),
174 search_font, matchFT());
175 if (it != fontlist.end() && it->pos() == pos &&
177 (it != fontlist.begin()
178 && boost::prior(it)->pos() == pos - 1))) {
179 // If it is a multi-character font
180 // entry, we just make it smaller
181 // (see update below), otherwise we
183 unsigned int const i = it - fontlist.begin();
184 fontlist.erase(fontlist.begin() + i);
185 it = fontlist.begin() + i;
186 if (i > 0 && i < fontlist.size() &&
187 fontlist[i - 1].font() == fontlist[i].font()) {
188 fontlist.erase(fontlist.begin() + i - 1);
189 it = fontlist.begin() + i - 1;
193 // Update all other entries.
194 FontList::iterator fend = fontlist.end();
195 for (; it != fend; ++it)
196 it->pos(it->pos() - 1);
198 // Update the inset table.
199 InsetTable search_inset(pos, 0);
200 InsetList::iterator lend = owner_->insetlist.end();
201 for (InsetList::iterator it =
202 std::upper_bound(owner_->insetlist.begin(),
204 search_inset, matchIT());
210 void Paragraph::Pimpl::simpleTeXBlanks(std::ostream & os, TexRow & texrow,
211 Paragraph::size_type const i,
212 int & column, LyXFont const & font,
213 LyXLayout const & style)
215 if (style.pass_thru) return;
216 if (column > tex_code_break_column
218 && getChar(i - 1) != ' '
220 // same in FreeSpacing mode
221 && !style.free_spacing
222 // In typewriter mode, we want to avoid
223 // ! . ? : at the end of a line
224 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
225 && (getChar(i - 1) == '.'
226 || getChar(i - 1) == '?'
227 || getChar(i - 1) == ':'
228 || getChar(i - 1) == '!'))) {
229 if (tex_code_break_column == 0) {
230 // in batchmode we need LaTeX to still
231 // see it as a space not as an extra '\n'
237 texrow.start(owner_, i + 1);
239 } else if (style.free_spacing) {
247 void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
248 BufferParams const & bparams,
253 LyXFont & running_font,
256 LyXLayout const & style,
257 Paragraph::size_type & i,
259 Paragraph::value_type const c)
261 if (style.pass_thru) {
262 if (c != '\0') os << c;
265 // Two major modes: LaTeX or plain
266 // Handle here those cases common to both modes
267 // and then split to handle the two modes separately.
269 case Paragraph::META_INSET: {
270 Inset * inset = owner_->getInset(i);
273 int const len = os.tellp();
274 //ostream::pos_type const len = os.tellp();
275 if ((inset->lyxCode() == Inset::GRAPHICS_CODE
276 || inset->lyxCode() == Inset::MATH_CODE
277 || inset->lyxCode() == Inset::URL_CODE)
278 && running_font.isRightToLeft()) {
283 int tmp = inset->latex(buf, os, moving_arg,
290 for (int j = 0; j < tmp; ++j) {
293 texrow.start(owner_, i + 1);
296 column += int(os.tellp()) - len;
302 case Paragraph::META_NEWLINE:
304 column += running_font.latexWriteEndChanges(os,
309 basefont = owner_->getLayoutFont(bparams);
310 running_font = basefont;
313 case Paragraph::META_HFILL:
319 // And now for the special cases within each mode
323 os << "\\textbackslash{}";
327 case '°': case '±': case '²': case '³':
328 case '×': case '÷': case '¹': case 'ª':
329 case 'º': case '¬': case 'µ':
330 if ((bparams.inputenc == "latin1" ||
331 bparams.inputenc == "latin9") ||
332 (bparams.inputenc == "auto" &&
333 (font.language()->encoding()->LatexName()
335 font.language()->encoding()->LatexName()
337 os << "\\ensuremath{"
346 case '|': case '<': case '>':
347 // In T1 encoding, these characters exist
348 if (lyxrc.fontenc == "T1") {
350 //... but we should avoid ligatures
351 if ((c == '>' || c == '<')
353 && getChar(i + 1) == c) {
354 //os << "\\textcompwordmark{}";
355 // Jean-Marc, have a look at
356 // this. I think this works
364 // Typewriter font also has them
365 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
369 // Otherwise, we use what LaTeX
373 os << "\\textless{}";
377 os << "\\textgreater{}";
387 case '-': // "--" in Typewriter mode -> "-{}-"
389 && getChar(i + 1) == '-'
390 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
399 os << "\\char`\\\"{}";
404 if (bparams.inputenc == "default") {
413 case '%': case '#': case '{':
420 os << "\\textasciitilde{}";
425 os << "\\textasciicircum{}";
429 case '*': case '[': case ']':
430 // avoid being mistaken for optional arguments
431 os << '{' << c << '}';
436 // Blanks are printed before font switching.
437 // Sure? I am not! (try nice-latex)
438 // I am sure it's correct. LyX might be smarter
439 // in the future, but for now, nothing wrong is
444 /* idea for labels --- begin*/
448 && font.family() != LyXFont::TYPEWRITER_FAMILY
449 && getChar(i + 1) == 'y'
450 && getChar(i + 2) == 'X') {
458 && font.family() != LyXFont::TYPEWRITER_FAMILY
459 && getChar(i + 1) == 'e'
460 && getChar(i + 2) == 'X') {
465 // Check for "LaTeX2e"
468 && font.family() != LyXFont::TYPEWRITER_FAMILY
469 && getChar(i + 1) == 'a'
470 && getChar(i + 2) == 'T'
471 && getChar(i + 3) == 'e'
472 && getChar(i + 4) == 'X'
473 && getChar(i + 5) == '2'
474 && getChar(i + 6) == 'e') {
482 && font.family() != LyXFont::TYPEWRITER_FAMILY
483 && getChar(i + 1) == 'a'
484 && getChar(i + 2) == 'T'
485 && getChar(i + 3) == 'e'
486 && getChar(i + 4) == 'X') {
490 /* idea for labels --- end*/
491 } else if (c != '\0') {
501 Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf,
502 BufferParams const & bparams,
503 std::ostream & os, TexRow & texrow)
505 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << std::endl;
506 Paragraph * par = owner_;
508 while (par && par->params().depth() == owner_->params().depth()) {
509 if (textclasslist.Style(bparams.textclass,
510 par->layout).isEnvironment()) {
511 par = par->TeXEnvironment(buf, bparams,
514 par = par->TeXOnePar(buf, bparams,
518 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << std::endl;
524 Paragraph * Paragraph::Pimpl::getParFromID(int id) const
526 InsetList::const_iterator cit = owner_->insetlist.begin();
527 InsetList::const_iterator lend = owner_->insetlist.end();
529 for (; cit != lend; ++cit) {
530 if ((result = cit->inset->getParFromID(id)))
537 LyXFont const Paragraph::Pimpl::realizeFont(LyXFont const & font,
538 BufferParams const & bparams) const
540 LyXFont tmpfont(font);
542 // check for environment font information
543 char par_depth = owner_->getDepth();
544 Paragraph const * par = owner_;
545 while (par && par->getDepth() && !tmpfont.resolved()) {
546 par = par->outerHook();
548 #ifndef INHERIT_LANGUAGE
549 tmpfont.realize(textclasslist.
550 Style(bparams.textclass,
551 par->getLayout()).font);
553 tmpfont.realize(textclasslist.
554 Style(bparams.textclass,
555 par->getLayout()).font, bparams.language);
557 par_depth = par->getDepth();
561 #ifndef INHERIT_LANGUAGE
562 tmpfont.realize(textclasslist.TextClass(bparams.textclass)
565 tmpfont.realize(textclasslist.TextClass(bparams.textclass)
566 .defaultfont(), bparams.language);