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.setFixedPitch(true);
76 font.setStyleHint(QFont::TypeWriter);
77 viewSourceTV->setFont(font);
78 // again, personal taste
79 viewSourceTV->setWordWrapMode(QTextOption::NoWrap);
83 static size_t crcCheck(docstring const & s)
85 boost::crc_32_type crc;
86 crc.process_bytes(&s[0], sizeof(char_type) * s.size());
87 return crc.checksum();
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.
95 static bool getContent(BufferView const * view, Buffer::OutputWhat output,
96 QString & qstr, string const & format, bool force_getcontent,
99 // get the *top* level paragraphs that contain the cursor,
100 // or the selected text
104 if (!view->cursor().selection()) {
105 par_begin = view->cursor().bottom().pit();
108 par_begin = view->cursor().selectionBegin().bottom().pit();
109 par_end = view->cursor().selectionEnd().bottom().pit();
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,
116 docstring s = ostr.str();
118 // Could this be private to this particular dialog? We could have
119 // more than one of these, in different windows.
120 static size_t crc = 0;
121 size_t newcrc = crcCheck(s);
122 if (newcrc == crc && !force_getcontent)
130 void ViewSourceWidget::setBufferView(BufferView const * bv)
133 force_getcontent_ = true;
135 setEnabled(bv ? true : false);
139 void ViewSourceWidget::contentsChanged()
141 if (autoUpdateCB->isChecked())
146 void ViewSourceWidget::setViewFormat()
148 view_format_ = outputFormatCO->itemData(
149 outputFormatCO->currentIndex()).toString();
154 void ViewSourceWidget::updateView()
157 document_->setPlainText(QString());
164 string const format = fromqstr(view_format_);
167 Buffer::OutputWhat output = Buffer::CurrentParagraph;
168 if (contentsCO->currentIndex() == 1)
169 output = Buffer::FullSource;
170 else if (contentsCO->currentIndex() == 2)
171 output = Buffer::OnlyPreamble;
172 else if (contentsCO->currentIndex() == 3)
173 output = Buffer::OnlyBody;
175 if (getContent(bv_, output, content, format,
176 force_getcontent_, masterPerspectiveCB->isChecked()))
177 document_->setPlainText(content);
179 CursorSlice beg = bv_->cursor().selectionBegin().bottom();
180 CursorSlice end = bv_->cursor().selectionEnd().bottom();
181 int const begrow = bv_->buffer().texrow().
182 getRowFromIdPos(beg.paragraph().id(), beg.pos());
183 int endrow = bv_->buffer().texrow().
184 getRowFromIdPos(end.paragraph().id(), end.pos());
185 int const nextendrow = bv_->buffer().texrow().
186 getRowFromIdPos(end.paragraph().id(), end.pos() + 1);
187 if (endrow != nextendrow)
188 endrow = nextendrow - 1;
190 QTextCursor c = QTextCursor(viewSourceTV->document());
191 c.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, begrow);
192 c.select(QTextCursor::BlockUnderCursor);
193 c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor,
194 endrow - begrow + 1);
195 viewSourceTV->setTextCursor(c);
199 void ViewSourceWidget::updateDefaultFormat()
204 outputFormatCO->blockSignals(true);
205 outputFormatCO->clear();
206 outputFormatCO->addItem(qt_("Default"),
207 QVariant(QString("default")));
210 vector<string> tmp = bv_->buffer().params().backends();
211 vector<string>::const_iterator it = tmp.begin();
212 vector<string>::const_iterator en = tmp.end();
213 for (; it != en; ++it) {
214 string const format = *it;
215 Format const * fmt = formats.getFormat(format);
217 LYXERR0("Can't find format for backend " << format << "!");
221 QString const pretty = qt_(fmt->prettyname());
222 QString const qformat = toqstr(format);
223 outputFormatCO->addItem(pretty, QVariant(qformat));
224 if (qformat == view_format_)
225 index = outputFormatCO->count() -1;
227 outputFormatCO->setCurrentIndex(index);
229 outputFormatCO->blockSignals(false);
233 void ViewSourceWidget::resizeEvent (QResizeEvent * event)
235 QSize const & formSize = formLayout->sizeHint();
236 // minimize the size of the part that contains the buttons
237 if (width() * formSize.height() < height() * formSize.width()) {
238 layout_->setDirection(QBoxLayout::TopToBottom);
240 layout_->setDirection(QBoxLayout::LeftToRight);
242 QWidget::resizeEvent(event);
246 GuiViewSource::GuiViewSource(GuiView & parent,
247 Qt::DockWidgetArea area, Qt::WindowFlags flags)
248 : DockView(parent, "view-source", qt_("LaTeX Source"), area, flags)
250 widget_ = new ViewSourceWidget;
255 GuiViewSource::~GuiViewSource()
261 void GuiViewSource::updateView()
263 if (widget_->autoUpdateCB->isChecked()) {
264 widget_->setBufferView(bufferview());
265 widget_->updateView();
267 widget_->masterPerspectiveCB->setEnabled(buffer().parent());
271 void GuiViewSource::enableView(bool enable)
273 widget_->setBufferView(bufferview());
274 widget_->updateDefaultFormat();
276 // In the opposite case, updateView() will be called anyway.
277 widget_->updateView();
281 bool GuiViewSource::initialiseParams(string const & /*source*/)
283 setWindowTitle(title());
288 QString GuiViewSource::title() const
292 return qt_("LaTeX Source");
294 return qt_("DocBook Source");
296 return qt_("Literate Source");
303 void GuiViewSource::saveSession() const
305 Dialog::saveSession();
308 // settings.setValue(
309 // sessionKey() + "/output", widget_->contentsCO->currentIndex());
311 sessionKey() + "/autoupdate", widget_->autoUpdateCB->isChecked());
315 void GuiViewSource::restoreSession()
317 DockView::restoreSession();
318 // FIXME: Full source updating is too slow to be done at startup.
319 //widget_->outputCO-setCurrentIndex(
320 // settings.value(sessionKey() + "/output", false).toInt());
321 widget_->contentsCO->setCurrentIndex(0);
323 widget_->autoUpdateCB->setChecked(
324 settings.value(sessionKey() + "/autoupdate", true).toBool());
325 widget_->updateView();
329 Dialog * createGuiViewSource(GuiView & lv)
331 return new GuiViewSource(lv);
335 } // namespace frontend
338 #include "moc_GuiViewSource.cpp"