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>
37 #include <QTextCursor>
38 #include <QTextDocument>
46 ViewSourceWidget::ViewSourceWidget()
47 : bv_(0), document_(new QTextDocument(this)),
48 highlighter_(new LaTeXHighlighter(document_)),
49 force_getcontent_(true)
53 connect(contentsCO, SIGNAL(activated(int)),
54 this, SLOT(contentsChanged()));
55 connect(autoUpdateCB, SIGNAL(toggled(bool)),
56 updatePB, SLOT(setDisabled(bool)));
57 connect(autoUpdateCB, SIGNAL(toggled(bool)),
58 this, SLOT(updateView()));
59 connect(masterPerspectiveCB, SIGNAL(toggled(bool)),
60 this, SLOT(updateView()));
61 connect(updatePB, SIGNAL(clicked()),
62 this, SLOT(updateView()));
63 connect(outputFormatCO, SIGNAL(activated(int)),
64 this, SLOT(setViewFormat()));
66 // setting a document at this point trigger an assertion in Qt
67 // so we disable the signals here:
68 document_->blockSignals(true);
69 viewSourceTV->setDocument(document_);
70 document_->blockSignals(false);
71 viewSourceTV->setReadOnly(true);
72 ///dialog_->viewSourceTV->setAcceptRichText(false);
73 // this is personal. I think source code should be in fixed-size font
74 QFont font(guiApp->typewriterFontName());
75 font.setKerning(false);
76 font.setFixedPitch(true);
77 font.setStyleHint(QFont::TypeWriter);
78 viewSourceTV->setFont(font);
79 // again, personal taste
80 viewSourceTV->setWordWrapMode(QTextOption::NoWrap);
84 static size_t crcCheck(docstring const & s)
86 boost::crc_32_type crc;
87 crc.process_bytes(&s[0], sizeof(char_type) * s.size());
88 return crc.checksum();
92 /** get the source code of selected paragraphs, or the whole document
93 \param fullSource get full source code
94 \return true if the content has changed since last call.
96 static bool getContent(BufferView const * view, Buffer::OutputWhat output,
97 QString & qstr, string const format, bool force_getcontent,
100 // get the *top* level paragraphs that contain the cursor,
101 // or the selected text
105 if (!view->cursor().selection()) {
106 par_begin = view->cursor().bottom().pit();
109 par_begin = view->cursor().selectionBegin().bottom().pit();
110 par_end = view->cursor().selectionEnd().bottom().pit();
112 if (par_begin > par_end)
113 swap(par_begin, par_end);
114 odocstringstream ostr;
115 view->buffer().getSourceCode(ostr, format, par_begin, par_end + 1,
117 docstring s = ostr.str();
119 // Could this be private to this particular dialog? We could have
120 // more than one of these, in different windows.
121 static size_t crc = 0;
122 size_t newcrc = crcCheck(s);
123 if (newcrc == crc && !force_getcontent)
131 void ViewSourceWidget::setBufferView(BufferView const * bv)
134 force_getcontent_ = true;
136 setEnabled(bv ? true : false);
140 void ViewSourceWidget::contentsChanged()
142 if (autoUpdateCB->isChecked())
147 void ViewSourceWidget::setViewFormat()
149 view_format_ = outputFormatCO->itemData(
150 outputFormatCO->currentIndex()).toString();
155 void ViewSourceWidget::updateView()
158 document_->setPlainText(QString());
165 string const format = fromqstr(view_format_);
168 Buffer::OutputWhat output = Buffer::CurrentParagraph;
169 if (contentsCO->currentIndex() == 1)
170 output = Buffer::FullSource;
171 else if (contentsCO->currentIndex() == 2)
172 output = Buffer::OnlyPreamble;
173 else if (contentsCO->currentIndex() == 3)
174 output = Buffer::OnlyBody;
176 if (getContent(bv_, output, content, format,
177 force_getcontent_, masterPerspectiveCB->isChecked()))
178 document_->setPlainText(content);
180 CursorSlice beg = bv_->cursor().selectionBegin().bottom();
181 CursorSlice end = bv_->cursor().selectionEnd().bottom();
182 int const begrow = bv_->buffer().texrow().
183 getRowFromIdPos(beg.paragraph().id(), beg.pos());
184 int endrow = bv_->buffer().texrow().
185 getRowFromIdPos(end.paragraph().id(), end.pos());
186 int const nextendrow = bv_->buffer().texrow().
187 getRowFromIdPos(end.paragraph().id(), end.pos() + 1);
188 if (endrow != nextendrow)
189 endrow = nextendrow - 1;
191 QTextCursor c = QTextCursor(viewSourceTV->document());
192 c.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, begrow);
193 c.select(QTextCursor::BlockUnderCursor);
194 c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor,
195 endrow - begrow + 1);
196 viewSourceTV->setTextCursor(c);
200 void ViewSourceWidget::updateDefaultFormat()
205 outputFormatCO->blockSignals(true);
206 outputFormatCO->clear();
207 outputFormatCO->addItem(qt_("Default"),
208 QVariant(QString("default")));
211 vector<string> tmp = bv_->buffer().params().backends();
212 vector<string>::const_iterator it = tmp.begin();
213 vector<string>::const_iterator en = tmp.end();
214 for (; it != en; ++it) {
215 string const format = *it;
216 Format const * fmt = formats.getFormat(format);
218 LYXERR0("Can't find format for backend " << format << "!");
222 QString const pretty = qt_(fmt->prettyname());
223 QString const qformat = toqstr(format);
224 outputFormatCO->addItem(pretty, QVariant(qformat));
225 if (qformat == view_format_)
226 index = outputFormatCO->count() -1;
228 outputFormatCO->setCurrentIndex(index);
230 outputFormatCO->blockSignals(false);
234 void ViewSourceWidget::resizeEvent (QResizeEvent * event)
236 QSize const & formSize = formLayout->sizeHint();
237 // minimize the size of the part that contains the buttons
238 if (width() * formSize.height() < height() * formSize.width()) {
239 layout_->setDirection(QBoxLayout::TopToBottom);
241 layout_->setDirection(QBoxLayout::LeftToRight);
243 QWidget::resizeEvent(event);
247 GuiViewSource::GuiViewSource(GuiView & parent,
248 Qt::DockWidgetArea area, Qt::WindowFlags flags)
249 : DockView(parent, "view-source", qt_("LaTeX Source"), area, flags)
251 widget_ = new ViewSourceWidget;
256 GuiViewSource::~GuiViewSource()
262 void GuiViewSource::updateView()
264 if (widget_->autoUpdateCB->isChecked()) {
265 widget_->setBufferView(bufferview());
266 widget_->updateView();
268 widget_->masterPerspectiveCB->setEnabled(buffer().parent());
272 void GuiViewSource::enableView(bool enable)
274 widget_->setBufferView(bufferview());
275 widget_->updateDefaultFormat();
277 // In the opposite case, updateView() will be called anyway.
278 widget_->updateView();
282 bool GuiViewSource::initialiseParams(string const & /*source*/)
284 setWindowTitle(title());
289 QString GuiViewSource::title() const
293 return qt_("LaTeX Source");
295 return qt_("DocBook Source");
297 return qt_("Literate Source");
304 void GuiViewSource::saveSession() const
306 Dialog::saveSession();
309 // settings.setValue(
310 // sessionKey() + "/output", widget_->contentsCO->currentIndex());
312 sessionKey() + "/autoupdate", widget_->autoUpdateCB->isChecked());
316 void GuiViewSource::restoreSession()
318 DockView::restoreSession();
319 // FIXME: Full source updating is too slow to be done at startup.
320 //widget_->outputCO-setCurrentIndex(
321 // settings.value(sessionKey() + "/output", false).toInt());
322 widget_->contentsCO->setCurrentIndex(0);
324 widget_->autoUpdateCB->setChecked(
325 settings.value(sessionKey() + "/autoupdate", true).toBool());
326 widget_->updateView();
330 Dialog * createGuiViewSource(GuiView & lv)
332 return new GuiViewSource(lv);
336 } // namespace frontend
339 #include "moc_GuiViewSource.cpp"