]> git.lyx.org Git - features.git/blob - src/frontends/qt4/GuiViewSource.cpp
* Use default output flavor for View Source.
[features.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 "BufferView.h"
21 #include "Buffer.h"
22 #include "Cursor.h"
23 #include "Paragraph.h"
24 #include "TexRow.h"
25
26 #include "support/debug.h"
27 #include "support/lassert.h"
28 #include "support/docstream.h"
29 #include "support/gettext.h"
30
31 #include <boost/crc.hpp>
32
33 #include <QSettings>
34 #include <QTextCursor>
35 #include <QTextDocument>
36 #include <QVariant>
37
38 using namespace std;
39
40 namespace lyx {
41 namespace frontend {
42
43 ViewSourceWidget::ViewSourceWidget()
44         :       bv_(0), document_(new QTextDocument(this)),
45                 highlighter_(new LaTeXHighlighter(document_))
46 {
47         setupUi(this);
48
49         connect(viewFullSourceCB, SIGNAL(clicked()),
50                 this, SLOT(updateView()));
51         connect(autoUpdateCB, SIGNAL(toggled(bool)),
52                 updatePB, SLOT(setDisabled(bool)));
53         connect(autoUpdateCB, SIGNAL(toggled(bool)),
54                 this, SLOT(updateView()));
55         connect(updatePB, SIGNAL(clicked()),
56                 this, SLOT(updateView()));
57
58         // setting a document at this point trigger an assertion in Qt
59         // so we disable the signals here:
60         document_->blockSignals(true);
61         viewSourceTV->setDocument(document_);
62         document_->blockSignals(false);
63         viewSourceTV->setReadOnly(true);
64         ///dialog_->viewSourceTV->setAcceptRichText(false);
65         // this is personal. I think source code should be in fixed-size font
66         QFont font(guiApp->typewriterFontName());
67         font.setKerning(false);
68         font.setFixedPitch(true);
69         font.setStyleHint(QFont::TypeWriter);
70         viewSourceTV->setFont(font);
71         // again, personal taste
72         viewSourceTV->setWordWrapMode(QTextOption::NoWrap);
73 }
74
75
76 static size_t crcCheck(docstring const & s)
77 {
78         boost::crc_32_type crc;
79         crc.process_bytes(&s[0], sizeof(char_type) * s.size());
80         return crc.checksum();
81 }
82
83
84 /** get the source code of selected paragraphs, or the whole document
85         \param fullSource get full source code
86         \return true if the content has changed since last call.
87  */
88 static bool getContent(BufferView const * view, bool fullSource, QString & qstr)
89 {
90         // get the *top* level paragraphs that contain the cursor,
91         // or the selected text
92         pit_type par_begin;
93         pit_type par_end;
94
95         if (!view->cursor().selection()) {
96                 par_begin = view->cursor().bottom().pit();
97                 par_end = par_begin;
98         } else {
99                 par_begin = view->cursor().selectionBegin().bottom().pit();
100                 par_end = view->cursor().selectionEnd().bottom().pit();
101         }
102         if (par_begin > par_end)
103                 swap(par_begin, par_end);
104         odocstringstream ostr;
105         const_cast<BufferView *>(view)->buffer().getSourceCode(
106                 ostr, par_begin, par_end + 1, fullSource);
107         docstring s = ostr.str();
108         static size_t crc = 0;
109         size_t newcrc = crcCheck(s);
110         if (newcrc == crc)
111                 return false;
112         crc = newcrc;
113         qstr = toqstr(s);
114         return true;
115 }
116
117
118 void ViewSourceWidget::setBufferView(BufferView const * bv)
119 {
120         bv_ = bv;
121         setEnabled(bv ?  true : false);
122 }
123
124
125 void ViewSourceWidget::updateView()
126 {
127         if (!bv_) {
128                 document_->setPlainText(QString());
129                 setEnabled(false);
130                 return;
131         }
132         
133         setEnabled(true);
134
135         QString content;
136         if (getContent(bv_, viewFullSourceCB->isChecked(), content))
137                 document_->setPlainText(content);
138
139         CursorSlice beg = bv_->cursor().selectionBegin().bottom();
140         CursorSlice end = bv_->cursor().selectionEnd().bottom();
141         int const begrow = bv_->buffer().texrow().
142                 getRowFromIdPos(beg.paragraph().id(), beg.pos());
143         int endrow = bv_->buffer().texrow().
144                 getRowFromIdPos(end.paragraph().id(), end.pos());
145         int const nextendrow = bv_->buffer().texrow().
146                 getRowFromIdPos(end.paragraph().id(), end.pos() + 1);
147         if (endrow != nextendrow)
148                 endrow = nextendrow - 1;
149
150         QTextCursor c = QTextCursor(viewSourceTV->document());
151         c.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, begrow);
152         c.select(QTextCursor::BlockUnderCursor);
153         c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor,
154                 endrow - begrow + 1);
155         viewSourceTV->setTextCursor(c);
156 }
157
158
159 GuiViewSource::GuiViewSource(GuiView & parent,
160                 Qt::DockWidgetArea area, Qt::WindowFlags flags)
161         : DockView(parent, "view-source", qt_("LaTeX Source"), area, flags)
162 {
163         widget_ = new ViewSourceWidget();
164         setWidget(widget_);
165 }
166
167
168 GuiViewSource::~GuiViewSource()
169 {
170         delete widget_;
171 }
172
173
174 void GuiViewSource::updateView()
175 {
176         if (widget_->autoUpdateCB->isChecked()) {
177                 widget_->setBufferView(bufferview());
178                 widget_->updateView();
179         }
180 }
181
182
183 void GuiViewSource::enableView(bool enable)
184 {
185         widget_->setBufferView(bufferview());
186         if (!enable)
187                 // In the opposite case, updateView() will be called anyway.
188                 widget_->updateView();
189 }
190
191
192 bool GuiViewSource::initialiseParams(string const & /*source*/)
193 {
194         setWindowTitle(title());
195         return true;
196 }
197
198
199 QString GuiViewSource::title() const
200 {
201         switch (docType()) {
202                 case LATEX:
203                         return qt_("LaTeX Source");
204                 case DOCBOOK:
205                         return qt_("DocBook Source");
206                 case LITERATE:
207                         return qt_("Literate Source");
208         }
209         LASSERT(false, /**/);
210         return QString();
211 }
212
213
214 void GuiViewSource::saveSession() const
215 {
216         Dialog::saveSession();
217         QSettings settings;
218         settings.setValue(
219                 sessionKey() + "/fullsource", widget_->viewFullSourceCB->isChecked());
220         settings.setValue(
221                 sessionKey() + "/autoupdate", widget_->autoUpdateCB->isChecked());
222 }
223
224
225 void GuiViewSource::restoreSession()
226 {
227         DockView::restoreSession();
228         // FIXME: Full source updating is too slow to be done at startup.
229         //widget_->viewFullSourceCB->setChecked(
230         //      settings.value(sessionKey() + "/fullsource", false).toBool());
231         widget_->viewFullSourceCB->setChecked(false);
232         QSettings settings;
233         widget_->autoUpdateCB->setChecked(
234                 settings.value(sessionKey() + "/autoupdate", true).toBool());
235         widget_->updateView();
236 }
237
238
239 Dialog * createGuiViewSource(GuiView & lv)
240 {
241         return new GuiViewSource(lv);
242 }
243
244
245 } // namespace frontend
246 } // namespace lyx
247
248 #include "moc_GuiViewSource.cpp"