1 /**
2  * \file Context.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jean-Marc Lasgouttes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10 
11 #include <config.h>
12 
13 #include "Context.h"
14 #include "Layout.h"
15 
16 #include "support/lstrings.h"
17 
18 #include <iostream>
19 
20 using namespace std;
21 using namespace lyx::support;
22 
23 namespace lyx {
24 
25 namespace {
26 
end_layout(ostream & os)27 void end_layout(ostream & os)
28 {
29 	os << "\n\\end_layout\n";
30 }
31 
32 
begin_deeper(ostream & os)33 void begin_deeper(ostream & os)
34 {
35 	os << "\n\\begin_deeper";
36 }
37 
38 
end_deeper(ostream & os)39 void end_deeper(ostream & os)
40 {
41 	os << "\n\\end_deeper";
42 }
43 
44 } // namespace
45 
46 
operator ==(TeXFont const & f1,TeXFont const & f2)47 bool operator==(TeXFont const & f1, TeXFont const & f2)
48 {
49 	return
50 		f1.size == f2.size &&
51 		f1.family == f2.family &&
52 		f1.series == f2.series &&
53 		f1.shape == f2.shape &&
54 		f1.language == f2.language;
55 }
56 
57 
output_font_change(ostream & os,TeXFont const & oldfont,TeXFont const & newfont)58 void output_font_change(ostream & os, TeXFont const & oldfont,
59 			TeXFont const & newfont)
60 {
61 	if (oldfont.family != newfont.family)
62 		os << "\n\\family " << newfont.family << '\n';
63 	if (oldfont.series != newfont.series)
64 		os << "\n\\series " << newfont.series << '\n';
65 	if (oldfont.shape != newfont.shape)
66 		os << "\n\\shape " << newfont.shape << '\n';
67 	if (oldfont.size != newfont.size)
68 		os << "\n\\size " << newfont.size << '\n';
69 	if (oldfont.language != newfont.language)
70 		os << "\n\\lang " << newfont.language << '\n';
71 }
72 
73 
74 TeXFont Context::normalfont;
75 bool Context::empty = true;
76 
77 
Context(bool need_layout_,TeX2LyXDocClass const & textclass_,Layout const * layout_,Layout const * parent_layout_,TeXFont const & font_)78 Context::Context(bool need_layout_,
79 		 TeX2LyXDocClass const & textclass_,
80 		 Layout const * layout_, Layout const * parent_layout_,
81 		 TeXFont const & font_)
82 	: need_layout(need_layout_),
83 	  need_end_layout(false), need_end_deeper(false),
84 	  has_item(false), deeper_paragraph(false),
85 	  new_layout_allowed(true), merging_hyphens_allowed(true),
86 	  textclass(textclass_),
87 	  layout(layout_), parent_layout(parent_layout_),
88 	  font(font_)
89 {
90 	if (!layout)
91 		layout = &textclass.defaultLayout();
92 	if (!parent_layout)
93 		parent_layout = &textclass.defaultLayout();
94 }
95 
96 
~Context()97 Context::~Context()
98 {
99 	if (!par_extra_stuff.empty())
100 		cerr << "Bug: Ignoring par-level extra stuff '"
101 		     << par_extra_stuff << '\'' << endl;
102 }
103 
104 
begin_layout(ostream & os,Layout const * const & l)105 void Context::begin_layout(ostream & os, Layout const * const & l)
106 {
107 	os << "\n\\begin_layout " << to_utf8(l->name()) << "\n";
108 	if (!extra_stuff.empty()) {
109 		os << extra_stuff;
110 	}
111 	if (!par_extra_stuff.empty()) {
112 		os << par_extra_stuff;
113 		par_extra_stuff.erase();
114 	}
115 	// FIXME: This is not enough for things like
116 	// \\Huge par1 \\par par2
117 	// FIXME: If the document language is not english this outputs a
118 	// superflous language change. Fortunately this is only file format
119 	// bloat and does not change the TeX export of LyX.
120 	output_font_change(os, normalfont, font);
121 }
122 
123 
check_layout(ostream & os)124 void Context::check_layout(ostream & os)
125 {
126 	if (need_layout) {
127 		check_end_layout(os);
128 
129 		// are we in a list-like environment?
130 		if (layout->isEnvironment()
131 		    && layout->latextype != LATEX_ENVIRONMENT) {
132 			// A list-like environment
133 			if (has_item) {
134 				// a new item. If we had a standard
135 				// paragraph before, we have to end it.
136 				if (deeper_paragraph) {
137 					end_deeper(os);
138 					deeper_paragraph = false;
139 				}
140 				begin_layout(os, layout);
141 				has_item = false;
142 			} else {
143 				// a standard paragraph in an
144 				// enumeration. We have to recognize
145 				// that this may require a begin_deeper.
146 				if (!deeper_paragraph)
147 					begin_deeper(os);
148 				begin_layout(os, &textclass.defaultLayout());
149 				deeper_paragraph = true;
150 			}
151 		} else {
152 			// No list-like environment
153 			begin_layout(os, layout);
154 		}
155 		need_layout = false;
156 		need_end_layout = true;
157 		empty = false;
158 	}
159 }
160 
161 
check_end_layout(ostream & os)162 void Context::check_end_layout(ostream & os)
163 {
164 	if (need_end_layout) {
165 		end_layout(os);
166 		need_end_layout = false;
167 	}
168 }
169 
170 
check_deeper(ostream & os)171 void Context::check_deeper(ostream & os)
172 {
173 	if (parent_layout->isEnvironment()) {
174 		// We start a nested environment.
175 		// We need to increase the depth.
176 		if (need_end_deeper) {
177 			// no need to have \end_deeper \begin_deeper
178 			need_end_deeper = false;
179 		} else {
180 			begin_deeper(os);
181 			need_end_deeper = true;
182 		}
183 	} else
184 		check_end_deeper(os);
185 }
186 
187 
check_end_deeper(ostream & os)188 void Context::check_end_deeper(ostream & os)
189 {
190 	if (need_end_deeper) {
191 		end_deeper(os);
192 		need_end_deeper = false;
193 	}
194 	if (deeper_paragraph) {
195 		end_deeper(os);
196 		deeper_paragraph = false;
197 	}
198 }
199 
200 
set_item()201 void Context::set_item()
202 {
203 	need_layout = true;
204 	has_item = true;
205 }
206 
207 
new_paragraph(ostream & os)208 void Context::new_paragraph(ostream & os)
209 {
210 	check_end_layout(os);
211 	need_layout = true;
212 }
213 
214 
add_extra_stuff(string const & stuff)215 void Context::add_extra_stuff(string const & stuff)
216 {
217 	if (!contains(extra_stuff, stuff))
218 		extra_stuff += stuff;
219 }
220 
221 
add_par_extra_stuff(string const & stuff)222 void Context::add_par_extra_stuff(string const & stuff)
223 {
224 	if (!contains(par_extra_stuff, stuff))
225 		par_extra_stuff += stuff;
226 }
227 
228 
dump(ostream & os,string const & desc) const229 void Context::dump(ostream & os, string const & desc) const
230 {
231 	os << "\n" << desc <<" [";
232 	if (need_layout)
233 		os << "need_layout ";
234 	if (need_end_layout)
235 		os << "need_end_layout ";
236 	if (need_end_deeper)
237 		os << "need_end_deeper ";
238 	if (has_item)
239 		os << "has_item ";
240 	if (deeper_paragraph)
241 		os << "deeper_paragraph ";
242 	if (new_layout_allowed)
243 		os << "new_layout_allowed ";
244 	if (merging_hyphens_allowed)
245 		os << "merging_hyphens_allowed ";
246 	if (!extra_stuff.empty())
247 		os << "extrastuff=[" << extra_stuff << "] ";
248 	if (!par_extra_stuff.empty())
249 		os << "parextrastuff=[" << par_extra_stuff << "] ";
250 	if (!list_extra_stuff.empty())
251 		os << "listextrastuff=[" << list_extra_stuff << "] ";
252 	os << "textclass=" << textclass.name()
253 	   << " layout=" << to_utf8(layout->name())
254 	   << " parent_layout=" << to_utf8(parent_layout->name()) << "] font=["
255 	   << font.size << ' ' << font.family << ' ' << font.series << ' '
256 	   << font.shape << ']' << endl;
257 }
258 
259 
260 } // namespace lyx
261