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