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,
44 : params(p.params), owner_(owner)
46 inset_owner = p.inset_owner;
48 fontlist = p.fontlist;
56 void Paragraph::Pimpl::clear()
62 void Paragraph::Pimpl::setContentsFromPar(Paragraph const * par)
65 text = par->pimpl_->text;
70 Paragraph::Pimpl::getChar(Paragraph::size_type pos) const
72 lyx::Assert(pos <= size());
73 // This is stronger, and I belive that this is the assertion
74 // that we should really use. (Lgb)
75 //Assert(pos < size());
77 // Then this has no meaning. (Lgb)
78 if (!size() || pos == size()) return '\0';
84 void Paragraph::Pimpl::setChar(Paragraph::size_type pos,
85 Paragraph::value_type c)
91 void Paragraph::Pimpl::insertChar(Paragraph::size_type pos,
92 Paragraph::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)
105 (*it).pos((*it).pos() + 1);
107 // Update the inset table.
108 InsetTable search_inset(pos, 0);
109 for (InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
110 owner_->insetlist.end(),
111 search_inset, matchIT());
112 it != owner_->insetlist.end(); ++it)
115 owner_->setFont(pos, font);
119 void Paragraph::Pimpl::insertInset(Paragraph::size_type pos,
120 Inset * inset, LyXFont const & font)
123 lyx::Assert(pos <= size());
125 insertChar(pos, META_INSET, font);
126 lyx::Assert(text[pos] == META_INSET);
128 // Add a new entry in the inset table.
129 InsetTable search_inset(pos, 0);
130 InsetList::iterator it = std::lower_bound(owner_->insetlist.begin(),
131 owner_->insetlist.end(),
132 search_inset, matchIT());
133 if (it != owner_->insetlist.end() && (*it).pos == pos) {
134 lyxerr << "ERROR (Paragraph::InsertInset): "
135 "there is an inset in position: " << pos << std::endl;
137 owner_->insetlist.insert(it, InsetTable(pos, inset));
141 inset->setOwner(inset_owner);
145 void Paragraph::Pimpl::erase(Paragraph::size_type pos)
147 lyx::Assert(pos < size());
148 // if it is an inset, delete the inset entry
149 if (text[pos] == Paragraph::META_INSET) {
151 InsetTable search_inset(pos, 0);
152 InsetList::iterator it =
153 std::lower_bound(owner_->insetlist.begin(),
154 owner_->insetlist.end(),
155 search_inset, matchIT());
156 if (it != owner_->insetlist.end() && (*it).pos == pos) {
158 owner_->insetlist.erase(it);
162 text.erase(text.begin() + pos);
164 // Erase entries in the tables.
165 FontTable search_font(pos, LyXFont());
167 FontList::iterator it =
168 std::lower_bound(fontlist.begin(),
170 search_font, matchFT());
171 if (it != fontlist.end() && (*it).pos() == pos &&
173 (it != fontlist.begin()
174 && (*(it - 1)).pos() == pos - 1))) {
175 // If it is a multi-character font
176 // entry, we just make it smaller
177 // (see update below), otherwise we
179 unsigned int const i = it - fontlist.begin();
180 fontlist.erase(fontlist.begin() + i);
181 it = fontlist.begin() + i;
182 if (i > 0 && i < fontlist.size() &&
183 fontlist[i - 1].font() == fontlist[i].font()) {
184 fontlist.erase(fontlist.begin() + i - 1);
185 it = fontlist.begin() + i - 1;
189 // Update all other entries.
190 FontList::iterator fend = fontlist.end();
191 for (; it != fend; ++it)
192 (*it).pos((*it).pos() - 1);
194 // Update the inset table.
195 InsetTable search_inset(pos, 0);
196 InsetList::iterator lend = owner_->insetlist.end();
197 for (InsetList::iterator it =
198 std::upper_bound(owner_->insetlist.begin(),
200 search_inset, matchIT());
206 void Paragraph::Pimpl::simpleTeXBlanks(std::ostream & os, TexRow & texrow,
207 Paragraph::size_type const i,
208 int & column, LyXFont const & font,
209 LyXLayout const & style)
211 if (column > tex_code_break_column
213 && owner_->getChar(i - 1) != ' '
214 && (i < owner_->size() - 1)
216 // In LaTeX mode, we don't want to
217 // break lines since some commands
219 && ! (font.latex() == LyXFont::ON)
221 // same in FreeSpacing mode
222 && !style.free_spacing
223 // In typewriter mode, we want to avoid
224 // ! . ? : at the end of a line
225 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
226 && (owner_->getChar(i-1) == '.'
227 || owner_->getChar(i-1) == '?'
228 || owner_->getChar(i-1) == ':'
229 || owner_->getChar(i-1) == '!'))) {
230 if (tex_code_break_column == 0) {
231 // in batchmode we need LaTeX to still
232 // see it as a space not as an extra '\n'
238 texrow.start(owner_, i + 1);
242 if (font.latex() == LyXFont::OFF) {
244 if (style.free_spacing) {
255 void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
256 BufferParams const & bparams,
261 LyXFont & running_font,
264 LyXLayout const & style,
265 Paragraph::size_type & i,
267 Paragraph::value_type const c)
269 // Two major modes: LaTeX or plain
270 // Handle here those cases common to both modes
271 // and then split to handle the two modes separately.
273 case Paragraph::META_INSET: {
274 Inset * inset = owner_->getInset(i);
277 int const len = os.tellp();
278 //ostream::pos_type const len = os.tellp();
279 if ((inset->lyxCode() == Inset::GRAPHICS_CODE
280 || inset->lyxCode() == Inset::MATH_CODE
281 || inset->lyxCode() == Inset::URL_CODE)
282 && running_font.isRightToLeft()) {
287 int tmp = inset->latex(buf, os, moving_arg,
296 column += int(os.tellp()) - len;
305 case Paragraph::META_NEWLINE:
307 column += running_font.latexWriteEndChanges(os,
312 basefont = owner_->getFont(bparams, -1);
313 running_font = basefont;
316 case Paragraph::META_HFILL:
322 // And now for the special cases within each mode
324 // Are we in LaTeX mode?
325 if (font.latex() == LyXFont::ON) {
326 // at present we only have one option
327 // but I'll leave it as a switch statement
328 // so its simpler to extend. (ARRae)
331 // make sure that we will not print
332 // error generating chars to the tex
333 // file. This test would not be needed
334 // if it were done in the buffer
343 // Plain mode (i.e. not LaTeX)
346 os << "\\textbackslash{}";
350 case '°': case '±': case '²': case '³':
351 case '×': case '÷': case '¹': case 'ª':
352 case 'º': case '¬': case 'µ':
353 if (bparams.inputenc == "latin1" ||
354 (bparams.inputenc == "auto" &&
355 font.language()->encoding()->LatexName()
357 os << "\\ensuremath{"
366 case '|': case '<': case '>':
367 // In T1 encoding, these characters exist
368 if (lyxrc.fontenc == "T1") {
370 //... but we should avoid ligatures
371 if ((c == '>' || c == '<')
372 && i <= owner_->size() - 2
373 && owner_->getChar(i + 1) == c) {
374 //os << "\\textcompwordmark{}";
375 // Jean-Marc, have a look at
376 // this. I think this works
384 // Typewriter font also has them
385 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
389 // Otherwise, we use what LaTeX
393 os << "\\textless{}";
397 os << "\\textgreater{}";
407 case '-': // "--" in Typewriter mode -> "-{}-"
408 if (i <= owner_->size() - 2
409 && owner_->getChar(i + 1) == '-'
410 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
419 os << "\\char`\\\"{}";
424 if (bparams.inputenc == "default") {
433 case '%': case '#': case '{':
440 os << "\\textasciitilde{}";
445 os << "\\textasciicircum{}";
449 case '*': case '[': case ']':
450 // avoid being mistaken for optional arguments
451 os << '{' << c << '}';
456 // Blanks are printed before font switching.
457 // Sure? I am not! (try nice-latex)
458 // I am sure it's correct. LyX might be smarter
459 // in the future, but for now, nothing wrong is
464 /* idea for labels --- begin*/
467 && i <= owner_->size() - 3
468 && font.family() != LyXFont::TYPEWRITER_FAMILY
469 && owner_->getChar(i + 1) == 'y'
470 && owner_->getChar(i + 2) == 'X') {
477 && i <= owner_->size() - 3
478 && font.family() != LyXFont::TYPEWRITER_FAMILY
479 && owner_->getChar(i + 1) == 'e'
480 && owner_->getChar(i + 2) == 'X') {
485 // Check for "LaTeX2e"
487 && i <= owner_->size() - 7
488 && font.family() != LyXFont::TYPEWRITER_FAMILY
489 && owner_->getChar(i + 1) == 'a'
490 && owner_->getChar(i + 2) == 'T'
491 && owner_->getChar(i + 3) == 'e'
492 && owner_->getChar(i + 4) == 'X'
493 && owner_->getChar(i + 5) == '2'
494 && owner_->getChar(i + 6) == 'e') {
501 && i <= owner_->size() - 5
502 && font.family() != LyXFont::TYPEWRITER_FAMILY
503 && owner_->getChar(i + 1) == 'a'
504 && owner_->getChar(i + 2) == 'T'
505 && owner_->getChar(i + 3) == 'e'
506 && owner_->getChar(i + 4) == 'X') {
510 /* idea for labels --- end*/
511 } else if (c != '\0') {
524 Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf,
525 BufferParams const & bparams,
526 std::ostream & os, TexRow & texrow)
528 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << std::endl;
529 Paragraph * par = owner_;
531 while (par && par->params().depth() == owner_->params().depth()) {
532 if (textclasslist.Style(bparams.textclass,
533 par->layout).isEnvironment()) {
534 par = par->TeXEnvironment(buf, bparams,
537 par = par->TeXOnePar(buf, bparams,
541 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << std::endl;
547 Paragraph * Paragraph::Pimpl::getParFromID(int id) const
549 InsetList::const_iterator lend = owner_->insetlist.end();
551 for (InsetList::const_iterator cit = owner_->insetlist.begin();
554 if ((result = cit->inset->getParFromID(id)))