]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiViewSource.cpp
Disambiguate std::bind, boost::bind, std::ref, boost::ref
[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 "GuiApplication.h"
16 #include "GuiViewSource.h"
17 #include "LaTeXHighlighter.h"
18 #include "qt_helpers.h"
19
20 #include "Buffer.h"
21 #include "BufferParams.h"
22 #include "BufferView.h"
23 #include "Cursor.h"
24 #include "Format.h"
25 #include "Paragraph.h"
26 #include "TexRow.h"
27
28 #include "support/debug.h"
29 #include "support/lassert.h"
30 #include "support/docstream.h"
31 #include "support/gettext.h"
32
33 #include <boost/crc.hpp>
34
35 #include <QSettings>
36 #include <QTextCursor>
37 #include <QTextDocument>
38 #include <QVariant>
39
40 using namespace std;
41
42 namespace lyx {
43 namespace frontend {
44
45 ViewSourceWidget::ViewSourceWidget()
46         :       bv_(0), document_(new QTextDocument(this)),
47                 highlighter_(new LaTeXHighlighter(document_)),
48                 force_getcontent_(true)
49 {
50         setupUi(this);
51
52         connect(contentsCO, SIGNAL(activated(int)),
53                 this, SLOT(contentsChanged()));
54         connect(autoUpdateCB, SIGNAL(toggled(bool)),
55                 updatePB, SLOT(setDisabled(bool)));
56         connect(autoUpdateCB, SIGNAL(toggled(bool)),
57                 this, SLOT(updateView()));
58         connect(masterPerspectiveCB, SIGNAL(toggled(bool)),
59                 this, SLOT(updateView()));
60         connect(updatePB, SIGNAL(clicked()),
61                 this, SLOT(updateView()));
62         connect(outputFormatCO, SIGNAL(activated(int)),
63                 this, SLOT(setViewFormat()));
64
65         // setting a document at this point trigger an assertion in Qt
66         // so we disable the signals here:
67         document_->blockSignals(true);
68         viewSourceTV->setDocument(document_);
69         document_->blockSignals(false);
70         viewSourceTV->setReadOnly(true);
71         ///dialog_->viewSourceTV->setAcceptRichText(false);
72         // this is personal. I think source code should be in fixed-size font
73         QFont font(guiApp->typewriterFontName());
74         font.setKerning(false);
75         font.setFixedPitch(true);
76         font.setStyleHint(QFont::TypeWriter);
77         viewSourceTV->setFont(font);
78         // again, personal taste
79         viewSourceTV->setWordWrapMode(QTextOption::NoWrap);
80 }
81
82
83 static size_t crcCheck(docstring const & s)
84 {
85         boost::crc_32_type crc;
86         crc.process_bytes(&s[0], sizeof(char_type) * s.size());
87         return crc.checksum();
88 }
89
90
91 /** get the source code of selected paragraphs, or the whole document
92         \param fullSource get full source code
93         \return true if the content has changed since last call.
94  */
95 static bool getContent(BufferView const * view, Buffer::OutputWhat output,
96                        QString & qstr, string const format, bool force_getcontent,
97                        bool master)
98 {
99         // get the *top* level paragraphs that contain the cursor,
100         // or the selected text
101         pit_type par_begin;
102         pit_type par_end;
103
104         if (!view->cursor().selection()) {
105                 par_begin = view->cursor().bottom().pit();
106                 par_end = par_begin;
107         } else {
108                 par_begin = view->cursor().selectionBegin().bottom().pit();
109                 par_end = view->cursor().selectionEnd().bottom().pit();
110         }
111         if (par_begin > par_end)
112                 swap(par_begin, par_end);
113         odocstringstream ostr;
114         view->buffer().getSourceCode(ostr, format, par_begin, par_end + 1,
115                                      output, master);
116         docstring s = ostr.str();
117         static size_t crc = 0;
118         size_t newcrc = crcCheck(s);
119         if (newcrc == crc && !force_getcontent)
120                 return false;
121         crc = newcrc;
122         qstr = toqstr(s);
123         return true;
124 }
125
126
127 void ViewSourceWidget::setBufferView(BufferView const * bv)
128 {
129         if (bv_ != bv)
130                 force_getcontent_ = true;
131         bv_ = bv;
132         setEnabled(bv ?  true : false);
133 }
134
135
136 void ViewSourceWidget::contentsChanged()
137 {
138         if (autoUpdateCB->isChecked())
139                 updateView();
140 }
141
142
143 void ViewSourceWidget::setViewFormat()
144 {
145         view_format_ = outputFormatCO->itemData(
146               outputFormatCO->currentIndex()).toString();
147         updateView();
148 }
149
150
151 void ViewSourceWidget::updateView()
152 {
153         if (!bv_) {
154                 document_->setPlainText(QString());
155                 setEnabled(false);
156                 return;
157         }
158
159         setEnabled(true);
160
161         string const format = fromqstr(view_format_);
162
163         QString content;
164         Buffer::OutputWhat output = Buffer::CurrentParagraph;
165         if (contentsCO->currentIndex() == 1)
166                 output = Buffer::FullSource;
167         else if (contentsCO->currentIndex() == 2)
168                 output = Buffer::OnlyPreamble;
169         else if (contentsCO->currentIndex() == 3)
170                 output = Buffer::OnlyBody;
171
172         if (getContent(bv_, output, content, format,
173                       force_getcontent_, masterPerspectiveCB->isChecked()))
174                 document_->setPlainText(content);
175
176         CursorSlice beg = bv_->cursor().selectionBegin().bottom();
177         CursorSlice end = bv_->cursor().selectionEnd().bottom();
178         int const begrow = bv_->buffer().texrow().
179                 getRowFromIdPos(beg.paragraph().id(), beg.pos());
180         int endrow = bv_->buffer().texrow().
181                 getRowFromIdPos(end.paragraph().id(), end.pos());
182         int const nextendrow = bv_->buffer().texrow().
183                 getRowFromIdPos(end.paragraph().id(), end.pos() + 1);
184         if (endrow != nextendrow)
185                 endrow = nextendrow - 1;
186
187         QTextCursor c = QTextCursor(viewSourceTV->document());
188         c.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, begrow);
189         c.select(QTextCursor::BlockUnderCursor);
190         c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor,
191                 endrow - begrow + 1);
192         viewSourceTV->setTextCursor(c);
193 }
194
195
196 void ViewSourceWidget::updateDefaultFormat()
197 {
198         if (!bv_)
199                 return;
200
201         outputFormatCO->blockSignals(true);
202         outputFormatCO->clear();
203         outputFormatCO->addItem(qt_("Default"),
204                                 QVariant(QString("default")));
205
206         int index = 0;
207         vector<string> tmp = bv_->buffer().params().backends();
208         vector<string>::const_iterator it = tmp.begin();
209         vector<string>::const_iterator en = tmp.end();
210         for (; it != en; ++it) {
211                 string const format = *it;
212                 Format const * fmt = formats.getFormat(format);
213                 if (!fmt) {
214                         LYXERR0("Can't find format for backend " << format << "!");
215                         continue;
216                 } 
217
218                 QString const pretty = qt_(fmt->prettyname());
219                 QString const qformat = toqstr(format);
220                 outputFormatCO->addItem(pretty, QVariant(qformat));
221                 if (qformat == view_format_)
222                    index = outputFormatCO->count() -1;
223         }
224         outputFormatCO->setCurrentIndex(index);
225
226         outputFormatCO->blockSignals(false);
227 }
228
229
230 GuiViewSource::GuiViewSource(GuiView & parent,
231                 Qt::DockWidgetArea area, Qt::WindowFlags flags)
232         : DockView(parent, "view-source", qt_("LaTeX Source"), area, flags)
233 {
234         widget_ = new ViewSourceWidget();
235         setWidget(widget_);
236 }
237
238
239 GuiViewSource::~GuiViewSource()
240 {
241         delete widget_;
242 }
243
244
245 void GuiViewSource::updateView()
246 {
247         if (widget_->autoUpdateCB->isChecked()) {
248                 widget_->setBufferView(bufferview());
249                 widget_->updateView();
250         }
251         widget_->masterPerspectiveCB->setEnabled(buffer().parent());
252 }
253
254
255 void GuiViewSource::enableView(bool enable)
256 {
257         widget_->setBufferView(bufferview());
258         widget_->updateDefaultFormat();
259         if (!enable)
260                 // In the opposite case, updateView() will be called anyway.
261                 widget_->updateView();
262 }
263
264
265 bool GuiViewSource::initialiseParams(string const & /*source*/)
266 {
267         setWindowTitle(title());
268         return true;
269 }
270
271
272 QString GuiViewSource::title() const
273 {
274         switch (docType()) {
275                 case LATEX:
276                         return qt_("LaTeX Source");
277                 case DOCBOOK:
278                         return qt_("DocBook Source");
279                 case LITERATE:
280                         return qt_("Literate Source");
281         }
282         LASSERT(false, /**/);
283         return QString();
284 }
285
286
287 void GuiViewSource::saveSession() const
288 {
289         Dialog::saveSession();
290         QSettings settings;
291         // see below
292         // settings.setValue(
293         //      sessionKey() + "/output", widget_->contentsCO->currentIndex());
294         settings.setValue(
295                 sessionKey() + "/autoupdate", widget_->autoUpdateCB->isChecked());
296 }
297
298
299 void GuiViewSource::restoreSession()
300 {
301         DockView::restoreSession();
302         // FIXME: Full source updating is too slow to be done at startup.
303         //widget_->outputCO-setCurrentIndex(
304         //      settings.value(sessionKey() + "/output", false).toInt());
305         widget_->contentsCO->setCurrentIndex(0);
306         QSettings settings;
307         widget_->autoUpdateCB->setChecked(
308                 settings.value(sessionKey() + "/autoupdate", true).toBool());
309         widget_->updateView();
310 }
311
312
313 Dialog * createGuiViewSource(GuiView & lv)
314 {
315         return new GuiViewSource(lv);
316 }
317
318
319 } // namespace frontend
320 } // namespace lyx
321
322 #include "moc_GuiViewSource.cpp"