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