]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiViewSource.cpp
* fix spelling in comments to please John.
[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(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         view->buffer().getSourceCode(ostr, par_begin, par_end + 1, fullSource);
106         docstring s = ostr.str();
107         static size_t crc = 0;
108         size_t newcrc = crcCheck(s);
109         if (newcrc == crc)
110                 return false;
111         crc = newcrc;
112         qstr = toqstr(s);
113         return true;
114 }
115
116
117 void ViewSourceWidget::setBufferView(BufferView const * bv)
118 {
119         bv_ = bv;
120         setEnabled(bv ?  true : false);
121 }
122
123
124 void ViewSourceWidget::updateView()
125 {
126         if (!bv_) {
127                 document_->setPlainText(QString());
128                 setEnabled(false);
129                 return;
130         }
131         
132         setEnabled(true);
133
134         QString content;
135         if (getContent(bv_, viewFullSourceCB->isChecked(), content))
136                 document_->setPlainText(content);
137
138         CursorSlice beg = bv_->cursor().selectionBegin().bottom();
139         CursorSlice end = bv_->cursor().selectionEnd().bottom();
140         int const begrow = bv_->buffer().texrow().
141                 getRowFromIdPos(beg.paragraph().id(), beg.pos());
142         int endrow = bv_->buffer().texrow().
143                 getRowFromIdPos(end.paragraph().id(), end.pos());
144         int const nextendrow = bv_->buffer().texrow().
145                 getRowFromIdPos(end.paragraph().id(), end.pos() + 1);
146         if (endrow != nextendrow)
147                 endrow = nextendrow - 1;
148
149         QTextCursor c = QTextCursor(viewSourceTV->document());
150         c.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, begrow);
151         c.select(QTextCursor::BlockUnderCursor);
152         c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor,
153                 endrow - begrow + 1);
154         viewSourceTV->setTextCursor(c);
155 }
156
157
158 GuiViewSource::GuiViewSource(GuiView & parent,
159                 Qt::DockWidgetArea area, Qt::WindowFlags flags)
160         : DockView(parent, "view-source", qt_("LaTeX Source"), area, flags)
161 {
162         widget_ = new ViewSourceWidget();
163         setWidget(widget_);
164 }
165
166
167 GuiViewSource::~GuiViewSource()
168 {
169         delete widget_;
170 }
171
172
173 void GuiViewSource::updateView()
174 {
175         if (widget_->autoUpdateCB->isChecked()) {
176                 widget_->setBufferView(bufferview());
177                 widget_->updateView();
178         }
179 }
180
181
182 void GuiViewSource::enableView(bool enable)
183 {
184         widget_->setBufferView(bufferview());
185         if (!enable)
186                 // In the opposite case, updateView() will be called anyway.
187                 widget_->updateView();
188 }
189
190
191 bool GuiViewSource::initialiseParams(string const & /*source*/)
192 {
193         setWindowTitle(title());
194         return true;
195 }
196
197
198 QString GuiViewSource::title() const
199 {
200         switch (docType()) {
201                 case LATEX:
202                         return qt_("LaTeX Source");
203                 case DOCBOOK:
204                         return qt_("DocBook Source");
205                 case LITERATE:
206                         return qt_("Literate Source");
207         }
208         LASSERT(false, /**/);
209         return QString();
210 }
211
212
213 void GuiViewSource::saveSession() const
214 {
215         Dialog::saveSession();
216         QSettings settings;
217         settings.setValue(
218                 sessionKey() + "/fullsource", widget_->viewFullSourceCB->isChecked());
219         settings.setValue(
220                 sessionKey() + "/autoupdate", widget_->autoUpdateCB->isChecked());
221 }
222
223
224 void GuiViewSource::restoreSession()
225 {
226         DockView::restoreSession();
227         // FIXME: Full source updating is too slow to be done at startup.
228         //widget_->viewFullSourceCB->setChecked(
229         //      settings.value(sessionKey() + "/fullsource", false).toBool());
230         widget_->viewFullSourceCB->setChecked(false);
231         QSettings settings;
232         widget_->autoUpdateCB->setChecked(
233                 settings.value(sessionKey() + "/autoupdate", true).toBool());
234         widget_->updateView();
235 }
236
237
238 Dialog * createGuiViewSource(GuiView & lv)
239 {
240         return new GuiViewSource(lv);
241 }
242
243
244 } // namespace frontend
245 } // namespace lyx
246
247 #include "moc_GuiViewSource.cpp"