]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBranch.cpp
Amend 6c3447c8: FindAdv: sometimes a space is added on some math symbols
[lyx.git] / src / insets / InsetBranch.cpp
1 /**
2  * \file InsetBranch.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Martin Vermeer
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetBranch.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "BufferView.h"
18 #include "BranchList.h"
19 #include "ColorSet.h"
20 #include "Cursor.h"
21 #include "DispatchResult.h"
22 #include "FuncRequest.h"
23 #include "FuncStatus.h"
24 #include "Inset.h"
25 #include "LaTeXFeatures.h"
26 #include "LyX.h"
27 #include "output_docbook.h"
28 #include "output_xhtml.h"
29 #include "TextClass.h"
30 #include "TocBackend.h"
31
32 #include "support/convert.h"
33 #include "support/debug.h"
34 #include "support/gettext.h"
35 #include "support/Lexer.h"
36 #include "support/lstrings.h"
37
38 #include "frontends/alert.h"
39 #include "frontends/Application.h"
40
41 #include <sstream>
42
43 using namespace std;
44
45
46 namespace lyx {
47
48 using support::Lexer;
49
50 InsetBranch::InsetBranch(Buffer * buf, InsetBranchParams const & params)
51         : InsetCollapsible(buf, InsetText::DefaultLayout), params_(params)
52 {}
53
54
55 void InsetBranch::write(ostream & os) const
56 {
57         os << "Branch ";
58         params_.write(os);
59         os << '\n';
60         InsetCollapsible::write(os);
61 }
62
63
64 void InsetBranch::read(Lexer & lex)
65 {
66         params_.read(lex);
67         InsetCollapsible::read(lex);
68 }
69
70
71 docstring InsetBranch::toolTip(BufferView const & bv, int, int) const
72 {
73         docstring const masterstatus = isBranchSelected() ?
74                 _("active") : _("non-active");
75         docstring const childstatus = isBranchSelected(true) ?
76                 _("active") : _("non-active");
77         docstring const status = (masterstatus == childstatus) ?
78                 masterstatus :
79                 support::bformat(_("master %1$s, child %2$s"),
80                                                  masterstatus, childstatus);
81
82         docstring const masteron = producesOutput() ?
83                 _("on") : _("off");
84         docstring const childon =
85                 (isBranchSelected(true) != params_.inverted) ?
86                         _("on") : _("off");
87         docstring const onoff = (masteron == childon) ?
88                 masteron :
89                 support::bformat(_("master %1$s, child %2$s"),
90                                                  masteron, childon);
91
92         docstring const heading =
93                 support::bformat(_("Branch Name: %1$s\nBranch Status: %2$s\nInset Status: %3$s"),
94                                                  params_.branch, status, onoff);
95
96         if (isOpen(bv))
97                 return heading;
98         return toolTipText(heading + from_ascii("\n"));
99 }
100
101
102 docstring const InsetBranch::buttonLabel(BufferView const &) const
103 {
104         static char_type const tick = 0x2714; // ✔ U+2714 HEAVY CHECK MARK
105         static char_type const cross = 0x2716; // ✖ U+2716 HEAVY MULTIPLICATION X
106
107         Buffer const & realbuffer = *buffer().masterBuffer();
108         BranchList const & branchlist = realbuffer.params().branchlist();
109         bool const inmaster = branchlist.find(params_.branch);
110         bool const inchild = buffer().params().branchlist().find(params_.branch);
111
112         bool const master_selected = producesOutput();
113         bool const child_selected = isBranchSelected(true) != params_.inverted;
114
115         docstring symb = docstring(1, master_selected ? tick : cross);
116         if (inchild && master_selected != child_selected)
117                 symb += (child_selected ? tick : cross);
118
119         docstring inv_symb = from_ascii(params_.inverted ? "~" : "");
120
121         if (decoration() == InsetDecoration::MINIMALISTIC)
122                 return symb + inv_symb + params_.branch;
123
124         if (!buffer_) {
125                 return symb + inv_symb + _("Branch (undefined): ")
126                         + params_.branch;
127         }
128         bool const has_layout =
129                 buffer().params().documentClass().hasInsetLayout(layoutName());
130         if (has_layout) {
131                 InsetLayout const & il = getLayout();
132                 docstring const & label_string = il.labelstring();
133                 if (!label_string.empty())
134                         return symb + inv_symb + label_string;
135         }
136         docstring s;
137         if (inmaster && inchild)
138                 s = _("Branch: ");
139         else if (inchild) // && !inmaster
140                 s = _("Branch (child): ");
141         else if (inmaster) // && !inchild
142                 s = _("Branch (master): ");
143         else // !inmaster && !inchild
144                 s = _("Branch (undefined): ");
145         s += inv_symb + params_.branch;
146
147         return symb + s;
148 }
149
150
151 ColorCode InsetBranch::backgroundColor(PainterInfo const & pi) const
152 {
153         if (params_.branch.empty())
154                 return Inset::backgroundColor(pi);
155         string const branch_id = (buffer().masterParams().branchlist().find(params_.branch))
156                         ? convert<string>(buffer().masterParams().branchlist().id())
157                         : convert<string>(buffer().params().branchlist().id());
158         // FIXME UNICODE
159         string const branchcol = "branch" + branch_id + to_utf8(params_.branch);
160         ColorCode c = lcolor.getFromLyXName(branchcol);
161         if (c == Color_none)
162                 c = Color_error;
163         return c;
164 }
165
166
167 void InsetBranch::doDispatch(Cursor & cur, FuncRequest & cmd)
168 {
169         switch (cmd.action()) {
170         case LFUN_INSET_MODIFY: {
171                 InsetBranchParams params;
172                 InsetBranch::string2params(to_utf8(cmd.argument()), params);
173
174                 cur.recordUndoInset(this);
175                 params_.branch = params.branch;
176                 params_.inverted = params.inverted;
177                 // what we really want here is a TOC update, but that means
178                 // a full buffer update
179                 cur.forceBufferUpdate();
180                 break;
181         }
182         case LFUN_BRANCH_ACTIVATE:
183         case LFUN_BRANCH_DEACTIVATE:
184         case LFUN_BRANCH_MASTER_ACTIVATE:
185         case LFUN_BRANCH_MASTER_DEACTIVATE:
186                 buffer().branchActivationDispatch(cmd.action(), params_.branch);
187                 break;
188         case LFUN_BRANCH_INVERT:
189                 cur.recordUndoInset(this);
190                 params_.inverted = !params_.inverted;
191                 // what we really want here is a TOC update, but that means
192                 // a full buffer update
193                 cur.forceBufferUpdate();
194                 break;
195         case LFUN_BRANCH_ADD:
196                 lyx::dispatch(FuncRequest(LFUN_BRANCH_ADD, params_.branch));
197                 break;
198         case LFUN_BRANCH_SYNC_ALL:
199                 lyx::dispatch(FuncRequest(LFUN_INSET_FORALL, "Branch:" + params_.branch + " inset-toggle assign"));
200                 break;
201         case LFUN_INSET_TOGGLE:
202                 if (cmd.argument() == "assign")
203                         setStatus(cur, (isBranchSelected(true) != params_.inverted) ? Open : Collapsed);
204                 else
205                         InsetCollapsible::doDispatch(cur, cmd);
206                 break;
207
208         default:
209                 InsetCollapsible::doDispatch(cur, cmd);
210                 break;
211         }
212 }
213
214
215 bool InsetBranch::getStatus(Cursor & cur, FuncRequest const & cmd,
216                 FuncStatus & flag) const
217 {
218         bool const known_branch =
219                 buffer().params().branchlist().find(params_.branch);
220
221         switch (cmd.action()) {
222         case LFUN_INSET_MODIFY:
223                 flag.setEnabled(true);
224                 break;
225
226         case LFUN_BRANCH_ACTIVATE:
227         case LFUN_BRANCH_DEACTIVATE:
228         case LFUN_BRANCH_MASTER_ACTIVATE:
229         case LFUN_BRANCH_MASTER_DEACTIVATE:
230                 flag.setEnabled(buffer().branchActivationEnabled(cmd.action(), params_.branch));
231                 break;
232
233         case LFUN_BRANCH_INVERT:
234                 flag.setEnabled(true);
235                 flag.setOnOff(params_.inverted);
236                 break;
237
238         case LFUN_BRANCH_ADD:
239                 flag.setEnabled(!known_branch);
240                 break;
241
242         case LFUN_BRANCH_SYNC_ALL:
243                 flag.setEnabled(known_branch);
244                 break;
245
246         case LFUN_INSET_TOGGLE:
247                 if (cmd.argument() == "assign")
248                         flag.setEnabled(true);
249                 else
250                         return InsetCollapsible::getStatus(cur, cmd, flag);
251                 break;
252
253         default:
254                 return InsetCollapsible::getStatus(cur, cmd, flag);
255         }
256         return true;
257 }
258
259
260 bool InsetBranch::isBranchSelected(bool const child) const
261 {
262         Buffer const & realbuffer = child ? buffer() : *buffer().masterBuffer();
263         BranchList const & branchlist = realbuffer.params().branchlist();
264         Branch const * ourBranch = branchlist.find(params_.branch);
265
266         if (!ourBranch) {
267                 // this branch is defined in child only
268                 ourBranch = buffer().params().branchlist().find(params_.branch);
269                 if (!ourBranch)
270                         return false;
271         }
272         return ourBranch->isSelected();
273 }
274
275
276 bool InsetBranch::producesOutput() const
277 {
278         return isBranchSelected() != params_.inverted;
279 }
280
281
282 void InsetBranch::latex(otexstream & os, OutputParams const & runparams) const
283 {
284         if (producesOutput() || runparams.find_with_non_output()) {
285                 OutputParams rp = runparams;
286                 rp.inbranch = true;
287                 InsetText::latex(os, rp);
288                 // These need to be passed upstream
289                 runparams.need_maketitle = rp.need_maketitle;
290                 runparams.have_maketitle = rp.have_maketitle;
291         }
292 }
293
294
295 int InsetBranch::plaintext(odocstringstream & os,
296                            OutputParams const & runparams, size_t max_length) const
297 {
298         if (!producesOutput() && !runparams.find_with_non_output())
299                 return 0;
300
301         int len = InsetText::plaintext(os, runparams, max_length);
302         return len;
303 }
304
305
306 void InsetBranch::docbook(XMLStream & xs, OutputParams const & runparams) const
307 {
308         if (producesOutput()) {
309                 OutputParams rp = runparams;
310                 rp.par_begin = 0;
311                 rp.par_end = text().paragraphs().size();
312                 docbookParagraphs(text(), buffer(), xs, rp);
313         }
314 }
315
316
317 docstring InsetBranch::xhtml(XMLStream & xs, OutputParams const & rp) const
318 {
319         if (producesOutput()) {
320                 OutputParams newrp = rp;
321                 newrp.par_begin = 0;
322                 newrp.par_end = text().paragraphs().size();
323                 xhtmlParagraphs(text(), buffer(), xs, newrp);
324         }
325         return docstring();
326 }
327
328
329 void InsetBranch::toString(odocstream & os) const
330 {
331         if (producesOutput())
332                 InsetCollapsible::toString(os);
333 }
334
335
336 void InsetBranch::forOutliner(docstring & os, size_t const maxlen,
337                                                           bool const shorten) const
338 {
339         if (producesOutput())
340                 InsetCollapsible::forOutliner(os, maxlen, shorten);
341 }
342
343
344 void InsetBranch::validate(LaTeXFeatures & features) const
345 {
346         // Showing previews in a disabled branch may require stuff
347         if (producesOutput() || features.runparams().for_preview)
348                 InsetCollapsible::validate(features);
349 }
350
351
352 string InsetBranch::contextMenuName() const
353 {
354         return "context-branch";
355 }
356
357
358 docstring InsetBranch::layoutName() const
359 {
360         docstring const name = support::subst(branch(), '_', ' ');
361         return from_ascii("Branch:") + name;
362 }
363
364
365
366 bool InsetBranch::isMacroScope() const
367 {
368         // Its own scope if not selected by buffer
369         return !producesOutput();
370 }
371
372
373 string InsetBranch::params2string(InsetBranchParams const & params)
374 {
375         ostringstream data;
376         params.write(data);
377         return data.str();
378 }
379
380
381 void InsetBranch::string2params(string const & in, InsetBranchParams & params)
382 {
383         params = InsetBranchParams();
384         if (in.empty())
385                 return;
386
387         istringstream data(in);
388         Lexer lex;
389         lex.setStream(data);
390         lex.setContext("InsetBranch::string2params");
391         params.read(lex);
392 }
393
394
395 void InsetBranch::updateBuffer(ParIterator const & it, UpdateType utype, bool const deleted)
396 {
397         setLabel(params_.branch + (params_.inverted ? " (-)" : ""));
398         InsetCollapsible::updateBuffer(it, utype, deleted);
399 }
400
401
402 void InsetBranchParams::write(ostream & os) const
403 {
404         os << to_utf8(branch)
405            << '\n'
406            << "inverted "
407            << inverted;
408 }
409
410
411 void InsetBranchParams::read(Lexer & lex)
412 {
413         // There may be a space in branch name
414         // if we wanted to use lex>>, the branch name should be properly in quotes
415         lex.eatLine();
416         branch = lex.getDocString();
417         lex >> "inverted" >> inverted;
418 }
419
420 } // namespace lyx