]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiViewSource.cpp
Use <cstdint> instead of <boost/cstdint.hpp>
[lyx.git] / src / frontends / qt4 / GuiViewSource.cpp
index 192a163faf203dfe9b341fa3a67463ec21732749..04c6bf5c349796661315388d72b26d91c9febab9 100644 (file)
 #include "BufferView.h"
 #include "Cursor.h"
 #include "Format.h"
+#include "FuncRequest.h"
+#include "LyX.h"
 #include "Paragraph.h"
+#include "TexRow.h"
 
 #include "support/debug.h"
 #include "support/lassert.h"
@@ -44,10 +47,10 @@ using namespace std;
 namespace lyx {
 namespace frontend {
 
-ViewSourceWidget::ViewSourceWidget()
-       :       bv_(0), document_(new QTextDocument(this)),
-               highlighter_(new LaTeXHighlighter(document_)),
-               update_timer_(new QTimer(this))
+ViewSourceWidget::ViewSourceWidget(QWidget * parent)
+       :       QWidget(parent),
+               document_(new QTextDocument(this)),
+               highlighter_(new LaTeXHighlighter(document_))
 {
        setupUi(this);
 
@@ -60,21 +63,9 @@ ViewSourceWidget::ViewSourceWidget()
        connect(masterPerspectiveCB, SIGNAL(toggled(bool)),
                this, SLOT(contentsChanged()));
        connect(updatePB, SIGNAL(clicked()),
-               this, SLOT(updateViewNow()));
+               this, SIGNAL(needUpdate()));
        connect(outputFormatCO, SIGNAL(activated(int)),
                this, SLOT(setViewFormat(int)));
-       connect(outputFormatCO, SIGNAL(activated(int)),
-               this, SLOT(contentsChanged()));
-#ifdef DEVEL_VERSION
-       if (lyx::lyxerr.debugging(Debug::LATEX))
-               connect(viewSourceTV, SIGNAL(cursorPositionChanged()),
-                               this, SLOT(gotoCursor()));
-#endif
-
-       // setting the update timer
-       update_timer_->setSingleShot(true);
-       connect(update_timer_, SIGNAL(timeout()),
-               this, SLOT(realUpdateView()));
 
        // setting a document at this point trigger an assertion in Qt
        // so we disable the signals here:
@@ -89,10 +80,13 @@ ViewSourceWidget::ViewSourceWidget()
        viewSourceTV->setFont(guiApp->typewriterSystemFont());
        // again, personal taste
        viewSourceTV->setWordWrapMode(QTextOption::NoWrap);
+
+       // catch double click events
+       viewSourceTV->viewport()->installEventFilter(this);
 }
 
 
-void ViewSourceWidget::getContent(BufferView const * view,
+void ViewSourceWidget::getContent(BufferView const & view,
                        Buffer::OutputWhat output, docstring & str, string const & format,
                        bool master)
 {
@@ -101,33 +95,23 @@ void ViewSourceWidget::getContent(BufferView const * view,
        pit_type par_begin;
        pit_type par_end;
 
-       if (!view->cursor().selection()) {
-               par_begin = view->cursor().bottom().pit();
+       if (!view.cursor().selection()) {
+               par_begin = view.cursor().bottom().pit();
                par_end = par_begin;
        } else {
-               par_begin = view->cursor().selectionBegin().bottom().pit();
-               par_end = view->cursor().selectionEnd().bottom().pit();
+               par_begin = view.cursor().selectionBegin().bottom().pit();
+               par_end = view.cursor().selectionEnd().bottom().pit();
        }
        if (par_begin > par_end)
                swap(par_begin, par_end);
        odocstringstream ostr;
-       texrow_ = view->buffer().getSourceCode(ostr, format,
-                                                                               par_begin, par_end + 1, output, master);
+       texrow_ = view.buffer()
+               .getSourceCode(ostr, format, par_begin, par_end + 1, output, master);
        //ensure that the last line can always be selected in its full width
        str = ostr.str() + "\n";
 }
 
 
-void ViewSourceWidget::setBufferView(BufferView const * bv)
-{
-       if (bv_ != bv) {
-               setText();
-               bv_ = bv;
-       }
-       setEnabled(bv ?  true : false);
-}
-
-
 bool ViewSourceWidget::setText(QString const & qstr)
 {
        bool const changed = document_->toPlainText() != qstr;
@@ -141,36 +125,52 @@ bool ViewSourceWidget::setText(QString const & qstr)
 void ViewSourceWidget::contentsChanged()
 {
        if (autoUpdateCB->isChecked())
-               updateViewNow();
+               Q_EMIT needUpdate();
 }
 
 
 void ViewSourceWidget::setViewFormat(int const index)
 {
        outputFormatCO->setCurrentIndex(index);
-       view_format_ = outputFormatCO->itemData(index).toString();
+       string format = fromqstr(outputFormatCO->itemData(index).toString());
+       if (view_format_ != format) {
+               view_format_ = format;
+               Q_EMIT needUpdate();
+       }
 }
 
 
-void ViewSourceWidget::updateView()
+int ViewSourceWidget::updateDelay() const
 {
        const int long_delay = 400;
        const int short_delay = 60;
        // a shorter delay if just the current paragraph is shown
-       update_timer_->start((contentsCO->currentIndex() == 0) ?
-                                               short_delay : long_delay);
+       return (contentsCO->currentIndex() == 0) ? short_delay : long_delay;
+}
+
+
+void GuiViewSource::scheduleUpdate()
+{
+       update_timer_->start(widget_->updateDelay());
 }
 
 
-void ViewSourceWidget::updateViewNow()
+void GuiViewSource::scheduleUpdateNow()
 {
        update_timer_->start(0);
 }
 
 
-void ViewSourceWidget::realUpdateView()
+void GuiViewSource::realUpdateView()
+{
+       widget_->updateView(bufferview());
+       updateTitle();
+}
+
+
+void ViewSourceWidget::updateView(BufferView const * bv)
 {
-       if (!bv_) {
+       if (!bv) {
                setText();
                setEnabled(false);
                return;
@@ -184,8 +184,6 @@ void ViewSourceWidget::realUpdateView()
        // we will try to preserve this
        int const h_scroll = viewSourceTV->horizontalScrollBar()->value();
 
-       string const format = fromqstr(view_format_);
-
        Buffer::OutputWhat output = Buffer::CurrentParagraph;
        if (contentsCO->currentIndex() == 1)
                output = Buffer::FullSource;
@@ -195,38 +193,35 @@ void ViewSourceWidget::realUpdateView()
                output = Buffer::OnlyBody;
 
        docstring content;
-       getContent(bv_, output, content, format, masterPerspectiveCB->isChecked());
+       getContent(*bv, output, content, view_format_,
+                  masterPerspectiveCB->isChecked());
        QString old = document_->toPlainText();
        QString qcontent = toqstr(content);
-#ifdef DEVEL_VERSION
-       // output tex<->row correspondences in the source panel if the "-dbg latex"
-       // option is given.
-       if (texrow_.get() && lyx::lyxerr.debugging(Debug::LATEX)) {
-               QStringList list = qcontent.split(QChar('\n'));
-               docstring_list dlist;
-               for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
-                       dlist.push_back(from_utf8(fromqstr(*it)));
-               texrow_->prepend(dlist);
-               qcontent.clear();
-               for (docstring_list::iterator it = dlist.begin(); it != dlist.end(); ++it)
-                       qcontent += toqstr(*it) + '\n';
+       if (guiApp->currentView()->develMode()) {
+               // output tex<->row correspondences in the source panel if the "-dbg latex"
+               // option is given.
+               if (texrow_ && lyx::lyxerr.debugging(Debug::LATEX)) {
+                       QStringList list = qcontent.split(QChar('\n'));
+                       docstring_list dlist;
+                       for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
+                               dlist.push_back(from_utf8(fromqstr(*it)));
+                       texrow_->prepend(dlist);
+                       qcontent.clear();
+                       for (docstring_list::iterator it = dlist.begin(); it != dlist.end(); ++it)
+                               qcontent += toqstr(*it) + '\n';
+               }
        }
-#endif
+
        // prevent gotoCursor()
-       viewSourceTV->blockSignals(true);
+       QSignalBlocker blocker(viewSourceTV);
        bool const changed = setText(qcontent);
 
-       if (changed && !texrow_.get()) {
+       if (changed && !texrow_) {
                // position-to-row is unavailable
                // we jump to the first modification
-               const QChar * oc = old.constData();
-               const QChar * nc = qcontent.constData();
+               int length = min(old.length(), qcontent.length());
                int pos = 0;
-               while (*oc != '\0' && *nc != '\0' && *oc == *nc) {
-                       ++oc;
-                       ++nc;
-                       ++pos;
-               }
+               for (; pos < length && old.at(pos) == qcontent.at(pos); ++pos) {}
                QTextCursor c = QTextCursor(viewSourceTV->document());
                //get some space below the cursor
                c.setPosition(pos);
@@ -246,10 +241,10 @@ void ViewSourceWidget::realUpdateView()
                //c.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor,1);
                viewSourceTV->setTextCursor(c);
 
-       } else if (texrow_.get()) {
+       } else if (texrow_) {
                // Use the available position-to-row conversion to highlight
                // the current selection in the source
-               std::pair<int,int> rows = texrow_->rowFromCursor(bv_->cursor());
+               std::pair<int,int> rows = texrow_->rowFromCursor(bv->cursor());
                int const beg_row = rows.first;
                int const end_row = rows.second;
 
@@ -277,15 +272,18 @@ void ViewSourceWidget::realUpdateView()
 
                //the real highlighting is done with an ExtraSelection
                QTextCharFormat format;
+               {
+               // We create a new color with the lightness of AlternateBase and
+               // the hue and saturation of Highlight
                QPalette palette = viewSourceTV->palette();
-               //Alternative:
-               //  QColor bg = palette.color(QPalette::Active,QPalette::Highlight);
-               //  bg.setAlpha(64);
-               //  format.setBackground(QBrush(bg));
-               //Other alternatives:
-               //format.setBackground(palette.light());
-               //format.setBackground(palette.alternateBase());
-               format.setBackground(palette.toolTipBase());
+               QBrush alt = palette.alternateBase();
+               QColor high = palette.highlight().color().toHsl();
+               QColor col = QColor::fromHsl(high.hue(),
+                                            high.hslSaturation(),
+                                            alt.color().lightness());
+               alt.setColor(col);
+               format.setBackground(alt);
+               }
                format.setProperty(QTextFormat::FullWidthSelection, true);
                QTextEdit::ExtraSelection sel;
                sel.format = format;
@@ -298,53 +296,61 @@ void ViewSourceWidget::realUpdateView()
                viewSourceTV->setTextCursor(c);
                viewSourceTV->horizontalScrollBar()->setValue(h_scroll);
        } // else if (texrow)
-       viewSourceTV->blockSignals(false);
 }
 
 
-// only used in DEVEL_MODE for debugging
-// need a proper LFUN if we want to implement it in release mode
-void ViewSourceWidget::gotoCursor()
+docstring ViewSourceWidget::currentFormatName(BufferView const * bv) const
 {
-       if (!bv_ || !texrow_.get())
-               return;
-       int row = viewSourceTV->textCursor().blockNumber() + 1;
-       const_cast<BufferView *>(bv_)->setCursorFromRow(row, *texrow_);
+       // Compute the actual format used
+       string const format = !bv ? ""
+               : flavor2format(bv->buffer().params().getOutputFlavor(view_format_));
+       Format const * f = theFormats().getFormat(format.empty() ? view_format_ : format);
+       return f ? f->prettyname() : from_utf8(view_format_);
 }
 
 
+bool ViewSourceWidget::eventFilter(QObject * obj, QEvent * ev)
+{
+       // this event filter is installed on the viewport of the QTextView
+       if (obj == viewSourceTV->viewport() &&
+           ev->type() == QEvent::MouseButtonDblClick) {
+               goToCursor();
+               return true;
+       }
+       return false;
+}
+
 
-void ViewSourceWidget::updateDefaultFormat()
+void ViewSourceWidget::goToCursor() const
 {
-       if (!bv_)
+       if (!texrow_)
                return;
+       int row = viewSourceTV->textCursor().blockNumber() + 1;
+       dispatch(texrow_->goToFuncFromRow(row));
+}
+
+
 
-       outputFormatCO->blockSignals(true);
+void ViewSourceWidget::updateDefaultFormat(BufferView const & bv)
+{
+       QSignalBlocker blocker(outputFormatCO);
        outputFormatCO->clear();
        outputFormatCO->addItem(qt_("Default"),
-                               QVariant(QString("default")));
+                               QVariant(QString("default")));
 
        int index = 0;
-       vector<string> tmp = bv_->buffer().params().backends();
-       vector<string>::const_iterator it = tmp.begin();
-       vector<string>::const_iterator en = tmp.end();
-       for (; it != en; ++it) {
-               string const format = *it;
-               Format const * fmt = formats.getFormat(format);
+       for (string const & fmt_name : bv.buffer().params().backends()) {
+               Format const * fmt = theFormats().getFormat(fmt_name);
                if (!fmt) {
-                       LYXERR0("Can't find format for backend " << format << "!");
+                       LYXERR0("Can't find format for backend " << fmt_name << "!");
                        continue;
-               } 
-
-               QString const pretty = qt_(fmt->prettyname());
-               QString const qformat = toqstr(format);
-               outputFormatCO->addItem(pretty, QVariant(qformat));
-               if (qformat == view_format_)
-                  index = outputFormatCO->count() -1;
+               }
+               QString const pretty = toqstr(translateIfPossible(fmt->prettyname()));
+               outputFormatCO->addItem(pretty, QVariant(toqstr(fmt_name)));
+               if (fmt_name == view_format_)
+                       index = outputFormatCO->count() - 1;
        }
        setViewFormat(index);
-
-       outputFormatCO->blockSignals(false);
 }
 
 
@@ -360,10 +366,10 @@ void ViewSourceWidget::resizeEvent (QResizeEvent * event)
        QWidget::resizeEvent(event);
 }
 
-void ViewSourceWidget::saveSession(QString const & session_key) const
+
+void ViewSourceWidget::saveSession(QSettings & settings, QString const & session_key) const
 {
-       QSettings settings;
-       settings.setValue(session_key + "/output", view_format_);
+       settings.setValue(session_key + "/output", toqstr(view_format_));
        settings.setValue(session_key + "/contents", contentsCO->currentIndex());
        settings.setValue(session_key + "/autoupdate", autoUpdateCB->isChecked());
        settings.setValue(session_key + "/masterview",
@@ -374,7 +380,8 @@ void ViewSourceWidget::saveSession(QString const & session_key) const
 void ViewSourceWidget::restoreSession(QString const & session_key)
 {
        QSettings settings;
-    view_format_ = settings.value(session_key + "/output", 0).toString();
+       view_format_ = fromqstr(settings.value(session_key + "/output", 0)
+                               .toString());
        contentsCO->setCurrentIndex(settings
                                                                .value(session_key + "/contents", 0)
                                                                .toInt());
@@ -386,39 +393,50 @@ void ViewSourceWidget::restoreSession(QString const & session_key)
                .toBool();
        autoUpdateCB->setChecked(checked);
        if (checked)
-               updateView();
+               Q_EMIT needUpdate();
 }
 
 
 GuiViewSource::GuiViewSource(GuiView & parent,
                Qt::DockWidgetArea area, Qt::WindowFlags flags)
-       : DockView(parent, "view-source", qt_("LaTeX Source"), area, flags)
+       : DockView(parent, "view-source", qt_("Code Preview"), area, flags),
+         widget_(new ViewSourceWidget(this)),
+         update_timer_(new QTimer(this))
 {
-       widget_ = new ViewSourceWidget;
        setWidget(widget_);
+
+       // setting the update timer
+       update_timer_->setSingleShot(true);
+       connect(update_timer_, SIGNAL(timeout()),
+               this, SLOT(realUpdateView()));
+
+       connect(widget_, SIGNAL(needUpdate()), this, SLOT(scheduleUpdateNow()));
 }
 
 
-GuiViewSource::~GuiViewSource()
+void GuiViewSource::onBufferViewChanged()
 {
-       delete widget_;
+       widget_->setText();
+       widget_->setEnabled((bool)bufferview());
 }
 
 
 void GuiViewSource::updateView()
 {
        if (widget_->autoUpdateCB->isChecked()) {
-               widget_->setBufferView(bufferview());
-               widget_->updateView();
+               widget_->setEnabled((bool)bufferview());
+               scheduleUpdate();
        }
        widget_->masterPerspectiveCB->setEnabled(buffer().parent());
+       updateTitle();
 }
 
 
 void GuiViewSource::enableView(bool enable)
 {
-       widget_->setBufferView(bufferview());
-       widget_->updateDefaultFormat();
+       widget_->setEnabled((bool)bufferview());
+       if (bufferview())
+               widget_->updateDefaultFormat(*bufferview());
        if (!enable)
                // In the opposite case, updateView() will be called anyway.
                widget_->contentsChanged();
@@ -427,31 +445,26 @@ void GuiViewSource::enableView(bool enable)
 
 bool GuiViewSource::initialiseParams(string const & /*source*/)
 {
-       setWindowTitle(title());
+       updateTitle();
        return true;
 }
 
 
-QString GuiViewSource::title() const
+void GuiViewSource::updateTitle()
 {
-       switch (docType()) {
-               case LATEX:
-                       //FIXME: this is shown for LyXHTML source, LyX source, etc.
-                       return qt_("LaTeX Source");
-               case DOCBOOK:
-                       return qt_("DocBook Source");
-               case LITERATE:
-                       return qt_("Literate Source");
-       }
-       LATTEST(false);
-       return QString();
+       docstring const format = widget_->currentFormatName(bufferview());
+       QString const title = format.empty() ? qt_("Code Preview")
+               : qt_("%1[[preview format name]] Preview")
+                 .arg(toqstr(translateIfPossible(format)));
+       setTitle(title);
+       setWindowTitle(title);
 }
 
 
-void GuiViewSource::saveSession() const
+void GuiViewSource::saveSession(QSettings & settings) const
 {
-       Dialog::saveSession();
-       widget_->saveSession(sessionKey());
+       Dialog::saveSession(settings);
+       widget_->saveSession(settings, sessionKey());
 }