]> git.lyx.org Git - lyx.git/blob - src/insets/insetfloat.C
Make it compile when USE_BOOST_FORMAT is unset
[lyx.git] / src / insets / insetfloat.C
1 /**
2  * \file insetfloat.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna
7  * \author Lars Gullik Bjønnes
8  *
9  * Full author contact details are available in file CREDITS
10  */
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "insetfloat.h"
18 #include "gettext.h"
19 #include "lyxfont.h"
20 #include "BufferView.h"
21 #include "lyxtext.h"
22 #include "insets/insettext.h"
23 #include "support/LOstream.h"
24 #include "support/lstrings.h"
25 #include "FloatList.h"
26 #include "LaTeXFeatures.h"
27 #include "debug.h"
28 #include "Floating.h"
29 #include "buffer.h"
30 #include "frontends/LyXView.h"
31 #include "frontends/Dialogs.h"
32 #include "lyxlex.h"
33 #include "iterators.h"
34
35 using std::ostream;
36 using std::endl;
37
38 // With this inset it will be possible to support the latex package
39 // float.sty, and I am sure that with this and some additional support
40 // classes we can support similar functionality in other formats
41 // (read DocBook).
42 // By using float.sty we will have the same handling for all floats, both
43 // for those already in existance (table and figure) and all user created
44 // ones¹. So suddenly we give the users the possibility of creating new
45 // kinds of floats on the fly. (and with a uniform look)
46 //
47 // API to float.sty:
48 //   \newfloat{type}{placement}{ext}[within]
49 //     type      - The "type" of the new class of floats, like program or
50 //                 algorithm. After the appropriate \newfloat, commands
51 //                 such as \begin{program} or \end{algorithm*} will be
52 //                 available.
53 //     placement - The default placement for the given class of floats.
54 //                 They are like in standard LaTeX: t, b, p and h for top,
55 //                 bottom, page, and here, respectively. On top of that
56 //                 there is a new type, H, which does not really correspond
57 //                 to a float, since it means: put it "here" and nowhere else.
58 //                 Note, however that the H specifier is special and, because
59 //                 of implementation details cannot be used in the second
60 //                 argument of \newfloat.
61 //     ext       - The file name extension of an auxiliary file for the list
62 //                 of figures (or whatever). LaTeX writes the captions to
63 //                 this file.
64 //     within    - This (optional) argument determines whether floats of this
65 //                 class will be numbered within some sectional unit of the
66 //                 document. For example, if within is equal to chapter, the
67 //                 floats will be numbered within chapters.
68 //   \floatstyle{style}
69 //     style -  plain, boxed, ruled
70 //   \floatname{float}{floatname}
71 //     float     -
72 //     floatname -
73 //   \floatplacement{float}{placement}
74 //     float     -
75 //     placement -
76 //   \restylefloat{float}
77 //     float -
78 //   \listof{type}{title}
79 //     title -
80
81 // ¹ the algorithm float is defined using the float.sty package. Like this
82 //   \floatstyle{ruled}
83 //   \newfloat{algorithm}{htbp}{loa}[<sect>]
84 //   \floatname{algorithm}{Algorithm}
85 //
86 // The intention is that floats should be definable from two places:
87 //          - layout files
88 //          - the "gui" (i.e. by the user)
89 //
90 // From layout files.
91 // This should only be done for floats defined in a documentclass and that
92 // does not need any additional packages. The two most known floats in this
93 // category is "table" and "figure". Floats defined in layout files are only
94 // stored in lyx files if the user modifies them.
95 //
96 // By the user.
97 // There should be a gui dialog (and also a collection of lyxfuncs) where
98 // the user can modify existing floats and/or create new ones.
99 //
100 // The individual floats will also have some settable
101 // variables: wide and placement.
102 //
103 // Lgb
104
105 namespace {
106
107 // this should not be hardcoded, but be part of the definition
108 // of the float (JMarc)
109 string const caplayout("Caption");
110
111 string floatname(string const & type, BufferParams const & bp)
112 {
113         FloatList const & floats = bp.getLyXTextClass().floats();
114         FloatList::const_iterator it = floats[type];
115         if (it == floats.end())
116                 return type;
117
118         return _(it->second.name());
119 }
120
121 } // namespace anon
122
123
124 InsetFloat::InsetFloat(BufferParams const & bp, string const & type)
125         : InsetCollapsable(bp), wide_(false)
126 {
127         string lab(_("float: "));
128         lab += floatname(type, bp);
129         setLabel(lab);
130         LyXFont font(LyXFont::ALL_SANE);
131         font.decSize();
132         font.decSize();
133         font.setColor(LColor::collapsable);
134         setLabelFont(font);
135         floatType_ = type;
136         setInsetName(type);
137         LyXTextClass const & tclass = bp.getLyXTextClass();
138         if (tclass.hasLayout(caplayout))
139                 inset.paragraph()->layout(tclass[caplayout]);
140 }
141
142
143 InsetFloat::InsetFloat(InsetFloat const & in, bool same_id)
144         : InsetCollapsable(in, same_id), floatType_(in.floatType_),
145           floatPlacement_(in.floatPlacement_), wide_(in.wide_)
146 {}
147
148
149 InsetFloat::~InsetFloat()
150 {
151         hideDialog();
152 }
153
154
155 void InsetFloat::write(Buffer const * buf, ostream & os) const
156 {
157         os << "Float " // getInsetName()
158            << floatType_ << '\n';
159
160         if (!floatPlacement_.empty()) {
161                 os << "placement " << floatPlacement_ << "\n";
162         }
163         if (wide_) {
164                 os << "wide true\n";
165         } else {
166                 os << "wide false\n";
167         }
168
169         InsetCollapsable::write(buf, os);
170 }
171
172
173 void InsetFloat::read(Buffer const * buf, LyXLex & lex)
174 {
175         if (lex.isOK()) {
176                 lex.next();
177                 string token = lex.getString();
178                 if (token == "placement") {
179                         lex.next();
180                         floatPlacement_ = lex.getString();
181                 } else {
182                         // take countermeasures
183                         lex.pushToken(token);
184                 }
185                 lex.next();
186                 token = lex.getString();
187                 if (token == "wide") {
188                         lex.next();
189                         string const tmptoken = lex.getString();
190                         if (tmptoken == "true")
191                                 wide(true, buf->params);
192                         else
193                                 wide(false, buf->params);
194                 } else {
195                         lyxerr << "InsetFloat::Read:: Missing wide!"
196                                << endl;
197                         // take countermeasures
198                         lex.pushToken(token);
199                 }
200         }
201         InsetCollapsable::read(buf, lex);
202 }
203
204
205 void InsetFloat::validate(LaTeXFeatures & features) const
206 {
207         if (contains(placement(), "H")) {
208                 features.require("float");
209         }
210
211         features.useFloat(floatType_);
212         InsetCollapsable::validate(features);
213 }
214
215
216 Inset * InsetFloat::clone(Buffer const &, bool same_id) const
217 {
218         return new InsetFloat(*const_cast<InsetFloat *>(this), same_id);
219 }
220
221
222 string const InsetFloat::editMessage() const
223 {
224         return _("Opened Float Inset");
225 }
226
227
228 int InsetFloat::latex(Buffer const * buf,
229                       ostream & os, bool fragile, bool fp) const
230 {
231         FloatList const & floats = buf->params.getLyXTextClass().floats();
232         string const tmptype = (wide_ ? floatType_ + "*" : floatType_);
233         // Figure out the float placement to use.
234         // From lowest to highest:
235         // - float default placement
236         // - document wide default placement
237         // - specific float placement
238         string placement;
239         string const buf_placement = buf->params.float_placement;
240         string const def_placement = floats.defaultPlacement(floatType_);
241         if (!floatPlacement_.empty()
242             && floatPlacement_ != def_placement) {
243                 placement = floatPlacement_;
244         } else if (floatPlacement_.empty() 
245                    && !buf_placement.empty()
246                    && buf_placement != def_placement) {
247                 placement = buf_placement;
248         }
249
250         // The \n is used to force \begin{<floatname>} to appear in a new line.
251         // The % is needed to prevent two consecutive \n chars in the case
252         // when the current output line is empty.
253         os << "%\n\\begin{" << tmptype << "}";
254         // We only output placement if different from the def_placement.
255         if (!placement.empty()) {
256                 os << "[" << placement << "]";
257         }
258         os << "\n";
259
260         int const i = inset.latex(buf, os, fragile, fp);
261
262         // The \n is used to force \end{<floatname>} to appear in a new line.
263         // In this case, we do not case if the current output line is empty.
264         os << "\n\\end{" << tmptype << "}\n";
265
266         return i + 4;
267 }
268
269
270 int InsetFloat::docbook(Buffer const * buf, ostream & os, bool mixcont) const
271 {
272         os << "<" << floatType_ << ">";
273         int const i = inset.docbook(buf, os, mixcont);
274         os << "</" << floatType_ << ">";
275
276         return i;
277 }
278
279
280 bool InsetFloat::insetAllowed(Inset::Code code) const
281 {
282         if (code == Inset::FLOAT_CODE)
283                 return false;
284         if (inset.getLockingInset() != const_cast<InsetFloat *>(this))
285                 return inset.insetAllowed(code);
286         if ((code == Inset::FOOT_CODE) || (code == Inset::MARGIN_CODE))
287                 return false;
288         return true;
289 }
290
291
292 bool InsetFloat::showInsetDialog(BufferView * bv) const
293 {
294         if (!inset.showInsetDialog(bv)) {
295                 bv->owner()->getDialogs().showFloat(const_cast<InsetFloat *>(this));
296         }
297         return true;
298 }
299
300
301 string const & InsetFloat::type() const
302 {
303         return floatType_;
304 }
305
306
307 void InsetFloat::placement(string const & p)
308 {
309         // FIX: Here we should only allow the placement to be set
310         // if a valid value.
311         floatPlacement_ = p;
312 }
313
314
315 string const & InsetFloat::placement() const
316 {
317         return floatPlacement_;
318 }
319
320
321 void InsetFloat::wide(bool w, BufferParams const & bp)
322 {
323         wide_ = w;
324
325         string lab(_("float:"));
326         lab += floatname(floatType_, bp);
327
328         if (wide_)
329                 lab += "*";
330
331         setLabel(lab);
332 }
333
334
335 bool InsetFloat::wide() const
336 {
337         return wide_;
338 }
339
340
341 void InsetFloat::addToToc(toc::TocList & toclist, Buffer const * buf) const
342 {
343         ParIterator pit(inset.paragraph());
344         ParIterator end;
345
346         // Find a caption layout in one of the (child inset's) pars
347         for (; pit != end; ++pit) {
348                 Paragraph * tmp = *pit;
349  
350                 if (tmp->layout()->name() == caplayout) {
351                         string const str =
352                                 tostr(toclist[type()].size() + 1)
353                                 + ". " + tmp->asString(buf, false);
354                         toc::TocItem const item(tmp, 0 , str);
355                         toclist[type()].push_back(item);
356                 }
357         }
358 }