]> git.lyx.org Git - lyx.git/blob - src/insets/InsetERT.cpp
Fix bug #7404.
[lyx.git] / src / insets / InsetERT.cpp
1 /**
2  * \file InsetERT.cpp
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
12 #include <config.h>
13
14 #include "InsetERT.h"
15
16 #include "Buffer.h"
17 #include "BufferParams.h"
18 #include "BufferView.h"
19 #include "Cursor.h"
20 #include "CutAndPaste.h"
21 #include "DispatchResult.h"
22 #include "Format.h"
23 #include "FuncRequest.h"
24 #include "FuncStatus.h"
25 #include "Language.h"
26 #include "Layout.h"
27 #include "Lexer.h"
28 #include "LyXAction.h"
29 #include "OutputParams.h"
30 #include "ParagraphParameters.h"
31 #include "Paragraph.h"
32 #include "TextClass.h"
33
34 #include "support/docstream.h"
35 #include "support/FileName.h"
36 #include "support/gettext.h"
37 #include "support/lstrings.h"
38 #include "support/TempFile.h"
39
40 #include <sstream>
41
42 using namespace std;
43 using namespace lyx::support;
44
45 namespace lyx {
46
47 InsetERT::InsetERT(Buffer * buf, CollapseStatus status)
48         : InsetCollapsible(buf)
49 {
50         status_ = status;
51 }
52
53
54 // Do not copy the temp file on purpose: If a copy of an inset which is
55 // currently being edited is made, then we simply copy the current contents.
56 InsetERT::InsetERT(InsetERT const & that) : InsetCollapsible(that)
57 {}
58
59
60 InsetERT & InsetERT::operator=(InsetERT const & that)
61 {
62         if (&that == this)
63                 return *this;
64         tempfile_.reset();
65         return *this;
66 }
67
68
69 void InsetERT::write(ostream & os) const
70 {
71         os << "ERT" << "\n";
72         InsetCollapsible::write(os);
73 }
74
75
76 int InsetERT::plaintext(odocstringstream & os,
77         OutputParams const & rp, size_t max_length) const
78 {
79         if (!rp.inIndexEntry)
80                 // do not output TeX code
81                 return 0;
82
83         ParagraphList::const_iterator par = paragraphs().begin();
84         ParagraphList::const_iterator end = paragraphs().end();
85
86         while (par != end && os.str().size() <= max_length) {
87                 pos_type siz = par->size();
88                 for (pos_type i = 0; i < siz; ++i) {
89                         char_type const c = par->getChar(i);
90                         // output the active characters
91                         switch (c) {
92                         case '|':
93                         case '!':
94                         case '@':
95                                 os.put(c);
96                                 break;
97                         default:
98                                 break;
99                         }
100                 }
101                 ++par;
102         }
103         return 0;
104 }
105
106
107 int InsetERT::docbook(odocstream & os, OutputParams const &) const
108 {
109         // FIXME can we do the same thing here as for LaTeX?
110         ParagraphList::const_iterator par = paragraphs().begin();
111         ParagraphList::const_iterator end = paragraphs().end();
112
113         int lines = 0;
114         while (par != end) {
115                 pos_type siz = par->size();
116                 for (pos_type i = 0; i < siz; ++i)
117                         os.put(par->getChar(i));
118                 ++par;
119                 if (par != end) {
120                         os << "\n";
121                         ++lines;
122                 }
123         }
124
125         return lines;
126 }
127
128
129 void InsetERT::doDispatch(Cursor & cur, FuncRequest & cmd)
130 {
131         switch (cmd.action()) {
132         case LFUN_INSET_EDIT: {
133                 cur.push(*this);
134                 text().selectAll(cur);
135                 string const format =
136                         cur.buffer()->params().documentClass().outputFormat();
137                 string const ext = theFormats().extension(format);
138                 tempfile_.reset(new TempFile("ert_editXXXXXX." + ext));
139                 FileName const tempfilename = tempfile_->name();
140                 string const name = tempfilename.toFilesystemEncoding();
141                 ofdocstream os(name.c_str());
142                 os << cur.selectionAsString(false);
143                 os.close();
144                 // Since we lock the inset while the external file is edited,
145                 // we need to move the cursor outside and clear any selection inside
146                 cur.clearSelection();
147                 cur.pop();
148                 cur.leaveInset(*this);
149                 theFormats().edit(buffer(), tempfilename, format);
150                 break;
151         }
152         case LFUN_INSET_END_EDIT: {
153                 FileName const tempfilename = tempfile_->name();
154                 docstring const s = tempfilename.fileContents("UTF-8");
155                 cur.recordUndoInset(this);
156                 cur.push(*this);
157                 text().selectAll(cur);
158                 cap::replaceSelection(cur);
159                 cur.text()->insertStringAsLines(cur, s, cur.current_font);
160                 // FIXME it crashes without this
161                 cur.fixIfBroken();
162                 tempfile_.reset();
163                 cur.pop();
164                 break;
165         }
166         case LFUN_INSET_MODIFY:
167                 if (cmd.getArg(0) == "ert") {
168                         cur.recordUndoInset(this);
169                         setStatus(cur, string2params(to_utf8(cmd.argument())));
170                         break;
171                 }
172                 //fall-through
173         default:
174                 InsetCollapsible::doDispatch(cur, cmd);
175                 break;
176         }
177
178 }
179
180
181 bool InsetERT::getStatus(Cursor & cur, FuncRequest const & cmd,
182         FuncStatus & status) const
183 {
184         switch (cmd.action()) {
185         case LFUN_INSET_EDIT:
186                 status.setEnabled(tempfile_ == 0);
187                 return true;
188         case LFUN_INSET_END_EDIT:
189                 status.setEnabled(tempfile_ != 0);
190                 return true;
191         case LFUN_INSET_MODIFY:
192                 if (cmd.getArg(0) == "ert") {
193                         status.setEnabled(true);
194                         return true;
195                 }
196                 //fall through
197
198         default:
199                 return InsetCollapsible::getStatus(cur, cmd, status);
200         }
201 }
202
203
204 bool InsetERT::editable() const
205 {
206         if (tempfile_)
207                 return false;
208         return InsetCollapsible::editable();
209 }
210
211
212 bool InsetERT::descendable(BufferView const & bv) const
213 {
214         if (tempfile_)
215                 return false;
216         return InsetCollapsible::descendable(bv);
217 }
218
219
220 docstring const InsetERT::buttonLabel(BufferView const & bv) const
221 {
222         if (decoration() == InsetLayout::CLASSIC)
223                 return isOpen(bv) ? _("ERT") : getNewLabel(_("ERT"));
224         else
225                 return getNewLabel(_("ERT"));
226 }
227
228
229 InsetCollapsible::CollapseStatus InsetERT::string2params(string const & in)
230 {
231         if (in.empty())
232                 return Collapsed;
233         istringstream data(in);
234         Lexer lex;
235         lex.setStream(data);
236         lex.setContext("InsetERT::string2params");
237         lex >> "ert";
238         int s;
239         lex >> s;
240         return static_cast<CollapseStatus>(s);
241 }
242
243
244 string InsetERT::params2string(CollapseStatus status)
245 {
246         ostringstream data;
247         data << "ert" << ' ' << status;
248         return data.str();
249 }
250
251
252 docstring InsetERT::xhtml(XHTMLStream &, OutputParams const &) const
253 {
254         return docstring();
255 }
256
257 } // namespace lyx