]> git.lyx.org Git - lyx.git/blob - src/mathed/formula.C
add missing writeNormal() methods to some insets
[lyx.git] / src / mathed / formula.C
1 /*
2 *  File:        formula.C
3 *  Purpose:     Implementation of formula inset
4 *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5 *  Created:     January 1996
6 *  Description: Allows the edition of math paragraphs inside Lyx.
7 *
8 *  Copyright: 1996-1998 Alejandro Aguilar Sierra
9 *
10 *  Version: 0.4, Lyx project.
11 *
12 *   You are free to use and modify this code under the terms of
13 *   the GNU General Public Licence version 2 or later.
14 */
15
16 #ifdef __GNUG__
17 #pragma implementation
18 #endif
19
20 #include <config.h>
21
22 #include "formula.h"
23 #include "commandtags.h"
24 #include "math_cursor.h"
25 #include "math_parser.h"
26 #include "math_charinset.h"
27 #include "lyx_main.h"
28 #include "BufferView.h"
29 #include "gettext.h"
30 #include "debug.h"
31 #include "lyx_gui_misc.h"
32 #include "support/LOstream.h"
33 #include "support/LAssert.h"
34 #include "support/lyxlib.h"
35 #include "support/syscall.h"
36 #include "support/lstrings.h"
37 #include "support/filetools.h" // LibFileSearch
38 #include "LyXView.h"
39 #include "Painter.h"
40 #include "lyxrc.h"
41 #include "math_matrixinset.h"
42 #include "mathed/support.h"
43
44 using std::ostream;
45 using std::ifstream;
46 using std::istream;
47 using std::pair;
48 using std::endl;
49 using std::vector;
50
51
52 namespace {
53
54         void stripFromLastEqualSign(MathArray & ar)
55         {
56                 // find position of last '=' in the array
57                 MathArray::size_type pos = ar.size();
58                 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
59                         if ((*it)->getChar() == '=')
60                                 pos = it - ar.begin();
61
62                 // delete everything behind this position
63                 ar.erase(pos, ar.size());
64         }
65
66
67         MathArray pipeThroughExtern(string const & arg, MathArray const & ar)
68         {
69                 string lang;
70                 string extra;
71                 istringstream iss(arg.c_str());
72                 iss >> lang >> extra;
73                 if (extra.empty())
74                         extra = "noextra";      
75
76                 // create normalized expression
77                 string outfile = lyx::tempName(string(), "mathextern");
78                 ostringstream os;
79                 os << "[" << extra << ' ';
80                 ar.writeNormal(os); 
81                 os << "]";
82                 string code = os.str().c_str();
83
84                 // run external sript
85                 string file = LibFileSearch(string(), "lyx2" + lang);
86                 if (file.empty()) {
87                         lyxerr << "converter to '" << lang << "' not found\n";
88                         return MathArray();
89                 }
90                 string script = file + " '" + code + "' " + outfile;
91                 lyxerr << "calling: " << script << endl;
92                 Systemcalls cmd(Systemcalls::System, script, 0);
93
94                 // append result
95                 MathArray res;
96                 mathed_parse_cell(res, GetFileContents(outfile));
97                 return res;
98         }
99
100 }
101
102
103 InsetFormula::InsetFormula()
104         : par_(MathAtom(new MathMatrixInset))
105 {}
106
107
108 InsetFormula::InsetFormula(MathInsetTypes t)
109         : par_(MathAtom(new MathMatrixInset(t)))
110 {}
111
112
113 InsetFormula::InsetFormula(string const & s) 
114 {
115         if (s.size()) {
116                 bool res = mathed_parse_normal(par_, s);
117
118                 if (!res)
119                         res = mathed_parse_normal(par_, "$" + s + "$");
120
121                 if (!res) {
122                         lyxerr << "cannot interpret '" << s << "' as math\n";
123                         par_ = MathAtom(new MathMatrixInset(LM_OT_SIMPLE));
124                 }
125         }
126         metrics();
127 }
128
129
130 Inset * InsetFormula::clone(Buffer const &, bool) const
131 {
132         return new InsetFormula(*this);
133 }
134
135
136 void InsetFormula::write(Buffer const * buf, ostream & os) const
137 {
138         os << "Formula ";
139         latex(buf, os, false, false);
140 }
141
142
143 int InsetFormula::latex(Buffer const * buf, ostream & os, bool fragil, bool)
144         const
145 {
146         MathWriteInfo wi(buf, os, fragil);
147         par_->write(wi);
148         return 1;
149 }
150
151
152 int InsetFormula::ascii(Buffer const * buf, ostream & os, int) const
153 {
154         MathWriteInfo wi(buf, os, false);
155         par_->write(wi);
156         return 1;
157 }
158
159
160 int InsetFormula::linuxdoc(Buffer const * buf, ostream & os) const
161 {
162         return ascii(buf, os, 0);
163 }
164
165
166 int InsetFormula::docbook(Buffer const * buf, ostream & os) const
167 {
168         return ascii(buf, os, 0);
169 }
170
171
172 void InsetFormula::read(Buffer const *, LyXLex & lex)
173 {
174         mathed_parse_normal(par_, lex);
175         metrics();
176 }
177
178
179 void InsetFormula::draw(BufferView * bv, LyXFont const & font,
180                         int y, float & xx, bool) const
181 {
182         int x = int(xx) - 1;
183         y -= 2;
184
185         Painter & pain = bv->painter();
186
187         metrics(bv, font);
188         int w = par_->width();
189         int h = par_->height();
190         int a = par_->ascent();
191         pain.fillRectangle(x, y - a, w, h, LColor::mathbg);
192
193         if (mathcursor && mathcursor->formula() == this) {
194                 mathcursor->drawSelection(pain);
195                 pain.rectangle(x, y - a, w, h, LColor::mathframe);
196         }
197
198         par_->draw(pain, x, y);
199         xx += par_->width();
200         xo_ = x;
201         yo_ = y;
202
203         setCursorVisible(false);
204 }
205
206
207 vector<string> const InsetFormula::getLabelList() const
208 {
209         return mat()->getLabelList();
210 }
211
212
213 UpdatableInset::RESULT
214 InsetFormula::localDispatch(BufferView * bv, kb_action action,
215          string const & arg)
216 {
217         RESULT result = DISPATCHED;
218
219         switch (action) {
220
221                 case LFUN_BREAKLINE: 
222                         bv->lockedInsetStoreUndo(Undo::INSERT);
223                         mathcursor->breakLine();
224                         mathcursor->normalize();
225                         updateLocal(bv, true);
226                         break;
227
228                 case LFUN_MATH_NUMBER:
229                 {
230                         //lyxerr << "toggling all numbers\n";
231                         if (display()) {
232                                 bv->lockedInsetStoreUndo(Undo::INSERT);
233                                 bool old = mat()->numberedType();
234                                 for (MathInset::row_type row = 0; row < par_->nrows(); ++row)
235                                         mat()->numbered(row, !old);
236                                 bv->owner()->message(old ? _("No number") : _("Number"));
237                                 updateLocal(bv, true);
238                         }
239                         break;
240                 }
241
242                 case LFUN_MATH_NONUMBER:
243                 {
244                         //lyxerr << "toggling line number\n";
245                         if (display()) {
246                                 bv->lockedInsetStoreUndo(Undo::INSERT);
247                                 MathCursor::row_type row = mathcursor->row();
248                                 bool old = mat()->numbered(row);
249                                 bv->owner()->message(old ? _("No number") : _("Number"));
250                                 mat()->numbered(row, !old);
251                                 updateLocal(bv, true);
252                         }
253                         break;
254                 }
255
256                 case LFUN_INSERT_LABEL:
257                 {
258                         bv->lockedInsetStoreUndo(Undo::INSERT);
259
260                         MathCursor::row_type row = mathcursor->row();
261                         string old_label = mat()->label(row);
262                         string new_label = arg;
263
264                         if (new_label.empty()) {
265                                 string const default_label =
266                                         (lyxrc.label_init_length >= 0) ? "eq:" : "";
267                                 pair<bool, string> const res = old_label.empty()
268                                         ? askForText(_("Enter new label to insert:"), default_label)
269                                         : askForText(_("Enter label:"), old_label);
270                                 
271                                 lyxerr << "res: " << res.first << " - '" << res.second << "'\n";
272                                 if (!res.first)
273                                         break;
274                                 new_label = frontStrip(strip(res.second));
275                         }
276
277                         //if (new_label == old_label)
278                         //      break;  // Nothing to do
279
280                         if (!new_label.empty()) {
281                                 lyxerr << "setting label to '" << new_label << "'\n";
282                                 mat()->numbered(row, true);
283                         }
284
285                         if (!new_label.empty() && bv->ChangeRefsIfUnique(old_label, new_label))
286                                 bv->redraw();
287
288                         mat()->label(row, new_label);
289
290                         updateLocal(bv, true);
291                         break;
292                 }
293
294                 case LFUN_MATH_EXTERN:
295                         bv->lockedInsetStoreUndo(Undo::EDIT);
296                         handleExtern(arg);
297                         // re-compute inset dimension
298                         metrics(bv);
299                         updateLocal(bv, true);
300                         break;
301
302                 case LFUN_MATH_MUTATE:
303                 {
304                         bv->lockedInsetStoreUndo(Undo::EDIT);
305                         int x;
306                         int y;
307                         mathcursor->getPos(x, y);
308                         mat()->mutate(arg);
309                         mathcursor->setPos(x, y);
310                         mathcursor->normalize();
311                         updateLocal(bv, true);
312                         break;
313                 }
314
315                 case LFUN_MATH_DISPLAY:
316                 {
317                         int x;
318                         int y;
319                         mathcursor->getPos(x, y);
320                         if (mat()->getType() == LM_OT_SIMPLE)
321                                 mat()->mutate(LM_OT_EQUATION);
322                         else
323                                 mat()->mutate(LM_OT_SIMPLE);
324                         mathcursor->setPos(x, y);
325                         mathcursor->normalize();
326                         updateLocal(bv, true);
327                         break;
328                 }
329                 
330                 case LFUN_PASTESELECTION:
331                 {
332                         string const clip = bv->getClipboard();
333                 if (!clip.empty())
334                                 mathed_parse_normal(par_, clip);
335                         break;
336                 }
337
338                 case LFUN_MATH_COLUMN_INSERT:
339                 {
340                         if (mat()->getType() == LM_OT_ALIGN)
341                                 mat()->mutate(LM_OT_ALIGNAT);
342                         mat()->addCol(mat()->ncols());
343                         mathcursor->normalize();
344                         updateLocal(bv, true);
345                 }
346
347                 default:
348                         result = InsetFormulaBase::localDispatch(bv, action, arg);
349         }
350
351         return result;
352 }
353
354
355 void InsetFormula::handleExtern(const string & arg)
356 {
357         // where are we?
358         if (!mathcursor)
359                 return; 
360
361         bool selected = mathcursor->selection();
362
363         MathArray ar;
364         if (selected) {
365                 mathcursor->selGet(ar);
366                 lyxerr << "use selection: " << ar << "\n";
367         } else {
368                 mathcursor->end();
369                 ar = mathcursor->cursor().cell();
370                 stripFromLastEqualSign(ar);
371                 mathcursor->insert(MathAtom(new MathCharInset('=', LM_TC_VAR)));
372                 lyxerr << "use whole cell: " << ar << "\n";
373         }
374
375         mathcursor->insert(pipeThroughExtern(arg, ar));
376 }
377
378
379 bool InsetFormula::display() const
380 {
381         return mat()->getType() != LM_OT_SIMPLE;
382 }
383
384
385 MathMatrixInset const * InsetFormula::mat() const
386 {
387         lyx::Assert(par_->asMatrixInset());
388         return par_->asMatrixInset();
389 }
390
391
392 MathMatrixInset * InsetFormula::mat()
393 {
394         lyx::Assert(par_->asMatrixInset());
395         return par_->asMatrixInset();
396 }
397
398
399 Inset::Code InsetFormula::lyxCode() const
400 {
401         return Inset::MATH_CODE;
402 }
403
404
405 void InsetFormula::validate(LaTeXFeatures & features) const
406 {
407         par_->validate(features);
408 }
409
410
411 bool InsetFormula::insetAllowed(Inset::Code code) const
412 {
413         return code == Inset::LABEL_CODE && display(); 
414 }
415
416
417 int InsetFormula::ascent(BufferView *, LyXFont const &) const
418 {
419         return par_->ascent() + 2;
420 }
421
422
423 int InsetFormula::descent(BufferView *, LyXFont const &) const
424 {
425         return par_->descent() - 2;
426 }
427
428
429 int InsetFormula::width(BufferView * bv, LyXFont const & font) const
430 {
431         metrics(bv, font);
432         return par_->width();
433 }
434
435
436 MathInsetTypes InsetFormula::getType() const
437 {
438         return mat()->getType();
439 }