]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiViewSource.cpp
ef34dc5500b3bab9c2396efab43e1e5435c1d358
[lyx.git] / src / frontends / qt4 / GuiViewSource.cpp
1 /**
2  * \file GuiViewSource.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Bo Peng
8  * \author Abdelrazak Younes
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiViewSource.h"
16 #include "qt_helpers.h"
17
18 #include "Application.h"
19 #include "BufferView.h"
20 #include "Buffer.h"
21 #include "Cursor.h"
22 #include "gettext.h"
23 #include "Paragraph.h"
24 #include "TexRow.h"
25
26 #include <QTextCursor>
27 #include <QTextDocument>
28 #include <boost/tuple/tuple.hpp>
29
30 using std::string;
31
32 namespace lyx {
33 namespace frontend {
34
35 GuiViewSourceDialog::GuiViewSourceDialog(ControlViewSource & controller)
36         :       controller_(controller), document_(new QTextDocument(this)),
37                 highlighter_(new LaTeXHighlighter(document_))
38 {
39         setupUi(this);
40         setWindowTitle(qt_("LaTeX Source"));
41
42         connect(viewFullSourceCB, SIGNAL(clicked()),
43                 this, SLOT(updateView()));
44         connect(autoUpdateCB, SIGNAL(toggled(bool)),
45                 updatePB, SLOT(setDisabled(bool)));
46         connect(updatePB, SIGNAL(clicked()),
47                 this, SLOT(updateView()));
48
49         // setting a document at this point trigger an assertion in Qt
50         // so we disable the signals here:
51         document()->blockSignals(true);
52         viewSourceTV->setDocument(document());
53         document()->blockSignals(false);
54         viewSourceTV->setReadOnly(true);
55         ///dialog_->viewSourceTV->setAcceptRichText(false);
56         // this is personal. I think source code should be in fixed-size font
57         QFont font(toqstr(theApp()->typewriterFontName()));
58         font.setKerning(false);
59         font.setFixedPitch(true);
60         font.setStyleHint(QFont::TypeWriter);
61         viewSourceTV->setFont(font);
62         // again, personal taste
63         viewSourceTV->setWordWrapMode(QTextOption::NoWrap);
64 }
65
66
67 void GuiViewSourceDialog::updateView()
68 {
69         if (autoUpdateCB->isChecked())
70                 update(viewFullSourceCB->isChecked());
71
72         int beg, end;
73         boost::tie(beg, end) = controller_.getRows();
74         QTextCursor c = QTextCursor(viewSourceTV->document());
75         c.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, beg);
76         c.select(QTextCursor::BlockUnderCursor);
77         c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor, end - beg + 1);
78         viewSourceTV->setTextCursor(c);
79         QWidget::update();
80 }
81
82
83 void GuiViewSourceDialog::update(bool full_source)
84 {
85         document_->setPlainText(toqstr(controller_.updateContent(full_source)));
86 }
87
88
89
90 /////////////////////////////////////////////////////////////////////
91 //
92 // LaTeXHighlighter
93 //
94 /////////////////////////////////////////////////////////////////////
95
96
97 LaTeXHighlighter::LaTeXHighlighter(QTextDocument * parent)
98         : QSyntaxHighlighter(parent)
99 {
100         keywordFormat.setForeground(Qt::darkBlue);
101         keywordFormat.setFontWeight(QFont::Bold);
102         commentFormat.setForeground(Qt::darkGray);
103         mathFormat.setForeground(Qt::red);
104 }
105
106
107 void LaTeXHighlighter::highlightBlock(QString const & text)
108 {
109         // $ $
110         QRegExp exprMath("\\$[^\\$]*\\$");
111         int index = text.indexOf(exprMath);
112         while (index >= 0) {
113                 int length = exprMath.matchedLength();
114                 setFormat(index, length, mathFormat);
115                 index = text.indexOf(exprMath, index + length);
116         }
117         // [ ]
118         QRegExp exprStartDispMath("(\\\\\\[|"
119                 "\\\\begin\\{equation\\**\\}|"
120                 "\\\\begin\\{eqnarray\\**\\}|"
121                 "\\\\begin\\{align(ed|at)*\\**\\}|"
122                 "\\\\begin\\{flalign\\**\\}|"
123                 "\\\\begin\\{gather\\**\\}|"
124                 "\\\\begin\\{multline\\**\\}|"
125                 "\\\\begin\\{array\\**\\}|"
126                 "\\\\begin\\{cases\\**\\}"
127                 ")");
128         QRegExp exprEndDispMath("(\\\\\\]|"
129                 "\\\\end\\{equation\\**\\}|"
130                 "\\\\end\\{eqnarray\\**\\}|"
131                 "\\\\end\\{align(ed|at)*\\**\\}|"
132                 "\\\\end\\{flalign\\**\\}|"
133                 "\\\\end\\{gather\\**\\}|"
134                 "\\\\end\\{multline\\**\\}|"
135                 "\\\\end\\{array\\**\\}|"
136                 "\\\\end\\{cases\\**\\}"
137                 ")");
138         int startIndex = 0;
139         // if previous block was in 'disp math'
140         // start search from 0 (for end disp math)
141         // otherwise, start search from 'begin disp math'
142         if (previousBlockState() != 1)
143                 startIndex = text.indexOf(exprStartDispMath);
144         while (startIndex >= 0) {
145                 int endIndex = text.indexOf(exprEndDispMath, startIndex);
146                 int length;
147                 if (endIndex == -1) {
148                         setCurrentBlockState(1);
149                         length = text.length() - startIndex;
150                 } else {
151                         length = endIndex - startIndex + exprEndDispMath.matchedLength();
152                 }
153                 setFormat(startIndex, length, mathFormat);
154                 startIndex = text.indexOf(exprStartDispMath, startIndex + length);
155         }
156         // \whatever
157         QRegExp exprKeyword("\\\\[A-Za-z]+");
158         index = text.indexOf(exprKeyword);
159         while (index >= 0) {
160                 int length = exprKeyword.matchedLength();
161                 setFormat(index, length, keywordFormat);
162                 index = text.indexOf(exprKeyword, index + length);
163         }
164         // comment
165         QRegExp exprComment("(^|[^\\\\])%.*$");
166         index = text.indexOf(exprComment);
167         while (index >= 0) {
168                 int const length = exprComment.matchedLength();
169                 setFormat(index, length, commentFormat);
170                 index = text.indexOf(exprComment, index + length);
171         }
172 }
173
174
175 ControlViewSource::ControlViewSource(Dialog & parent)
176         : Controller(parent)
177 {}
178
179
180 bool ControlViewSource::initialiseParams(string const & /*source*/)
181 {
182         return true;
183 }
184
185
186 docstring const ControlViewSource::updateContent(bool fullSource)
187 {
188         // get the *top* level paragraphs that contain the cursor,
189         // or the selected text
190         pit_type par_begin;
191         pit_type par_end;
192
193         BufferView * view = bufferview();
194         if (!view->cursor().selection()) {
195                 par_begin = view->cursor().bottom().pit();
196                 par_end = par_begin;
197         } else {
198                 par_begin = view->cursor().selectionBegin().bottom().pit();
199                 par_end = view->cursor().selectionEnd().bottom().pit();
200         }
201         if (par_begin > par_end)
202                 std::swap(par_begin, par_end);
203         odocstringstream ostr;
204         view->buffer().getSourceCode(ostr, par_begin, par_end + 1, fullSource);
205         return ostr.str();
206 }
207
208
209 std::pair<int, int> ControlViewSource::getRows() const
210 {
211         BufferView const * view = bufferview();
212         CursorSlice beg = view->cursor().selectionBegin().bottom();
213         CursorSlice end = view->cursor().selectionEnd().bottom();
214
215         int begrow = view->buffer().texrow().
216                 getRowFromIdPos(beg.paragraph().id(), beg.pos());
217         int endrow = view->buffer().texrow().
218                 getRowFromIdPos(end.paragraph().id(), end.pos());
219         int nextendrow = view->buffer().texrow().
220                 getRowFromIdPos(end.paragraph().id(), end.pos() + 1);
221         return std::make_pair(begrow, endrow == nextendrow ? endrow : (nextendrow - 1));
222 }
223
224
225 docstring const ControlViewSource::title() const
226 {
227         switch (docType()) {
228                 case LATEX:
229                         return _("LaTeX Source");
230                 case DOCBOOK:
231                         return _("DocBook Source");
232                 case LITERATE:
233                         return _("Literate Source");
234                 default:
235                         BOOST_ASSERT(false);
236                         return docstring();
237         }
238 }
239
240
241 Dialog * createGuiViewSource(LyXView & lv)
242 {
243         return new GuiViewSource(static_cast<GuiViewBase &>(lv));
244 }
245
246
247 } // namespace frontend
248 } // namespace lyx
249
250 #include "GuiViewSource_moc.cpp"