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) != ' '
218 // In LaTeX mode, we don't want to
219 // break lines since some commands
221 && ! (font.latex() == LyXFont::ON)
223 // same in FreeSpacing mode
224 && !style.free_spacing
225 // In typewriter mode, we want to avoid
226 // ! . ? : at the end of a line
227 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
228 && (getChar(i - 1) == '.'
229 || getChar(i - 1) == '?'
230 || getChar(i - 1) == ':'
231 || getChar(i - 1) == '!'))) {
232 if (tex_code_break_column == 0) {
233 // in batchmode we need LaTeX to still
234 // see it as a space not as an extra '\n'
240 texrow.start(owner_, i + 1);
244 if (font.latex() == LyXFont::OFF) {
246 if (style.free_spacing) {
257 void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
258 BufferParams const & bparams,
263 LyXFont & running_font,
266 LyXLayout const & style,
267 Paragraph::size_type & i,
269 Paragraph::value_type const c)
271 if (style.pass_thru) {
272 if (c != '\0') os << c;
275 // Two major modes: LaTeX or plain
276 // Handle here those cases common to both modes
277 // and then split to handle the two modes separately.
279 case Paragraph::META_INSET: {
280 Inset * inset = owner_->getInset(i);
283 int const len = os.tellp();
284 //ostream::pos_type const len = os.tellp();
285 if ((inset->lyxCode() == Inset::GRAPHICS_CODE
286 || inset->lyxCode() == Inset::MATH_CODE
287 || inset->lyxCode() == Inset::URL_CODE)
288 && running_font.isRightToLeft()) {
293 int tmp = inset->latex(buf, os, moving_arg,
302 column += int(os.tellp()) - len;
311 case Paragraph::META_NEWLINE:
313 column += running_font.latexWriteEndChanges(os,
318 basefont = owner_->getFont(bparams, -1);
319 running_font = basefont;
322 case Paragraph::META_HFILL:
328 // And now for the special cases within each mode
330 // Are we in LaTeX mode?
331 if (font.latex() == LyXFont::ON) {
332 // at present we only have one option
333 // but I'll leave it as a switch statement
334 // so its simpler to extend. (ARRae)
337 // make sure that we will not print
338 // error generating chars to the tex
339 // file. This test would not be needed
340 // if it were done in the buffer
349 // Plain mode (i.e. not LaTeX)
352 os << "\\textbackslash{}";
356 case '°': case '±': case '²': case '³':
357 case '×': case '÷': case '¹': case 'ª':
358 case 'º': case '¬': case 'µ':
359 if (bparams.inputenc == "latin1" ||
360 (bparams.inputenc == "auto" &&
361 font.language()->encoding()->LatexName()
363 os << "\\ensuremath{"
372 case '|': case '<': case '>':
373 // In T1 encoding, these characters exist
374 if (lyxrc.fontenc == "T1") {
376 //... but we should avoid ligatures
377 if ((c == '>' || c == '<')
379 && getChar(i + 1) == c) {
380 //os << "\\textcompwordmark{}";
381 // Jean-Marc, have a look at
382 // this. I think this works
390 // Typewriter font also has them
391 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
395 // Otherwise, we use what LaTeX
399 os << "\\textless{}";
403 os << "\\textgreater{}";
413 case '-': // "--" in Typewriter mode -> "-{}-"
415 && getChar(i + 1) == '-'
416 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
425 os << "\\char`\\\"{}";
430 if (bparams.inputenc == "default") {
439 case '%': case '#': case '{':
446 os << "\\textasciitilde{}";
451 os << "\\textasciicircum{}";
455 case '*': case '[': case ']':
456 // avoid being mistaken for optional arguments
457 os << '{' << c << '}';
462 // Blanks are printed before font switching.
463 // Sure? I am not! (try nice-latex)
464 // I am sure it's correct. LyX might be smarter
465 // in the future, but for now, nothing wrong is
470 /* idea for labels --- begin*/
474 && font.family() != LyXFont::TYPEWRITER_FAMILY
475 && getChar(i + 1) == 'y'
476 && getChar(i + 2) == 'X') {
484 && font.family() != LyXFont::TYPEWRITER_FAMILY
485 && getChar(i + 1) == 'e'
486 && getChar(i + 2) == 'X') {
491 // Check for "LaTeX2e"
494 && font.family() != LyXFont::TYPEWRITER_FAMILY
495 && getChar(i + 1) == 'a'
496 && getChar(i + 2) == 'T'
497 && getChar(i + 3) == 'e'
498 && getChar(i + 4) == 'X'
499 && getChar(i + 5) == '2'
500 && getChar(i + 6) == 'e') {
508 && font.family() != LyXFont::TYPEWRITER_FAMILY
509 && getChar(i + 1) == 'a'
510 && getChar(i + 2) == 'T'
511 && getChar(i + 3) == 'e'
512 && getChar(i + 4) == 'X') {
516 /* idea for labels --- end*/
517 } else if (c != '\0') {
530 Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf,
531 BufferParams const & bparams,
532 std::ostream & os, TexRow & texrow)
534 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << std::endl;
535 Paragraph * par = owner_;
537 while (par && par->params().depth() == owner_->params().depth()) {
538 if (textclasslist.Style(bparams.textclass,
539 par->layout).isEnvironment()) {
540 par = par->TeXEnvironment(buf, bparams,
543 par = par->TeXOnePar(buf, bparams,
547 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << std::endl;
553 Paragraph * Paragraph::Pimpl::getParFromID(int id) const
555 InsetList::const_iterator cit = owner_->insetlist.begin();
556 InsetList::const_iterator lend = owner_->insetlist.end();
558 for (; cit != lend; ++cit) {
559 if ((result = cit->inset->getParFromID(id)))