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