2 * \file GuiViewSource.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * \author Abdelrazak Younes
10 * Full author contact details are available in file CREDITS.
15 #include "GuiApplication.h"
16 #include "GuiViewSource.h"
17 #include "LaTeXHighlighter.h"
18 #include "qt_helpers.h"
21 #include "BufferParams.h"
22 #include "BufferView.h"
25 #include "Paragraph.h"
28 #include "support/debug.h"
29 #include "support/lassert.h"
30 #include "support/docstream.h"
31 #include "support/gettext.h"
33 #include <boost/crc.hpp>
36 #include <QTextCursor>
37 #include <QTextDocument>
45 ViewSourceWidget::ViewSourceWidget()
46 : bv_(0), document_(new QTextDocument(this)),
47 highlighter_(new LaTeXHighlighter(document_)),
48 force_getcontent_(true)
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()));
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);
81 static size_t crcCheck(docstring const & s)
83 boost::crc_32_type crc;
84 crc.process_bytes(&s[0], sizeof(char_type) * s.size());
85 return crc.checksum();
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.
93 static bool getContent(BufferView const * view, Buffer::OutputWhat output,
94 QString & qstr, string const format, bool force_getcontent)
96 // get the *top* level paragraphs that contain the cursor,
97 // or the selected text
101 if (!view->cursor().selection()) {
102 par_begin = view->cursor().bottom().pit();
105 par_begin = view->cursor().selectionBegin().bottom().pit();
106 par_end = view->cursor().selectionEnd().bottom().pit();
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)
123 void ViewSourceWidget::setBufferView(BufferView const * bv)
126 force_getcontent_ = true;
128 setEnabled(bv ? true : false);
132 void ViewSourceWidget::contentsChanged()
134 if (autoUpdateCB->isChecked())
139 void ViewSourceWidget::setViewFormat()
141 view_format_ = outputFormatCO->itemData(
142 outputFormatCO->currentIndex()).toString();
147 void ViewSourceWidget::updateView()
150 document_->setPlainText(QString());
157 string const format = fromqstr(view_format_);
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;
168 if (getContent(bv_, output, content, format, force_getcontent_))
169 document_->setPlainText(content);
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;
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);
191 void ViewSourceWidget::updateDefaultFormat()
196 outputFormatCO->blockSignals(true);
197 outputFormatCO->clear();
198 outputFormatCO->addItem(qt_("Default"),
199 QVariant(QString("default")));
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);
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
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;
220 outputFormatCO->setCurrentIndex(index);
222 outputFormatCO->blockSignals(false);
226 GuiViewSource::GuiViewSource(GuiView & parent,
227 Qt::DockWidgetArea area, Qt::WindowFlags flags)
228 : DockView(parent, "view-source", qt_("LaTeX Source"), area, flags)
230 widget_ = new ViewSourceWidget();
235 GuiViewSource::~GuiViewSource()
241 void GuiViewSource::updateView()
243 if (widget_->autoUpdateCB->isChecked()) {
244 widget_->setBufferView(bufferview());
245 widget_->updateView();
250 void GuiViewSource::enableView(bool enable)
252 widget_->setBufferView(bufferview());
253 widget_->updateDefaultFormat();
255 // In the opposite case, updateView() will be called anyway.
256 widget_->updateView();
260 bool GuiViewSource::initialiseParams(string const & /*source*/)
262 setWindowTitle(title());
267 QString GuiViewSource::title() const
271 return qt_("LaTeX Source");
273 return qt_("DocBook Source");
275 return qt_("Literate Source");
277 LASSERT(false, /**/);
282 void GuiViewSource::saveSession() const
284 Dialog::saveSession();
287 // settings.setValue(
288 // sessionKey() + "/output", widget_->contentsCO->currentIndex());
290 sessionKey() + "/autoupdate", widget_->autoUpdateCB->isChecked());
294 void GuiViewSource::restoreSession()
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);
302 widget_->autoUpdateCB->setChecked(
303 settings.value(sessionKey() + "/autoupdate", true).toBool());
304 widget_->updateView();
308 Dialog * createGuiViewSource(GuiView & lv)
310 return new GuiViewSource(lv);
314 } // namespace frontend
317 #include "moc_GuiViewSource.cpp"