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"
24 extern int tex_code_break_column;
27 // Initialization of the counter for the paragraph id's,
28 unsigned int Paragraph::Pimpl::paragraph_id = 0;
30 // Initialize static member.
31 ShareContainer<LyXFont> Paragraph::Pimpl::FontTable::container;
34 Paragraph::Pimpl::Pimpl(Paragraph * owner)
42 Paragraph::Pimpl::Pimpl(Paragraph::Pimpl const & p, Paragraph * owner)
43 : params(p.params), owner_(owner)
45 inset_owner = p.inset_owner;
47 fontlist = p.fontlist;
51 void Paragraph::Pimpl::clear()
57 void Paragraph::Pimpl::setContentsFromPar(Paragraph const * par)
60 text = par->pimpl_->text;
65 Paragraph::Pimpl::getChar(Paragraph::size_type pos) const
67 lyx::Assert(pos <= size());
68 // This is stronger, and I belive that this is the assertion
69 // that we should really use. (Lgb)
70 //Assert(pos < size());
72 // Then this has no meaning. (Lgb)
73 if (!size() || pos == size()) return '\0';
79 void Paragraph::Pimpl::setChar(Paragraph::size_type pos,
80 Paragraph::value_type c)
86 void Paragraph::Pimpl::insertChar(Paragraph::size_type pos,
87 Paragraph::value_type c,
90 lyx::Assert(pos <= size());
92 text.insert(text.begin() + pos, c);
94 // Update the font table.
95 FontTable search_font(pos, LyXFont());
96 for (FontList::iterator it = std::lower_bound(fontlist.begin(),
98 search_font, matchFT());
99 it != fontlist.end(); ++it)
100 (*it).pos((*it).pos() + 1);
102 // Update the inset table.
103 InsetTable search_inset(pos, 0);
104 for (InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
105 owner_->insetlist.end(),
106 search_inset, matchIT());
107 it != owner_->insetlist.end(); ++it)
110 owner_->setFont(pos, font);
114 void Paragraph::Pimpl::insertInset(Paragraph::size_type pos,
115 Inset * inset, LyXFont const & font)
118 lyx::Assert(pos <= size());
120 insertChar(pos, META_INSET, font);
121 lyx::Assert(text[pos] == META_INSET);
123 // Add a new entry in the inset table.
124 InsetTable search_inset(pos, 0);
125 InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
126 owner_->insetlist.end(),
127 search_inset, matchIT());
128 if (it != owner_->insetlist.end() && (*it).pos == pos) {
129 lyxerr << "ERROR (Paragraph::InsertInset): "
130 "there is an inset in position: " << pos << std::endl;
132 owner_->insetlist.insert(it, InsetTable(pos, inset));
136 inset->setOwner(inset_owner);
140 void Paragraph::Pimpl::erase(Paragraph::size_type pos)
142 lyx::Assert(pos < size());
143 // if it is an inset, delete the inset entry
144 if (text[pos] == Paragraph::META_INSET) {
146 InsetTable search_inset(pos, 0);
147 InsetList::iterator it =
148 std::lower_bound(owner_->insetlist.begin(),
149 owner_->insetlist.end(),
150 search_inset, matchIT());
151 if (it != owner_->insetlist.end() && (*it).pos == pos) {
153 owner_->insetlist.erase(it);
157 text.erase(text.begin() + pos);
159 // Erase entries in the tables.
160 FontTable search_font(pos, LyXFont());
162 FontList::iterator it =
163 std::lower_bound(fontlist.begin(),
165 search_font, matchFT());
166 if (it != fontlist.end() && (*it).pos() == pos &&
168 (it != fontlist.begin()
169 && (*(it - 1)).pos() == pos - 1))) {
170 // If it is a multi-character font
171 // entry, we just make it smaller
172 // (see update below), otherwise we
174 unsigned int const i = it - fontlist.begin();
175 fontlist.erase(fontlist.begin() + i);
176 it = fontlist.begin() + i;
177 if (i > 0 && i < fontlist.size() &&
178 fontlist[i - 1].font() == fontlist[i].font()) {
179 fontlist.erase(fontlist.begin() + i - 1);
180 it = fontlist.begin() + i - 1;
184 // Update all other entries.
185 FontList::iterator fend = fontlist.end();
186 for (; it != fend; ++it)
187 (*it).pos((*it).pos() - 1);
189 // Update the inset table.
190 InsetTable search_inset(pos, 0);
191 InsetList::iterator lend = owner_->insetlist.end();
192 for (InsetList::iterator it =
193 std::upper_bound(owner_->insetlist.begin(),
195 search_inset, matchIT());
201 void Paragraph::Pimpl::simpleTeXBlanks(std::ostream & os, TexRow & texrow,
202 Paragraph::size_type const i,
203 int & column, LyXFont const & font,
204 LyXLayout const & style)
206 if (column > tex_code_break_column
208 && owner_->getChar(i - 1) != ' '
209 && (i < owner_->size() - 1)
211 // In LaTeX mode, we don't want to
212 // break lines since some commands
214 && ! (font.latex() == LyXFont::ON)
216 // same in FreeSpacing mode
217 && !style.free_spacing
218 // In typewriter mode, we want to avoid
219 // ! . ? : at the end of a line
220 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
221 && (owner_->getChar(i-1) == '.'
222 || owner_->getChar(i-1) == '?'
223 || owner_->getChar(i-1) == ':'
224 || owner_->getChar(i-1) == '!'))) {
225 if (tex_code_break_column == 0) {
226 // in batchmode we need LaTeX to still
227 // see it as a space not as an extra '\n'
233 texrow.start(owner_, i + 1);
237 if (font.latex() == LyXFont::OFF) {
239 if (style.free_spacing) {
250 void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
251 BufferParams const & bparams,
256 LyXFont & running_font,
259 LyXLayout const & style,
260 Paragraph::size_type & i,
262 Paragraph::value_type const c)
264 // Two major modes: LaTeX or plain
265 // Handle here those cases common to both modes
266 // and then split to handle the two modes separately.
268 case Paragraph::META_INSET: {
269 Inset * inset = owner_->getInset(i);
272 int const len = os.tellp();
273 //ostream::pos_type const len = os.tellp();
274 if ((inset->lyxCode() == Inset::GRAPHICS_CODE
275 || inset->lyxCode() == Inset::MATH_CODE
276 || inset->lyxCode() == Inset::URL_CODE)
277 && running_font.isRightToLeft()) {
282 int tmp = inset->latex(buf, os, moving_arg,
291 column += int(os.tellp()) - len;
300 case Paragraph::META_NEWLINE:
302 column += running_font.latexWriteEndChanges(os,
307 basefont = owner_->getFont(bparams, -1);
308 running_font = basefont;
311 case Paragraph::META_HFILL:
317 // And now for the special cases within each mode
319 // Are we in LaTeX mode?
320 if (font.latex() == LyXFont::ON) {
321 // at present we only have one option
322 // but I'll leave it as a switch statement
323 // so its simpler to extend. (ARRae)
326 // make sure that we will not print
327 // error generating chars to the tex
328 // file. This test would not be needed
329 // if it were done in the buffer
338 // Plain mode (i.e. not LaTeX)
341 os << "\\textbackslash{}";
345 case '°': case '±': case '²': case '³':
346 case '×': case '÷': case '¹': case 'ª':
347 case 'º': case '¬': case 'µ':
348 if (bparams.inputenc == "latin1" ||
349 (bparams.inputenc == "auto" &&
350 font.language()->encoding()->LatexName()
352 os << "\\ensuremath{"
361 case '|': case '<': case '>':
362 // In T1 encoding, these characters exist
363 if (lyxrc.fontenc == "T1") {
365 //... but we should avoid ligatures
366 if ((c == '>' || c == '<')
367 && i <= owner_->size() - 2
368 && owner_->getChar(i + 1) == c) {
369 //os << "\\textcompwordmark{}";
370 // Jean-Marc, have a look at
371 // this. I think this works
379 // Typewriter font also has them
380 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
384 // Otherwise, we use what LaTeX
388 os << "\\textless{}";
392 os << "\\textgreater{}";
402 case '-': // "--" in Typewriter mode -> "-{}-"
403 if (i <= owner_->size() - 2
404 && owner_->getChar(i + 1) == '-'
405 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
414 os << "\\char`\\\"{}";
419 if (bparams.inputenc == "default") {
428 case '%': case '#': case '{':
435 os << "\\textasciitilde{}";
440 os << "\\textasciicircum{}";
444 case '*': case '[': case ']':
445 // avoid being mistaken for optional arguments
446 os << '{' << c << '}';
451 // Blanks are printed before font switching.
452 // Sure? I am not! (try nice-latex)
453 // I am sure it's correct. LyX might be smarter
454 // in the future, but for now, nothing wrong is
459 /* idea for labels --- begin*/
462 && i <= owner_->size() - 3
463 && font.family() != LyXFont::TYPEWRITER_FAMILY
464 && owner_->getChar(i + 1) == 'y'
465 && owner_->getChar(i + 2) == 'X') {
472 && i <= owner_->size() - 3
473 && font.family() != LyXFont::TYPEWRITER_FAMILY
474 && owner_->getChar(i + 1) == 'e'
475 && owner_->getChar(i + 2) == 'X') {
480 // Check for "LaTeX2e"
482 && i <= owner_->size() - 7
483 && font.family() != LyXFont::TYPEWRITER_FAMILY
484 && owner_->getChar(i + 1) == 'a'
485 && owner_->getChar(i + 2) == 'T'
486 && owner_->getChar(i + 3) == 'e'
487 && owner_->getChar(i + 4) == 'X'
488 && owner_->getChar(i + 5) == '2'
489 && owner_->getChar(i + 6) == 'e') {
496 && i <= owner_->size() - 5
497 && font.family() != LyXFont::TYPEWRITER_FAMILY
498 && owner_->getChar(i + 1) == 'a'
499 && owner_->getChar(i + 2) == 'T'
500 && owner_->getChar(i + 3) == 'e'
501 && owner_->getChar(i + 4) == 'X') {
505 /* idea for labels --- end*/
506 } else if (c != '\0') {
519 Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf,
520 BufferParams const & bparams,
521 std::ostream & os, TexRow & texrow)
523 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << std::endl;
524 Paragraph * par = owner_;
526 while (par && par->params().depth() == owner_->params().depth()) {
527 if (textclasslist.Style(bparams.textclass,
528 par->layout).isEnvironment()) {
529 par = par->TeXEnvironment(buf, bparams,
532 par = par->TeXOnePar(buf, bparams,
536 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << std::endl;