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