#include "Bullet.h"
#include "Chktex.h"
#include "debug.h"
+#include "DocIterator.h"
#include "Encoding.h"
#include "ErrorList.h"
#include "Exporter.h"
// here the buffer should take care that it is
// saved properly, before it goes into the void.
- closing();
+ Buffer * master = getMasterBuffer();
+ if (master != this && use_gui)
+ // We are closing buf which was a child document so we
+ // must update the labels and section numbering of its master
+ // Buffer.
+ updateLabels(*master);
if (!temppath().empty() && !destroyDir(FileName(temppath()))) {
Alert::warning(_("Could not remove temporary directory"),
// Remove any previewed LaTeX snippets associated with this buffer.
graphics::Previews::get().removeLoader(*this);
+
+ closing(this);
}
}
-void Buffer::saveCursor(StableDocIterator cur, StableDocIterator anc)
-{
- cursor_ = cur;
- anchor_ = anc;
-}
-
-
void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to,
Inset::Code code)
{
#include <iosfwd>
#include <string>
-#include <map>
#include <utility>
#include <vector>
class ParConstIterator;
class ParIterator;
class ParagraphList;
-class StableDocIterator;
class TeXErrors;
class TexRow;
class TocBackend;
/// Reset autosave timers for all users.
boost::signal<void()> resetAutosaveTimers;
/// This signal is emitting if the buffer is being closed.
- boost::signal<void()> closing;
+ boost::signal<void(Buffer *)> closing;
/** Save file.
///
void insertMacro(docstring const & name, MacroData const & data);
- ///
- void saveCursor(StableDocIterator cursor, StableDocIterator anchor);
- ///
- StableDocIterator getCursor() const { return cursor_; }
- ///
- StableDocIterator getAnchor() const { return anchor_; }
///
void changeRefsIfUnique(docstring const & from, docstring const & to,
Inset::Code code);
/// The pointer never changes although *pimpl_'s contents may.
boost::scoped_ptr<Impl> const pimpl_;
- /// Save the cursor Position on Buffer switch
- /// this would not be needed if every Buffer would have
- /// it's BufferView, this should be FIXED in future.
- StableDocIterator cursor_;
- StableDocIterator anchor_;
/// A cache for the bibfiles (including bibfiles of loaded child
/// documents), needed for appropriate update of natbib labels.
mutable std::vector<support::FileName> bibfilesCache_;
} // anon namespace
-BufferView::BufferView()
- : width_(0), height_(0), buffer_(0), wh_(0),
+BufferView::BufferView(Buffer & buf)
+ : width_(0), height_(0), buffer_(buf), wh_(0),
cursor_(*this),
multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0),
intl_(new Intl), last_inset_(0)
{
xsel_cache_.set = false;
intl_->initKeyMapper(lyxrc.use_kbmap);
-}
+ cursor_.push(buffer_.inset());
+ cursor_.resetAnchor();
+ buffer_.text().setCurrentFont(cursor_);
-BufferView::~BufferView()
-{
+ if (graphics::Previews::status() != LyXRC::PREVIEW_OFF)
+ graphics::Previews::get().generateBufferPreviews(buffer_);
}
-Buffer * BufferView::buffer() const
+BufferView::~BufferView()
{
- return buffer_;
}
-Buffer * BufferView::setBuffer(Buffer * b)
+Buffer * BufferView::buffer()
{
- LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
- << "[ b = " << b << "]" << endl;
-
- if (buffer_) {
- // Save the current selection if any
- cap::saveSelection(cursor_);
- // Save the actual cursor position and anchor inside the
- // buffer so that it can be restored in case we rechange
- // to this buffer later on.
- buffer_->saveCursor(cursor_.selectionBegin(),
- cursor_.selectionEnd());
- // update bookmark pit of the current buffer before switch
- for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) {
- BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(i);
- if (buffer()->fileName() != bm.filename.absFilename())
- continue;
- // if top_id or bottom_pit, bottom_pos has been changed, update bookmark
- // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
- pit_type new_pit;
- pos_type new_pos;
- int new_id;
- boost::tie(new_pit, new_pos, new_id) = moveToPosition(bm.bottom_pit, bm.bottom_pos, bm.top_id, bm.top_pos);
- if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos || bm.top_id != new_id )
- const_cast<BookmarksSection::Bookmark &>(bm).updatePos(new_pit, new_pos, new_id);
- }
- // current buffer is going to be switched-off, save cursor pos
- // Ideally, the whole cursor stack should be saved, but session
- // currently can only handle bottom (whole document) level pit and pos.
- // That is to say, if a cursor is in a nested inset, it will be
- // restore to the left of the top level inset.
- LyX::ref().session().lastFilePos().save(FileName(buffer_->fileName()),
- boost::tie(cursor_.bottom().pit(), cursor_.bottom().pos()) );
- }
-
- // If we're quitting lyx, don't bother updating stuff
- if (quitting) {
- buffer_ = 0;
- return 0;
- }
-
- //FIXME Fix for bug 3440 is here.
- // If we are closing current buffer, switch to the first in
- // buffer list.
- if (!b) {
- LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
- << " No Buffer!" << endl;
- // We are closing the buffer, use the first buffer as current
- //FIXME 3440
- // if (last_buffer_) buffer_ = last_buffer_;
- // also check that this is in theBufferList()?
- buffer_ = theBufferList().first();
- } else {
- //FIXME 3440
- // last_buffer = buffer_;
- // Set current buffer
- buffer_ = b;
- }
-
- // Reset old cursor
- cursor_ = Cursor(*this);
- anchor_ref_ = 0;
- offset_ref_ = 0;
-
- if (!buffer_)
- return 0;
-
- LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION
- << "Buffer addr: " << buffer_ << endl;
- cursor_.push(buffer_->inset());
- cursor_.resetAnchor();
- buffer_->text().setCurrentFont(cursor_);
-
- // Update the metrics now that we have a proper Cursor.
- updateMetrics(false);
-
- // FIXME: This code won't be needed once we switch to
- // "one Buffer" / "one BufferView".
- if (buffer_->getCursor().size() > 0 &&
- buffer_->getAnchor().size() > 0)
- {
- cursor_.setCursor(buffer_->getAnchor().asDocIterator(&(buffer_->inset())));
- cursor_.resetAnchor();
- cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset())));
- cursor_.setSelection();
- // do not set selection to the new buffer because we
- // only paste recent selection.
-
- // Make sure that the restored cursor is not broken. This can happen for
- // example if this Buffer has been modified by another view.
- cursor_.fixIfBroken();
-
- if (fitCursor())
- // Update the metrics if the cursor new position was off screen.
- updateMetrics(false);
- }
-
- if (graphics::Previews::status() != LyXRC::PREVIEW_OFF)
- graphics::Previews::get().generateBufferPreviews(*buffer_);
- return buffer_;
+ return &buffer_;
}
-void BufferView::resize()
+Buffer const * BufferView::buffer() const
{
- if (!buffer_)
- return;
-
- LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION << endl;
-
- updateMetrics(false);
+ return &buffer_;
}
<< "[fitcursor = " << (flags & Update::FitCursor)
<< ", forceupdate = " << (flags & Update::Force)
<< ", singlepar = " << (flags & Update::SinglePar)
- << "] buffer: " << buffer_ << endl;
-
- // Check needed to survive LyX startup
- if (!buffer_)
- return false;
-
- LYXERR(Debug::WORKAREA) << "BufferView::update" << std::endl;
+ << "] buffer: " << &buffer_ << endl;
// Update macro store
if (!(cursor().inMathed() && cursor().inMacroMode()))
- buffer_->buildMacros();
+ buffer_.buildMacros();
// Now do the first drawing step if needed. This consists on updating
// the CoordCache in updateMetrics().
void BufferView::updateScrollbar()
{
- if (!buffer_) {
- LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION
- << " no text in updateScrollbar" << endl;
- scrollbarParameters_.reset();
- return;
- }
-
- Text & t = buffer_->text();
+ Text & t = buffer_.text();
TextMetrics & tm = text_metrics_[&t];
int const parsize = int(t.paragraphs().size() - 1);
LYXERR(Debug::GUI) << BOOST_CURRENT_FUNCTION
<< "[ value = " << value << "]" << endl;
- if (!buffer_)
- return;
-
- Text & t = buffer_->text();
+ Text & t = buffer_.text();
TextMetrics & tm = text_metrics_[&t];
float const bar = value / float(wh_ * t.paragraphs().size());
void BufferView::setCursorFromScrollbar()
{
- if (!buffer_)
- return;
-
- Text & t = buffer_->text();
+ Text & t = buffer_.text();
int const height = 2 * defaultRowHeight();
int const first = height;
case bv_funcs::CUR_ABOVE:
// We reset the cursor because bv_funcs::status() does not
// work when the cursor is within mathed.
- cur.reset(buffer_->inset());
+ cur.reset(buffer_.inset());
t.setCursorFromCoordinates(cur, 0, first);
cur.clearSelection();
break;
case bv_funcs::CUR_BELOW:
// We reset the cursor because bv_funcs::status() does not
// work when the cursor is within mathed.
- cur.reset(buffer_->inset());
+ cur.reset(buffer_.inset());
t.setCursorFromCoordinates(cur, 0, last);
cur.clearSelection();
break;
int const y = bv_funcs::getPos(*this, cur, cur.boundary()).y_;
int const newy = min(last, max(y, first));
if (y != newy) {
- cur.reset(buffer_->inset());
+ cur.reset(buffer_.inset());
t.setCursorFromCoordinates(cur, 0, newy);
}
}
// pit and pos will be updated with bottom level pit/pos
// when lyx exits.
LyX::ref().session().bookmarks().save(
- FileName(buffer_->fileName()),
+ FileName(buffer_.fileName()),
cursor_.bottom().pit(),
cursor_.bottom().pos(),
cursor_.paragraph().id(),
// This is the case for a 'live' bookmark when unique paragraph ID
// is used to track bookmarks.
if (top_id > 0) {
- ParIterator par = buffer_->getParFromID(top_id);
- if (par != buffer_->par_iterator_end()) {
+ ParIterator par = buffer_.getParFromID(top_id);
+ if (par != buffer_.par_iterator_end()) {
DocIterator dit = makeDocIterator(par, min(par->size(), top_pos));
// Some slices of the iterator may not be
// reachable (e.g. closed collapsable inset)
// restoration is inaccurate. If a bookmark was within an inset,
// it will be restored to the left of the outmost inset that contains
// the bookmark.
- if (static_cast<size_t>(bottom_pit) < buffer_->paragraphs().size()) {
- DocIterator it = doc_iterator_begin(buffer_->inset());
+ if (static_cast<size_t>(bottom_pit) < buffer_.paragraphs().size()) {
+ DocIterator it = doc_iterator_begin(buffer_.inset());
it.pit() = bottom_pit;
it.pos() = min(bottom_pos, it.paragraph().size());
setCursor(it);
switch (cmd.action) {
case LFUN_UNDO:
- flag.enabled(!buffer_->undostack().empty());
+ flag.enabled(!buffer_.undostack().empty());
break;
case LFUN_REDO:
- flag.enabled(!buffer_->redostack().empty());
+ flag.enabled(!buffer_.redostack().empty());
break;
case LFUN_FILE_INSERT:
case LFUN_FILE_INSERT_PLAINTEXT_PARA:
case LFUN_CHANGES_TRACK:
flag.enabled(true);
- flag.setOnOff(buffer_->params().trackChanges);
+ flag.setOnOff(buffer_.params().trackChanges);
break;
case LFUN_CHANGES_OUTPUT:
- flag.enabled(buffer_);
- flag.setOnOff(buffer_->params().outputChanges);
+ flag.enabled(true);
+ flag.setOnOff(buffer_.params().outputChanges);
break;
case LFUN_CHANGES_MERGE:
// In principle, these command should only be enabled if there
// is a change in the document. However, without proper
// optimizations, this will inevitably result in poor performance.
- flag.enabled(buffer_);
+ flag.enabled(true);
break;
case LFUN_BUFFER_TOGGLE_COMPRESSION: {
- flag.setOnOff(buffer_->params().compressed);
+ flag.setOnOff(buffer_.params().compressed);
break;
}
<< " button[" << cmd.button() << ']'
<< endl;
- // FIXME: this should not be possible.
- if (!buffer_)
- return Update::None;
-
Cursor & cur = cursor_;
// Default Update flags.
Update::flags updateFlags = Update::Force | Update::FitCursor;
case LFUN_PARAGRAPH_GOTO: {
int const id = convert<int>(to_utf8(cmd.argument()));
int i = 0;
- for (Buffer * b = buffer_; i == 0 || b != buffer_; b = theBufferList().next(b)) {
+ for (Buffer * b = &buffer_; i == 0 || b != &buffer_;
+ b = theBufferList().next(b)) {
+
ParIterator par = b->getParFromID(id);
if (par == b->par_iterator_end()) {
LYXERR(Debug::INFO)
<< " found in buffer `"
<< b->fileName() << "'." << endl;
- if (b == buffer_) {
+ if (b == &buffer_) {
// Set the cursor
setCursor(makeDocIterator(par, 0));
} else {
case LFUN_OUTLINE_UP:
toc::outline(toc::Up, cursor_);
cursor_.text()->setCursor(cursor_, cursor_.pit(), 0);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_OUTLINE_DOWN:
toc::outline(toc::Down, cursor_);
cursor_.text()->setCursor(cursor_, cursor_.pit(), 0);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_OUTLINE_IN:
toc::outline(toc::In, cursor_);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_OUTLINE_OUT:
toc::outline(toc::Out, cursor_);
- updateLabels(*buffer_);
+ updateLabels(buffer_);
break;
case LFUN_NOTE_NEXT:
}
case LFUN_CHANGES_TRACK:
- buffer_->params().trackChanges = !buffer_->params().trackChanges;
+ buffer_.params().trackChanges = !buffer_.params().trackChanges;
break;
case LFUN_CHANGES_OUTPUT:
- buffer_->params().outputChanges = !buffer_->params().outputChanges;
- if (buffer_->params().outputChanges) {
+ buffer_.params().outputChanges = !buffer_.params().outputChanges;
+ if (buffer_.params().outputChanges) {
bool dvipost = LaTeXFeatures::isAvailable("dvipost");
bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
LaTeXFeatures::isAvailable("xcolor");
case LFUN_ALL_CHANGES_ACCEPT:
// select complete document
- cursor_.reset(buffer_->inset());
+ cursor_.reset(buffer_.inset());
cursor_.selHandle(true);
- buffer_->text().cursorBottom(cursor_);
+ buffer_.text().cursorBottom(cursor_);
// accept everything in a single step to support atomic undo
- buffer_->text().acceptOrRejectChanges(cursor_, Text::ACCEPT);
+ buffer_.text().acceptOrRejectChanges(cursor_, Text::ACCEPT);
break;
case LFUN_ALL_CHANGES_REJECT:
// select complete document
- cursor_.reset(buffer_->inset());
+ cursor_.reset(buffer_.inset());
cursor_.selHandle(true);
- buffer_->text().cursorBottom(cursor_);
+ buffer_.text().cursorBottom(cursor_);
// reject everything in a single step to support atomic undo
// Note: reject does not work recursively; the user may have to repeat the operation
- buffer_->text().acceptOrRejectChanges(cursor_, Text::REJECT);
+ buffer_.text().acceptOrRejectChanges(cursor_, Text::REJECT);
break;
case LFUN_WORD_FIND:
Inset::BIBTEX_CODE);
if (inset) {
if (inset->addDatabase(to_utf8(cmd.argument())))
- buffer_->updateBibfilesCache();
+ buffer_.updateBibfilesCache();
}
break;
}
Inset::BIBTEX_CODE);
if (inset) {
if (inset->delDatabase(to_utf8(cmd.argument())))
- buffer_->updateBibfilesCache();
+ buffer_.updateBibfilesCache();
}
break;
}
from = cur.selectionBegin();
to = cur.selectionEnd();
} else {
- from = doc_iterator_begin(buffer_->inset());
- to = doc_iterator_end(buffer_->inset());
+ from = doc_iterator_begin(buffer_.inset());
+ to = doc_iterator_end(buffer_.inset());
}
int const count = countWords(from, to);
docstring message;
case LFUN_BUFFER_TOGGLE_COMPRESSION:
// turn compression on/off
- buffer_->params().compressed = !buffer_->params().compressed;
+ buffer_.params().compressed = !buffer_.params().compressed;
break;
case LFUN_NEXT_INSET_TOGGLE: {
docstring const BufferView::requestSelection()
{
- if (!buffer_)
- return docstring();
-
Cursor & cur = cursor_;
if (!cur.selection()) {
void BufferView::clearSelection()
{
- if (buffer_) {
- cursor_.clearSelection();
- // Clear the selection buffer. Otherwise a subsequent
- // middle-mouse-button paste would use the selection buffer,
- // not the more current external selection.
- cap::clearSelection();
- xsel_cache_.set = false;
- // The buffer did not really change, but this causes the
- // redraw we need because we cleared the selection above.
- buffer_->changed();
- }
+ cursor_.clearSelection();
+ // Clear the selection buffer. Otherwise a subsequent
+ // middle-mouse-button paste would use the selection buffer,
+ // not the more current external selection.
+ cap::clearSelection();
+ xsel_cache_.set = false;
+ // The buffer did not really change, but this causes the
+ // redraw we need because we cleared the selection above.
+ buffer_.changed();
}
// The complete text metrics will be redone.
text_metrics_.clear();
-
- if (buffer_)
- resize();
+ updateMetrics(false);
}
// LFUN_FILE_OPEN generated by drag-and-drop.
FuncRequest cmd = cmd0;
- // E.g. Qt mouse press when no buffer
- if (!buffer_)
- return false;
-
Cursor cur(*this);
- cur.push(buffer_->inset());
+ cur.push(buffer_.inset());
cur.selection() = cursor_.selection();
// Either the inset under the cursor or the
// Get inset under mouse, if there is one.
Inset const * covering_inset =
- getCoveringInset(buffer_->text(), cmd.x, cmd.y);
+ getCoveringInset(buffer_.text(), cmd.x, cmd.y);
if (covering_inset == last_inset_)
// Same inset, no need to do anything...
return false;
}
// Build temporary cursor.
- Inset * inset = buffer_->text().editXY(cur, cmd.x, cmd.y);
+ Inset * inset = buffer_.text().editXY(cur, cmd.x, cmd.y);
// Put anchor at the same position.
cur.resetAnchor();
void BufferView::scroll(int /*lines*/)
{
-// if (!buffer_)
-// return;
-//
-// Text const * t = &buffer_->text();
+// Text const * t = buffer_.text();
// int const line_height = defaultRowHeight();
//
// // The new absolute coordinate
int tmpid = -1;
int tmppos = -1;
- buffer_->texrow().getIdFromRow(row, tmpid, tmppos);
+ buffer_.texrow().getIdFromRow(row, tmpid, tmppos);
- cursor_.reset(buffer_->inset());
+ cursor_.reset(buffer_.inset());
if (tmpid == -1)
- buffer_->text().setCursor(cursor_, 0, 0);
+ buffer_.text().setCursor(cursor_, 0, 0);
else
- buffer_->text().setCursor(cursor_, buffer_->getParFromID(tmpid).pit(), tmppos);
+ buffer_.text().setCursor(cursor_, buffer_.getParFromID(tmpid).pit(), tmppos);
}
void BufferView::gotoLabel(docstring const & label)
{
- for (InsetIterator it = inset_iterator_begin(buffer_->inset()); it; ++it) {
+ for (InsetIterator it = inset_iterator_begin(buffer_.inset()); it; ++it) {
vector<docstring> labels;
- it->getLabelList(*buffer_, labels);
+ it->getLabelList(buffer_, labels);
if (std::find(labels.begin(), labels.end(), label) != labels.end()) {
setCursor(it);
update();
if (!changed)
return false;
- updateLabels(*buffer_);
+ updateLabels(buffer_);
updateMetrics(false);
- buffer_->changed();
+ buffer_.changed();
return true;
}
// FIXME: We should split-up updateMetrics() for the singlepar case.
void BufferView::updateMetrics(bool singlepar)
{
- Text & buftext = buffer_->text();
+ Text & buftext = buffer_.text();
TextMetrics & tm = textMetrics(&buftext);
pit_type size = int(buftext.paragraphs().size());
// Launch a file browser
// FIXME UNICODE
string initpath = lyxrc.document_path;
-
- if (buffer_) {
- string const trypath = buffer_->filePath();
- // If directory is writeable, use this as default.
- if (isDirWriteable(FileName(trypath)))
- initpath = trypath;
- }
+ string const trypath = buffer_.filePath();
+ // If directory is writeable, use this as default.
+ if (isDirWriteable(FileName(trypath)))
+ initpath = trypath;
// FIXME UNICODE
FileDialog fileDlg(_("Select LyX document to insert"),
docstring res;
Buffer buf("", false);
if (lyx::loadLyXFile(&buf, FileName(filename))) {
- ErrorList & el = buffer_->errorList("Parse");
+ ErrorList & el = buffer_.errorList("Parse");
// Copy the inserted document error list into the current buffer one.
el = buf.errorList("Parse");
recordUndo(cursor_);
// emit message signal.
message(bformat(res, disp_fn));
- buffer_->errors("Parse");
- resize();
+ buffer_.errors("Parse");
+ updateMetrics(false);
}
} // namespace lyx
*/
class BufferView : boost::noncopyable {
public:
- BufferView();
+ ///
+ BufferView(Buffer & buffer);
~BufferView();
- /// set the buffer we are viewing.
- /// \todo FIXME: eventually, we will create a new BufferView
- /// when switching Buffers, so this method should go.
- /// returns the buffer currently set
- Buffer * setBuffer(Buffer * b);
/// return the buffer being viewed.
- Buffer * buffer() const;
-
- /// resize the BufferView.
- void resize();
+ Buffer * buffer();
+ Buffer const * buffer() const;
/// perform pending metrics updates.
/** \c Update::FitCursor means first to do a FitCursor, and to
///
CoordCache coord_cache_;
///
- Buffer * buffer_;
+ Buffer & buffer_;
/// Estimated average par height for scrollbar.
int wh_;
if (loader_format == "lyx") {
- lv->loadLyXFile(lyxfile);
+ Buffer * buf = lv->loadLyXFile(lyxfile);
+ if (!buf) {
+ // we are done
+ lv->message(_("file not imported!"));
+ return false;
+ }
+ updateLabels(*buf);
+ lv->setBuffer(buf);
+ lv->showErrorList("Parse");
} else {
Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
if (b)
}
BufferList::iterator begin = pimpl_->buffer_list_.begin();
- BufferList::iterator end = pimpl_->buffer_list_.end();
bool final_success = false;
- for (BufferList::iterator I = begin; I != end; ++I) {
+ for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
Buffer * buf = *I;
+ if (buf != buf->getMasterBuffer())
+ continue;
bool success = false;
buf->dispatch(batch_command, &success);
final_success |= success;
if (!pimpl_->files_to_load_.empty()) {
for_each(pimpl_->files_to_load_.begin(),
pimpl_->files_to_load_.end(),
- bind(&LyXView::loadLyXFile, view, _1, true, false, false));
+ bind(&LyXView::loadLyXFile, view, _1, true));
// clear this list to save a few bytes of RAM
pimpl_->files_to_load_.clear();
pimpl_->session_->lastOpened().clear();
- return;
- }
- if (!lyxrc.load_session)
- return;
+ } else if (lyxrc.load_session) {
+ vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
+ // do not add to the lastfile list since these files are restored from
+ // last session, and should be already there (regular files), or should
+ // not be added at all (help files).
+ for_each(lastopened.begin(), lastopened.end(),
+ bind(&LyXView::loadLyXFile, view, _1, false));
- vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
- // do not add to the lastfile list since these files are restored from
- // last session, and should be already there (regular files), or should
- // not be added at all (help files).
- for_each(lastopened.begin(), lastopened.end(),
- bind(&LyXView::loadLyXFile, view, _1, false, false, false));
+ // clear this list to save a few bytes of RAM
+ pimpl_->session_->lastOpened().clear();
+ }
+
+ BufferList::iterator I = pimpl_->buffer_list_.begin();
+ BufferList::iterator end = pimpl_->buffer_list_.end();
+ for (; I != end; ++I) {
+ Buffer * buf = *I;
+ if (buf != buf->getMasterBuffer())
+ continue;
+ updateLabels(*buf);
+ }
- // clear this list to save a few bytes of RAM
- pimpl_->session_->lastOpened().clear();
+ // FIXME: Switch to the last loaded Buffer. This must not be the first one
+ // because the Buffer won't be connected in this case. The correct solution
+ // would be to avoid the manual connection of the current Buffer in LyXView.
+ view->setBuffer(pimpl_->buffer_list_.last());
}
{ LFUN_BUFFER_NEW, "buffer-new", NoBuffer },
{ LFUN_BUFFER_NEW_TEMPLATE,"buffer-new-template", NoBuffer },
{ LFUN_BUFFER_RELOAD, "buffer-reload", ReadOnly },
- { LFUN_BUFFER_SWITCH, "buffer-switch", ReadOnly },
+ { LFUN_BUFFER_SWITCH, "buffer-switch", NoBuffer | ReadOnly },
{ LFUN_BUFFER_TOGGLE_READ_ONLY, "buffer-toggle-read-only", ReadOnly },
{ LFUN_BUFFER_UPDATE, "buffer-update", ReadOnly },
{ LFUN_BUFFER_VIEW, "buffer-view", ReadOnly },
#include "frontends/KeySymbol.h"
#include "frontends/LyXView.h"
#include "frontends/Menubar.h"
-#include "frontends/Toolbars.h"
#include "frontends/Selection.h"
+#include "frontends/Toolbars.h"
+#include "frontends/WorkArea.h"
#include "support/environment.h"
#include "support/FileFilterList.h"
void LyXFunc::setLyXView(LyXView * lv)
{
- if (!quitting && lyx_view_ && lyx_view_ != lv)
+ if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
// save current selection to the selection buffer to allow
// middle-button paste in another window
cap::saveSelection(lyx_view_->view()->cursor());
} else {
dispatch(func);
}
+
+ /* When we move around, or type, it's nice to be able to see
+ * the cursor immediately after the keypress.
+ */
+ if (lyx_view_ && lyx_view_->currentWorkArea())
+ lyx_view_->currentWorkArea()->startBlinkingCursor();
}
// --- Menus -----------------------------------------------
case LFUN_BUFFER_NEW:
menuNew(argument, false);
+ updateFlags = Update::None;
break;
case LFUN_BUFFER_NEW_TEMPLATE:
menuNew(argument, true);
+ updateFlags = Update::None;
break;
case LFUN_BUFFER_CLOSE:
closeBuffer();
- view()->update();
+ updateFlags = Update::None;
break;
case LFUN_BUFFER_WRITE:
}
lyx_view_->message(bformat(_("Opening help file %1$s..."),
makeDisplayPath(fname.absFilename())));
- lyx_view_->loadLyXFile(fname, false);
+ Buffer * buf = lyx_view_->loadLyXFile(fname, false);
+ if (buf) {
+ updateLabels(*buf);
+ lyx_view_->setBuffer(buf);
+ lyx_view_->showErrorList("Parse");
+ }
+ updateFlags = Update::None;
break;
}
case LFUN_BUFFER_SWITCH:
BOOST_ASSERT(lyx_view_);
lyx_view_->setBuffer(theBufferList().getBuffer(argument));
- updateFlags = Update::Force;
+ updateFlags = Update::None;
break;
case LFUN_BUFFER_NEXT:
BOOST_ASSERT(lyx_view_);
lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
- updateFlags = Update::Force;
+ updateFlags = Update::None;
break;
case LFUN_BUFFER_PREVIOUS:
BOOST_ASSERT(lyx_view_);
lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
- updateFlags = Update::Force;
+ updateFlags = Update::None;
break;
case LFUN_FILE_NEW:
BOOST_ASSERT(lyx_view_);
newFile(*lyx_view_, argument);
+ updateFlags = Update::None;
break;
case LFUN_FILE_OPEN:
BOOST_ASSERT(lyx_view_);
open(argument);
+ updateFlags = Update::None;
break;
case LFUN_DROP_LAYOUTS_CHOICE:
int row;
istringstream is(argument);
is >> file_name >> row;
- if (prefixIs(file_name, package().temp_dir().absFilename())) {
+ Buffer * buf = 0;
+ bool loaded = false;
+ if (prefixIs(file_name, package().temp_dir().absFilename()))
// Needed by inverse dvi search. If it is a file
// in tmpdir, call the apropriated function
- lyx_view_->setBuffer(theBufferList().getBufferFromTmp(file_name));
- } else {
+ buf = theBufferList().getBufferFromTmp(file_name);
+ else {
// Must replace extension of the file to be .lyx
// and get full path
FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
// Either change buffer or load the file
- if (theBufferList().exists(s.absFilename())) {
- lyx_view_->setBuffer(theBufferList().getBuffer(s.absFilename()));
- } else {
- lyx_view_->loadLyXFile(s);
+ if (theBufferList().exists(s.absFilename()))
+ buf = theBufferList().getBuffer(s.absFilename());
+ else {
+ buf = lyx_view_->loadLyXFile(s);
+ loaded = true;
}
}
- view()->setCursorFromRow(row);
+ if (!buf) {
+ updateFlags = Update::None;
+ break;
+ }
+ updateLabels(*buf);
+ lyx_view_->setBuffer(buf);
+ view()->setCursorFromRow(row);
+ if (loaded)
+ lyx_view_->showErrorList("Parse");
updateFlags = Update::FitCursor;
break;
}
}
case LFUN_BUFFER_CHILD_OPEN: {
- // takes an optional argument, "|bool", at the end
- // indicating whether this file is being opened automatically
- // by LyX itself, in which case we will not want to switch
- // buffers after opening. The default is false, so in practice
- // it is used only when true.
- BOOST_ASSERT(lyx_view_);
- int const arglength = argument.length();
- FileName filename;
- bool autoOpen = false;
- if (argument.substr(arglength - 5, 5) == "|true") {
- autoOpen = true;
- filename = makeAbsPath(argument.substr(0, arglength - 5),
- lyx_view_->buffer()->filePath());
- } else if (argument.substr(arglength - 6, 6) == "|false") {
- filename = makeAbsPath(argument.substr(0, arglength - 6),
- lyx_view_->buffer()->filePath());
- } else filename =
- makeAbsPath(argument, lyx_view_->buffer()->filePath());
+ BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
+ Buffer * parent = lyx_view_->buffer();
+ FileName filename = makeAbsPath(argument, parent->filePath());
view()->saveBookmark(false);
+ Buffer * child = 0;
+ bool parsed = false;
if (theBufferList().exists(filename.absFilename())) {
- Buffer * buf = theBufferList().getBuffer(filename.absFilename());
- if (!autoOpen)
- lyx_view_->setBuffer(buf, true);
- else
- buf->setParentName(lyx_view_->buffer()->fileName());
- } else
- lyx_view_->loadLyXFile(filename, true, true, autoOpen);
+ child = theBufferList().getBuffer(filename.absFilename());
+ } else {
+ setMessage(bformat(_("Opening child document %1$s..."),
+ makeDisplayPath(filename.absFilename())));
+ child = lyx_view_->loadLyXFile(filename, true);
+ parsed = true;
+ }
+ if (child) {
+ // Set the parent name of the child document.
+ // This makes insertion of citations and references in the child work,
+ // when the target is in the parent or another child document.
+ child->setParentName(parent->fileName());
+ updateLabels(*child->getMasterBuffer());
+ lyx_view_->setBuffer(child);
+ if (parsed)
+ lyx_view_->showErrorList("Parse");
+ }
// If a screen update is required (in case where auto_open is false),
- // loadLyXFile() would have taken care of it already. Otherwise we shall
+ // setBuffer() would have taken care of it already. Otherwise we shall
// reset the update flag because it can cause a circular problem.
// See bug 3970.
updateFlags = Update::None;
}
Buffer * const b = newFile(filename, templname, !name.empty());
- if (b) {
- updateLabels(*b);
+ if (b)
lyx_view_->setBuffer(b);
- }
}
lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
docstring str2;
- if (lyx_view_->loadLyXFile(fullname)) {
+ Buffer * buf = lyx_view_->loadLyXFile(fullname);
+ if (buf) {
+ updateLabels(*buf);
+ lyx_view_->setBuffer(buf);
+ lyx_view_->showErrorList("Parse");
str2 = bformat(_("Document %1$s opened."), disp_fn);
} else {
str2 = bformat(_("Could not open document %1$s"), disp_fn);
void LyXFunc::reloadBuffer()
{
FileName filename(lyx_view_->buffer()->fileName());
+ docstring const disp_fn = makeDisplayPath(filename.absFilename());
+ docstring str;
closeBuffer();
- lyx_view_->loadLyXFile(filename);
+ Buffer * buf = lyx_view_->loadLyXFile(filename);
+ if (buf) {
+ updateLabels(*buf);
+ lyx_view_->setBuffer(buf);
+ lyx_view_->showErrorList("Parse");
+ str = bformat(_("Document %1$s reloaded."), disp_fn);
+ } else {
+ str = bformat(_("Could not reload document %1$s"), disp_fn);
+ }
+ lyx_view_->message(str);
}
// Each "lyx_view_" should have it's own message method. lyxview and
const std::string & geometryArg)
{
LyXView & view = gui().createRegisteredView();
- int view_id = view.id();
-
theLyXFunc().setLyXView(&view);
- /*int workArea_id_ =*/ gui().newWorkArea(width, height, view_id);
-
view.init();
view.setGeometry(width, height, posx, posy, maximized, iconSizeXY, geometryArg);
+
view.setFocus();
setCurrentView(view);
There should be only one instance of this class. No Qt object
initialisation should be done before the instanciation of this class.
-\todo The work areas handling could be moved to a base virtual class
-common to all frontends.
+ Model/View/Controller separation at frontend level in LyX-qt4:
+
+ BufferList (N Buffers)
+ |
+ Buffer-a
+ Buffer-b
+ Buffer-c
+ Buffer-d
+
+ Application (this is the frontend really, should probably be renamed).
+ |
+ LyXView-1 (M1 WorkAreas, M1 <= N)
+ | |
+ | <tab-widget>
+ | | (many)
+ | WorkArea-1
+ | |
+ | BufferView <-----------> Buffer-c
+ | |
+ | Cursor
+ |
+ LyXView-2 (M2 WorkAreas, M2 <= N, M2 independent of M1)
+ |
+ ...
- Model/View/Controller separation in LyX:
1) The Model: \c Buffer
The Buffer is the in-memory representation of a LyX file format. The
Buffer does not (should not) have any information on what part of it
is represented on screen. There is one unique Buffer per opened LyX
- file.
+ file. A Buffer may or may not be represented on screen; typically, a
+ child document does not have an associated BufferView unless the user
+ choose to visualize it.
- 2) The Controller: \c BufferView / \c Painter
+ 2) The Controller: \c BufferView / \c Painter \c Cursor
- The BufferView is a tool used by the view that translates a part of
- the Buffer contents into drawing routines. The BufferView asks each
- inset of the Buffer to draw itself onto the screen using the Painter.
- There can be only one Buffer displayed in a BufferView. While there
- is the possibility to switch Buffer inside the BufferView, the goal
- is to instantiate a new BufferView on each Buffer switch.
+ The BufferView is a tool used by the view (\sa WorkArea) that
+ translates a part of the Buffer contents into drawing routines. The
+ BufferView asks each inset of the Buffer to draw itself onto the
+ screen using the Painter. There can be only one Buffer displayed in
+ a BufferView and it is set on construction. Ideally, a BufferView
+ should not be able to change the contents of its associated Buffer.
+ A BufferView is instanciated and destroyed by a \c WorkArea; it is
+ automatically destroyed by the parent WorkArea when its Buffer is
+ closed.
- \todo Instantiate a new BufferView on each Buffer switch.
+ \todo Move all Buffer changing LFUN to LyXFunc or Cursor.
+ \todo BufferView::buffer() should only offer const access.
The \c Painter is just a virtual interface to formalize each kind of
drawing routines (text, line, rectangle, etc).
3) The View: \c WorkArea (and it's qt4 specialisation GuiWorkArea)
This contains the real screen area where the drawing is done by the
- Painter. One WorkArea holds one unique \c BufferView. While it could be
- possible that multiple WorkArea share one BufferView, this is not
- possible right now.
+ Painter. One WorkArea holds one unique \c BufferView. While it could
+ be possible that multiple WorkArea share one BufferView, this is not
+ something desirable because a BufferView is dependent of the WorkArea
+ size.
The WorkArea also provide a scrollbar which position is translated
into scrolling command to the inner \c BufferView.
4) The Window: \c LyXView (and its qt4 specialisation \c GuiView)
- This is a full window containing a menubar, toolbars, a tabbar and a
- WorkArea. One LyXView could in theory contain multiple WorkArea
- (ex: with split window) but this number is limited to one only for
- now. In any case, there would be only one WorkArea that gets the focus
+ This is a full window containing a menubar, toolbars and a central
+ widget. A LyXView is in charge of creating and closing a View for a
+ given Buffer.
+ In the qt4 specialisation, \c GuiView, the central widget is a tab
+ widget. Each tab is reverved to the visualisation of one Buffer and
+ contains one WorkArea. In the qt4 frontend, one LyXView thus contains
+ multiple WorkAreas but this number can limited to one for another
+ frontend. The idea is that the kernel should not know how a Buffer
+ is displayed on screen; it's the frontend business.
+ In the future, we may also have multiple Workareas showing
+ simultaneously in the same GuiView (ex: with split window).
+
+ \todo Implement split-window
+
+ In any case, there would be only one WorkArea that gets the focus
at a time.
- Now, concerning the TabBar versus TabWidget issue. Right now, there is
- only one WorkArea and the TabBar just used to tell the BufferView inside
- the WorkArea to switch to this another Buffer.
+ With our current implementation using a QTabWidget, each Tab own its
+ own \c WorkArea. Clicking on a tab switch a WorkArea and not really
+ a Buffer. LFUN_BUFFER_SWITCH will tell the frontend to search the
+ WorkArea associated to this Buffer. The WorkArea is automatically
+ created if not already present.
+
+ A WorkArea is connected to the Buffer::closing signal and is thus
+ automatically destroyed when its Buffer is closed.
- With a TabWidget, each Tab would own its own \c WorkArea. Clicking on a tab
- would switch a WorkArea instead of a Buffer.
*/
class Application
{
return view_ids_;
}
-
- virtual int newWorkArea(unsigned int width, unsigned int height, int view_id) = 0;
- ///
- virtual WorkArea & workArea(int id) = 0;
-
protected:
std::vector<int> view_ids_;
docstring current_layout;
LyXView::LyXView(int id)
- : work_area_(0),
- toolbars_(new Toolbars(*this)),
+ : toolbars_(new Toolbars(*this)),
autosave_timeout_(new Timeout(5000)),
dialogs_(new Dialogs(*this)),
controlcommand_(new ControlCommandBuffer(*this)), id_(id)
LyXView::~LyXView()
{
disconnectBuffer();
+ disconnectBufferView();
}
-// FIXME, there's only one WorkArea per LyXView possible for now.
-void LyXView::setWorkArea(WorkArea * work_area)
+Buffer * LyXView::buffer()
{
- BOOST_ASSERT(work_area);
- work_area_ = work_area;
- work_area_ids_.clear();
- work_area_ids_.push_back(work_area_->id());
+ WorkArea * work_area = currentWorkArea();
+ if (work_area)
+ return work_area->bufferView().buffer();
+ return 0;
}
-// FIXME, there's only one WorkArea per LyXView possible for now.
-WorkArea const * LyXView::currentWorkArea() const
+Buffer const * LyXView::buffer() const
{
- return work_area_;
+ WorkArea const * work_area = currentWorkArea();
+ if (work_area)
+ return work_area->bufferView().buffer();
+ return 0;
}
-// FIXME, there's only one WorkArea per LyXView possible for now.
-WorkArea * LyXView::currentWorkArea()
-{
- return work_area_;
-}
-
-
-Buffer * LyXView::buffer() const
-{
- BOOST_ASSERT(work_area_);
- return work_area_->bufferView().buffer();
-}
-
-
-void LyXView::setBuffer(Buffer * b, bool child_document)
+void LyXView::setBuffer(Buffer * newBuffer)
{
busy(true);
- BOOST_ASSERT(work_area_);
- Buffer * oldBuffer = work_area_->bufferView().buffer();
+ Buffer * oldBuffer = buffer();
+ if (oldBuffer == newBuffer) {
+ busy(false);
+ return;
+ }
+
// parentfilename will be used in case when we switch to a child
// document (hence when child_document is true)
string parentfilename;
if (oldBuffer)
parentfilename = oldBuffer->fileName();
- if (!b && theBufferList().empty())
- getDialogs().hideBufferDependent();
-
- Buffer * newBuffer = work_area_->bufferView().setBuffer(b);
-
- if (newBuffer) {
- //Are we closing an oldBuffer which was a child document?
- if (!b && oldBuffer && oldBuffer->getMasterBuffer() != oldBuffer)
- // Update the labels and section numbering of its master Buffer.
- updateLabels(*oldBuffer->getMasterBuffer());
- //Are we opening a new child document?
- else if (child_document && newBuffer->getMasterBuffer() != oldBuffer) {
- // Set the parent name of the child document.
- // This makes insertion of citations and references in the child work,
- // when the target is in the parent or another child document.
- newBuffer->setParentName(parentfilename);
- // Update the labels and section numbering to the new master Buffer.
- updateLabels(*newBuffer->getMasterBuffer());
- }
- //Now that all the updating of the old buffer has been done, we can
- //connect the new buffer. Note that this will also disconnect the old
- //buffer, if such there is.
- //FIXME Is it clear that this should go right here? Or should it go
- //earlier before the previous if (in which case we'd remove the "else")?
- connectBuffer(*newBuffer);
-
- /* FIXME: We need to rebuild the Toc dialog before the others even
- if it will be rebuilt again in the next line. This avoid a crash when
- other dialogs are rebuilt before the Toc dialog. The reason is
- that closing a Buffer triggers an update of all opened dialogs
- when dispatching LFUN_DIALOG_UPDATE (hence the patch).
- The path is as following:
- setBuffer() -> updateBufferDependent() -> RestoreButton() -> LFUN
- The problem here is that the Toc dialog has not been
- reconstructed (because it comes after in the list of dialogs). */
- updateToc();
-
- // Buffer-dependent dialogs should be updated or
- // hidden. This should go here because some dialogs (eg ToC)
- // require bv_->text.
- getDialogs().updateBufferDependent(true);
+ WorkArea * wa = workArea(*newBuffer);
+ if (wa == 0) {
+ updateLabels(*newBuffer->getMasterBuffer());
+ wa = addWorkArea(*newBuffer);
} else
//Disconnect the old buffer...there's no new one.
disconnectBuffer();
+ connectBuffer(*newBuffer);
+ connectBufferView(wa->bufferView());
+ setCurrentWorkArea(wa);
- if (quitting)
- return;
-
- updateMenubar();
- updateToolbars();
- updateLayoutChoice();
- updateWindowTitle();
- updateStatusBar();
- updateTab();
busy(false);
- work_area_->redraw();
}
-bool LyXView::loadLyXFile(FileName const & filename, bool tolastfiles,
- bool child_document, bool auto_open)
+Buffer * LyXView::loadLyXFile(FileName const & filename, bool tolastfiles)
{
busy(true);
-
- BOOST_ASSERT(work_area_);
string parentfilename;
- Buffer * oldBuffer = work_area_->bufferView().buffer();
+ Buffer * oldBuffer = buffer();
if (oldBuffer)
parentfilename = oldBuffer->fileName();
- bool alreadyLoaded = checkIfLoaded(filename);
Buffer * newBuffer = checkAndLoadLyXFile(filename);
if (!newBuffer) {
message(_("Document not loaded."));
updateStatusBar();
busy(false);
- work_area_->redraw();
- return false;
+ return 0;
}
- if (child_document && newBuffer != oldBuffer) {
- // Set the parent name of the child document.
- // This makes insertion of citations and references in the child work,
- // when the target is in the parent or another child document.
- newBuffer->setParentName(parentfilename);
- message(bformat(_("Opening child document %1$s..."),
- makeDisplayPath(filename.absFilename())));
- }
-
- // Update the labels and section numbering.
- updateLabels(*newBuffer->getMasterBuffer());
-
- bool const parse_error = !newBuffer->errorList("Parse").empty();
- bool const need_switch = parse_error || !auto_open;
- if (need_switch) {
- setBuffer(newBuffer, child_document);
- if (!alreadyLoaded) {
- if (parse_error)
- showErrorList("Parse");
- // scroll to the position when the file was last closed
- if (lyxrc.use_lastfilepos) {
- pit_type pit;
- pos_type pos;
- boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename);
- // if successfully move to pit (returned par_id is not zero),
- // update metrics and reset font
- if (work_area_->bufferView().moveToPosition(pit, pos, 0, 0).get<1>()) {
- if (work_area_->bufferView().fitCursor())
- work_area_->bufferView().updateMetrics(false);
- newBuffer->text().setCurrentFont(work_area_->bufferView().cursor());
- updateMenubar();
- updateToolbars();
- updateLayoutChoice();
- updateStatusBar();
- work_area_->redraw();
- }
- }
- if (tolastfiles)
- LyX::ref().session().lastFiles().add(filename);
+ WorkArea * wa = addWorkArea(*newBuffer);
+
+ // scroll to the position when the file was last closed
+ if (lyxrc.use_lastfilepos) {
+ pit_type pit;
+ pos_type pos;
+ boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename);
+ // if successfully move to pit (returned par_id is not zero),
+ // update metrics and reset font
+ BufferView & bv = wa->bufferView();
+ if (bv.moveToPosition(pit, pos, 0, 0).get<1>()) {
+ if (bv.fitCursor())
+ bv.updateMetrics(false);
+ newBuffer->text().setCurrentFont(bv.cursor());
}
}
busy(false);
- return true;
+ return newBuffer;
}
if (errorsConnection_.connected())
disconnectBuffer();
- BOOST_ASSERT(work_area_);
- bufferChangedConnection_ =
- buf.changed.connect(
- boost::bind(&WorkArea::redraw, work_area_));
-
bufferStructureChangedConnection_ =
buf.getMasterBuffer()->structureChanged.connect(
boost::bind(&LyXView::updateToc, this));
readonlyConnection_ =
buf.readonly.connect(
boost::bind(&LyXView::showReadonly, this, _1));
-
- closingConnection_ =
- buf.closing.connect(
- boost::bind(&LyXView::setBuffer, this, (Buffer *)0, false));
}
void LyXView::disconnectBuffer()
{
errorsConnection_.disconnect();
- bufferChangedConnection_.disconnect();
bufferStructureChangedConnection_.disconnect();
messageConnection_.disconnect();
busyConnection_.disconnect();
titleConnection_.disconnect();
timerConnection_.disconnect();
readonlyConnection_.disconnect();
- closingConnection_.disconnect();
layout_changed_connection_.disconnect();
}
void LyXView::connectBufferView(BufferView & bv)
{
+ message_connection_ = bv.message.connect(
+ boost::bind(&LyXView::message, this, _1));
show_dialog_connection_ = bv.showDialog.connect(
boost::bind(&LyXView::showDialog, this, _1));
show_dialog_with_data_connection_ = bv.showDialogWithData.connect(
void LyXView::disconnectBufferView()
{
+ message_connection_.disconnect();
show_dialog_connection_.disconnect();
show_dialog_with_data_connection_.disconnect();
show_inset_dialog_connection_.disconnect();
}
-BufferView * LyXView::view() const
+BufferView * LyXView::view()
{
- BOOST_ASSERT(work_area_);
- return &work_area_->bufferView();
+ WorkArea * wa = currentWorkArea();
+ return wa? &wa->bufferView() : 0;
}
void LyXView::updateToolbars()
{
- BOOST_ASSERT(work_area_);
- bool const math =
- work_area_->bufferView().cursor().inMathed();
- bool const table =
- lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
- bool const review =
- lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
- lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
-
- toolbars_->update(math, table, review);
+ WorkArea * wa = currentWorkArea();
+ if (wa) {
+ bool const math =
+ wa->bufferView().cursor().inMathed();
+ bool const table =
+ lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
+ bool const review =
+ lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
+ lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
+
+ toolbars_->update(math, table, review);
+ } else
+ toolbars_->update(false, false, false);
+
// update redaonly status of open dialogs. This could also be in
// updateMenubar(), but since updateToolbars() and updateMenubar()
// are always called together it is only here.
{
LYXERR(Debug::INFO) << "Running autoSave()" << endl;
- if (view()->buffer())
+ if (buffer())
lyx::autoSave(view());
}
void LyXView::updateLayoutChoice()
{
// Don't show any layouts without a buffer
- if (!view()->buffer()) {
+ if (!buffer()) {
toolbars_->clearLayoutList();
return;
}
current_layout = buffer()->params().getTextClass().defaultLayoutName();
}
- BOOST_ASSERT(work_area_);
- docstring const & layout = work_area_->bufferView().cursor().
+ docstring const & layout = currentWorkArea()->bufferView().cursor().
innerParagraph().layout()->name();
if (layout != current_layout) {
docstring maximize_title = lyx::from_ascii("LyX");
docstring minimize_title = lyx::from_ascii("LyX");
- if (view()->buffer()) {
- string const cur_title = buffer()->fileName();
+ Buffer * buf = buffer();
+ if (buf) {
+ string const cur_title = buf->fileName();
if (!cur_title.empty()) {
maximize_title += ": " + makeDisplayPath(cur_title, 30);
minimize_title = lyx::from_utf8(onlyFilename(cur_title));
- if (!buffer()->isClean()) {
+ if (!buf->isClean()) {
maximize_title += _(" (changed)");
minimize_title += lyx::char_type('*');
}
- if (buffer()->isReadonly())
+ if (buf->isReadonly())
maximize_title += _(" (read only)");
}
}
setWindowTitle(maximize_title, minimize_title);
- updateTab();
}
void LyXView::dispatch(FuncRequest const & cmd)
{
- theLyXFunc().setLyXView(this);
- lyx::dispatch(cmd);
+ string const argument = to_utf8(cmd.argument());
+ switch(cmd.action) {
+ case LFUN_BUFFER_SWITCH:
+ setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
+ break;
+ default:
+ theLyXFunc().setLyXView(this);
+ lyx::dispatch(cmd);
+ }
}
-Buffer const * const LyXView::updateInset(Inset const * inset) const
+Buffer const * const LyXView::updateInset(Inset const * inset)
{
- Buffer const * buffer_ptr = 0;
- if (inset) {
- BOOST_ASSERT(work_area_);
- work_area_->scheduleRedraw();
+ WorkArea * work_area = currentWorkArea();
+ if (!work_area)
+ return 0;
- buffer_ptr = work_area_->bufferView().buffer();
+ if (inset) {
+ BOOST_ASSERT(work_area);
+ work_area->scheduleRedraw();
}
- return buffer_ptr;
+ return work_area->bufferView().buffer();
}
} // namespace frontend
virtual void setFocus() = 0;
- std::vector<int> const & workAreaIds() const { return work_area_ids_; }
-
- /// FIXME: rename to setCurrentWorkArea()
- void setWorkArea(WorkArea * work_area);
-
+ ///
+ virtual WorkArea * workArea(Buffer & buffer) = 0;
+ ///
+ virtual WorkArea * addWorkArea(Buffer & buffer) = 0;
+ ///
+ virtual void setCurrentWorkArea(WorkArea * work_area) = 0;
+ ///
+ virtual void removeWorkArea(WorkArea * work_area) = 0;
/// return the current WorkArea (the one that has the focus).
- WorkArea const * currentWorkArea() const;
+ virtual WorkArea const * currentWorkArea() const = 0;
/// FIXME: This non-const access is needed because of
/// a mis-designed \c ControlSpellchecker.
- WorkArea * currentWorkArea();
+ virtual WorkArea * currentWorkArea() = 0;
/**
* This is called after the concrete view has been created.
//@{ generic accessor functions
- /** return the current buffer view
- Returned as a shared_ptr so that anything wanting to cache the
- buffer view can do so safely using a boost::weak_ptr.
- */
- BufferView * view() const;
+ /// \return the current buffer view.
+ BufferView * view();
- /// return the buffer currently shown in this window
- Buffer * buffer() const;
+ /// \return the buffer currently shown in this window
+ Buffer * buffer();
+ Buffer const * buffer() const;
/// return the toolbar for this view
Toolbars & getToolbars() { return *toolbars_.get(); }
//@}
/// load a buffer into the current workarea.
- bool loadLyXFile(support::FileName const & name, ///< File to load.
- bool tolastfiles = true, ///< append to the "Open recent" menu?
- bool child_document = false, ///< Is this a child document?
- bool auto_open = false); ///< Is this being opened by LyX itself?
+ Buffer * loadLyXFile(support::FileName const & name, ///< File to load.
+ bool tolastfiles = true); ///< append to the "Open recent" menu?
/// set a buffer to the current workarea.
- void setBuffer(Buffer * b, ///< \c Buffer to set.
- bool child_document = false); ///< Is this a child document?
+ void setBuffer(Buffer * b); ///< \c Buffer to set.
/// updates the possible layouts selectable
void updateLayoutChoice();
/// updates the title of the window
void updateWindowTitle();
- /// updates the tab view
- virtual void updateTab() = 0;
-
/// reset autosave timer
void resetAutosaveTimer();
/** redraw \c inset in all the BufferViews in which it is currently
* visible. If successful return a pointer to the owning Buffer.
*/
- Buffer const * const updateInset(Inset const *) const;
+ Buffer const * const updateInset(Inset const *);
/// returns true if this view has the focus.
virtual bool hasFocus() const = 0;
/// show the error list to the user
void showErrorList(std::string const &);
+protected:
/// connect to signals in the given BufferView
void connectBufferView(BufferView & bv);
/// disconnect from signals in the given BufferView
void disconnectBufferView();
-
-protected:
- /// current work area (screen view of a BufferView).
- /**
- \todo FIXME: there is only one workArea per LyXView for now.
- */
- frontend::WorkArea * work_area_;
+ /// connect to signals in the given buffer
+ void connectBuffer(Buffer & buf);
+ /// disconnect from signals in the given buffer
+ void disconnectBuffer();
/// view's menubar
boost::scoped_ptr<Menubar> menubar_;
/// dialogs for this view
boost::scoped_ptr<Dialogs> dialogs_;
- /// buffer changed signal connection
- boost::signals::connection bufferChangedConnection_;
/// buffer structure changed signal connection
boost::signals::connection bufferStructureChangedConnection_;
/// buffer errors signal connection
boost::signals::connection timerConnection_;
/// buffer readonly status changed signal connection
boost::signals::connection readonlyConnection_;
- /// buffer closing signal connection
- boost::signals::connection closingConnection_;
- /// connect to signals in the given buffer
- void connectBuffer(Buffer & buf);
- /// disconnect from signals in the given buffer
- /// NOTE: Do not call this unless you really want no buffer
- /// to be connected---for example, when closing the last open
- /// buffer. If you are switching buffers, just call
- /// connectBuffer(), and the old buffer will be disconnected
- /// automatically. This ensures that we do not leave LyX in a
- /// state in which no buffer is connected.
- void disconnectBuffer();
/// BufferView messages signal connection
//@{
private:
int id_;
- std::vector<int> work_area_ids_;
};
} // namespace frontend
#include "frontends/Application.h"
#include "frontends/FontMetrics.h"
-
-#include "FuncRequest.h"
-#include "LyXFunc.h"
+#include "frontends/LyXView.h"
#include "BufferView.h"
#include "Buffer.h"
#include "BufferParams.h"
+#include "Color.h"
#include "CoordCache.h"
#include "Cursor.h"
#include "debug.h"
-#include "Language.h"
-#include "Color.h"
#include "Font.h"
+#include "FuncRequest.h"
+#include "Language.h"
+#include "LyX.h"
+#include "LyXFunc.h"
#include "LyXRC.h"
-#include "Text.h"
-#include "LyXView.h"
#include "MetricsInfo.h"
+#include "Text.h"
#include "gettext.h"
#include "support/ForkedcallsController.h"
+#include "support/FileName.h"
#include <boost/utility.hpp>
#include <boost/bind.hpp>
namespace lyx {
namespace frontend {
-WorkArea::WorkArea(int id, LyXView & lyx_view)
- : buffer_view_(0), lyx_view_(lyx_view), greyed_out_(true),
- id_(id), cursor_visible_(false), cursor_timeout_(400)
+WorkArea::WorkArea(Buffer & buffer, LyXView & lv)
+ : buffer_view_(new BufferView(buffer)), lyx_view_(&lv),
+ cursor_visible_(false), cursor_timeout_(400)
{
- // Start loading the pixmap as soon as possible
- //if (lyxrc.show_banner) {
- // showBanner();
- //}
-
// Setup the signals
timecon = cursor_timeout_.timeout
.connect(boost::bind(&WorkArea::toggleCursor, this));
+ bufferChangedConnection_ =
+ buffer.changed.connect(
+ boost::bind(&WorkArea::redraw, this));
+
+ bufferClosingConnection_ =
+ buffer.closing.connect(
+ boost::bind(&WorkArea::close, this));
+
cursor_timeout_.start();
}
-void WorkArea::setBufferView(BufferView * buffer_view)
+WorkArea::~WorkArea()
{
- if (buffer_view_) {
- message_connection_.disconnect();
- lyx_view_.disconnectBufferView();
- }
-
- hideCursor();
- buffer_view_ = buffer_view;
- toggleCursor();
+ bufferChangedConnection_.disconnect();
+ bufferClosingConnection_.disconnect();
+
+ // current buffer is going to be switched-off, save cursor pos
+ // Ideally, the whole cursor stack should be saved, but session
+ // currently can only handle bottom (whole document) level pit and pos.
+ // That is to say, if a cursor is in a nested inset, it will be
+ // restore to the left of the top level inset.
+ Cursor & cur = buffer_view_->cursor();
+ LyX::ref().session().lastFilePos().save(
+ support::FileName(buffer_view_->buffer()->fileName()),
+ boost::tie(cur.bottom().pit(), cur.bottom().pos()) );
+
+ delete buffer_view_;
+}
- message_connection_ = buffer_view_->message.connect(
- boost::bind(&WorkArea::displayMessage, this, _1));
- lyx_view_.connectBufferView(*buffer_view);
+void WorkArea::close()
+{
+ lyx_view_->removeWorkArea(this);
}
+//void WorkArea::setLyXView(LyXView * lyx_view)
+//{
+// lyx_view_ = lyx_view;
+//}
+
BufferView & WorkArea::bufferView()
{
void WorkArea::redraw()
{
- if (!buffer_view_ || !buffer_view_->buffer()) {
- greyed_out_ = true;
- // The argument here are meaningless.
- expose(1,1,1,1);
+ if (!isVisible())
+ // No need to redraw in this case.
return;
- }
// No need to do anything if this is the current view. The BufferView
// metrics are already up to date.
- if (&lyx_view_ != theApp()->currentView()) {
+ if (lyx_view_ != theApp()->currentView()) {
// FIXME: it would be nice to optimize for the off-screen case.
buffer_view_->updateMetrics(false);
buffer_view_->cursor().fixIfBroken();
}
ViewMetricsInfo const & vi = buffer_view_->viewMetricsInfo();
- greyed_out_ = false;
LYXERR(Debug::WORKAREA) << "WorkArea::redraw screen" << endl;
// the blinking cursor.
stopBlinkingCursor();
- theLyXFunc().setLyXView(&lyx_view_);
+ theLyXFunc().setLyXView(lyx_view_);
theLyXFunc().processKeySym(key, state);
-
- /* When we move around, or type, it's nice to be able to see
- * the cursor immediately after the keypress.
- */
- startBlinkingCursor();
}
{
// Handle drag&drop
if (cmd0.action == LFUN_FILE_OPEN) {
- lyx_view_.dispatch(cmd0);
+ lyx_view_->dispatch(cmd0);
return;
}
- theLyXFunc().setLyXView(&lyx_view_);
+ theLyXFunc().setLyXView(lyx_view_);
FuncRequest cmd;
// Skip these when selecting
if (cmd.action != LFUN_MOUSE_MOTION) {
- lyx_view_.updateLayoutChoice();
- lyx_view_.updateMenubar();
- lyx_view_.updateToolbars();
+ lyx_view_->updateLayoutChoice();
+ lyx_view_->updateMenubar();
+ lyx_view_->updateToolbars();
}
// GUI tweaks except with mouse motion with no button pressed.
// Slight hack: this is only called currently when we
// clicked somewhere, so we force through the display
// of the new status here.
- lyx_view_.clearMessage();
+ lyx_view_->clearMessage();
// Show the cursor immediately after any operation.
startBlinkingCursor();
void WorkArea::resizeBufferView()
{
- lyx_view_.busy(true);
- lyx_view_.message(_("Formatting document..."));
+ lyx_view_->busy(true);
+ lyx_view_->message(_("Formatting document..."));
buffer_view_->workAreaResize(width(), height());
- lyx_view_.updateLayoutChoice();
- lyx_view_.clearMessage();
- lyx_view_.busy(false);
+ lyx_view_->updateLayoutChoice();
+ lyx_view_->clearMessage();
+ lyx_view_->busy(false);
}
redraw();
if (lyxrc.cursor_follows_scrollbar) {
buffer_view_->setCursorFromScrollbar();
- lyx_view_.updateLayoutChoice();
+ lyx_view_->updateLayoutChoice();
}
// Show the cursor immediately after any operation.
startBlinkingCursor();
if (cursor_visible_)
return;
- if (!buffer_view_->buffer())
- return;
-
CursorShape shape = BAR_SHAPE;
Text const & text = *buffer_view_->cursor().innerText();
void WorkArea::toggleCursor()
{
- if (buffer_view_->buffer()) {
-
- if (cursor_visible_)
- hideCursor();
- else
- showCursor();
+ if (cursor_visible_)
+ hideCursor();
+ else
+ showCursor();
- // Use this opportunity to deal with any child processes that
- // have finished but are waiting to communicate this fact
- // to the rest of LyX.
- ForkedcallsController & fcc = ForkedcallsController::get();
- fcc.handleCompletedProcesses();
- }
+ // Use this opportunity to deal with any child processes that
+ // have finished but are waiting to communicate this fact
+ // to the rest of LyX.
+ ForkedcallsController & fcc = ForkedcallsController::get();
+ fcc.handleCompletedProcesses();
cursor_timeout_.restart();
}
-
-void WorkArea::displayMessage(lyx::docstring const & message)
-{
- lyx_view_.message(message);
-}
-
} // namespace frontend
} // namespace lyx
#undef CursorShape
namespace lyx {
-
+class Buffer;
class BufferView;
class FuncRequest;
*/
class WorkArea : public boost::signals::trackable {
public:
- WorkArea(int id, LyXView & lyx_view);
-
- virtual ~WorkArea() {}
+ ///
+ WorkArea(Buffer & buffer, LyXView & lv);
- int const id() const { return id_; }
+ virtual ~WorkArea();
- void setBufferView(BufferView * buffer_view);
+ ///
+ void setLyXView(LyXView & lv) { lyx_view_ = &lv; }
///
BufferView & bufferView();
/// \return true if has the keyboard input focus.
virtual bool hasFocus() const = 0;
+ /// \return true if has this WorkArea is visible.
+ virtual bool isVisible() const = 0;
+
/// return the width of the work area in pixels
virtual int width() const = 0;
/// Process Key pressed event.
/// This needs to be public because it is accessed externally by GuiView.
void processKeySym(KeySymbolPtr key, key_modifier::state state);
+
protected:
/// cause the display of the given area of the work area
virtual void expose(int x, int y, int w, int h) = 0;
///
void dispatch(FuncRequest const & cmd0,
key_modifier::state = key_modifier::none);
+
+ /// close this work area.
+ /// Slot for Buffer::closing boost signal.
+ void close();
///
void resizeBufferView();
///
///
BufferView * buffer_view_;
-
- ///
- LyXView & lyx_view_;
///
- bool greyed_out_;
+ LyXView * lyx_view_;
private:
- ///
- int id_;
- ///
- void displayMessage(docstring const &);
- /// buffer messages signal connection
- boost::signals::connection message_connection_;
-
/// is the cursor currently displayed
bool cursor_visible_;
///
Timeout cursor_timeout_;
+
+ /// buffer changed signal connection
+ boost::signals::connection bufferChangedConnection_;
+ /// buffer closing signal connection
+ boost::signals::connection bufferClosingConnection_;
};
} // namespace frontend
#include <QFileOpenEvent>
#include <QLocale>
#include <QLibraryInfo>
+#include <QPixmapCache>
#include <QTextCodec>
#include <QTimer>
#include <QTranslator>
LoaderQueue::setPriority(10,100);
guiApp = this;
+
+ // Set the cache to 5120 kilobytes which corresponds to screen size of
+ // 1280 by 1024 pixels with a color depth of 32 bits.
+ QPixmapCache::setCacheLimit(5120);
}
#include <config.h>
-// This include must be declared before everything else because
-// of boost/Qt/LyX clash...
-#include "GuiView.h"
-
#include "GuiImplementation.h"
-#include "GuiWorkArea.h"
-#include "BufferView.h"
-#include "BufferList.h"
-#include "FuncRequest.h"
-#include "LyXFunc.h"
+#include "GuiView.h"
#include <QApplication>
-using boost::shared_ptr;
-
namespace
{
GuiImplementation::GuiImplementation()
{
view_ids_.clear();
- work_area_ids_.clear();
}
std::map<int, GuiView *>::iterator it;
for (it = views_.begin(); it != views_.end(); ++it) {
if (it->first == id) {
- std::vector<int> const & wa_ids = it->second->workAreaIds();
- for (size_t i = 0; i < wa_ids.size(); ++i)
- work_areas_.erase(wa_ids[i]);
views_.erase(id);
break;
}
}
views_.clear();
- work_areas_.clear();
view_ids_.clear();
- work_area_ids_.clear();
return true;
}
}
-std::vector<int> const & GuiImplementation::workAreaIds()
-{
- updateIds(work_areas_, work_area_ids_);
- return work_area_ids_;
-}
-
-
-int GuiImplementation::newWorkArea(unsigned int w, unsigned int h, int view_id)
-{
- updateIds(views_, view_ids_);
- int id = 0;
- while (work_areas_.find(id) != work_areas_.end())
- id++;
-
- GuiView * view = views_[view_id];
-
- work_areas_.insert(std::pair<int, GuiWorkArea *>
- (id, new GuiWorkArea(w, h, id, *view)));
-
- // FIXME BufferView creation should be independant of WorkArea creation
- buffer_views_[id].reset(new BufferView);
- work_areas_[id]->setBufferView(buffer_views_[id].get());
-
- view->setWorkArea(work_areas_[id]);
- view->initTab(work_areas_[id]);
-
- return id;
-}
-
-
-WorkArea& GuiImplementation::workArea(int id)
-{
- BOOST_ASSERT(work_areas_.find(id) != work_areas_.end());
- return *work_areas_[id];
-}
-
-
} // namespace frontend
} // namespace lyx
namespace lyx {
namespace frontend {
-class GuiWorkArea;
class GuiView;
class LyXView;
virtual LyXView& view(int id) const;
- virtual int newWorkArea(unsigned int width, unsigned int height, int view_id);
- virtual WorkArea& workArea(int id);
-
private:
/// Multiple views container.
* \sa Qt::WA_DeleteOnClose attribute.
*/
std::map<int, GuiView *> views_;
-
- /// Multiple workareas container.
- /**
- * Warning: This must not be a smart pointer as the destruction of the
- * object is handled by Qt when its parent view is closed.
- */
- std::map<int, GuiWorkArea *> work_areas_;
- ///
-
- /// view of a buffer. Eventually there will be several.
- std::map<int, boost::shared_ptr<BufferView> > buffer_views_;
-
-
- std::vector<int> const & workAreaIds();
-
- std::vector<int> work_area_ids_;
};
} // namespace frontend
#include "qt_helpers.h"
#include "frontends/Application.h"
+#include "frontends/Dialogs.h"
#include "frontends/Gui.h"
#include "frontends/WorkArea.h"
#include "LyXRC.h"
#include "MenuBackend.h"
#include "Session.h"
+#include "version.h"
#include <QAction>
#include <QApplication>
#include <QDesktopWidget>
#include <QDragEnterEvent>
#include <QDropEvent>
-#include <QHBoxLayout>
#include <QList>
#include <QMimeData>
+#include <QPainter>
#include <QPixmap>
#include <QPushButton>
+#include <QStackedWidget>
#include <QStatusBar>
#include <QToolBar>
-#include <QTabBar>
+#include <QTabWidget>
#include <QUrl>
-#include <QVBoxLayout>
-
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
int const statusbar_timer_value = 3000;
-class TabWidget : public QWidget
+class BackgroundWidget: public QWidget
{
- QHBoxLayout* hlayout;
public:
- QTabBar* tabbar;
- QPushButton* closeTabButton;
-
- void hideTabsIfNecessary()
+ BackgroundWidget(QString const & file, QString const & text)
{
- if (tabbar->count() > 1) {
- tabbar->show();
- closeTabButton->show();
- } else {
- tabbar->hide();
- closeTabButton->hide();
+ splash_ = new QPixmap(file);
+ if (!splash_) {
+ lyxerr << "could not load splash screen: '" << fromqstr(file) << "'" << endl;
+ return;
}
+
+ QPainter pain(splash_);
+ pain.setPen(QColor(255, 255, 0));
+ QFont font;
+ // The font used to display the version info
+ font.setStyleHint(QFont::SansSerif);
+ font.setWeight(QFont::Bold);
+ font.setPointSize(convert<int>(lyxrc.font_sizes[Font::SIZE_LARGE]));
+ pain.setFont(font);
+ pain.drawText(260, 270, text);
}
- TabWidget(QWidget* w, bool topTabBar)
+ void paintEvent(QPaintEvent * ev)
{
- closeTabButton = new QPushButton(this);
- FileName const file = support::libFileSearch("images", "closetab", "xpm");
- if (!file.empty()) {
- QPixmap pm(toqstr(file.absFilename()));
- closeTabButton->setIcon(QIcon(pm));
- closeTabButton->setMaximumSize(pm.size());
- closeTabButton->setFlat(true);
- } else {
- closeTabButton->setText("Close");
- }
- closeTabButton->setCursor(Qt::ArrowCursor);
- closeTabButton->setToolTip(tr("Close tab"));
- closeTabButton->setEnabled(true);
+ if (!splash_)
+ return;
- tabbar = new QTabBar;
-#if QT_VERSION >= 0x040200
- tabbar->setUsesScrollButtons(true);
-#endif
- hlayout = new QHBoxLayout;
- QVBoxLayout* vlayout = new QVBoxLayout;
- hlayout->addWidget(tabbar);
- hlayout->addWidget(closeTabButton);
- if (topTabBar) {
- vlayout->addLayout(hlayout);
- vlayout->addWidget(w);
- } else {
- tabbar->setShape(QTabBar::RoundedSouth);
- vlayout->addWidget(w);
- vlayout->addLayout(hlayout);
- }
- vlayout->setMargin(0);
- vlayout->setSpacing(0);
- hlayout->setMargin(0);
- setLayout(vlayout);
- hideTabsIfNecessary();
+ int x = (width() - splash_->width()) / 2;
+ int y = (height() - splash_->height()) / 2;
+ QPainter pain(this);
+ pain.drawPixmap(x, y, *splash_);
}
- void clearTabbar()
- {
- for (int i = tabbar->count() - 1; i >= 0; --i)
- tabbar->removeTab(i);
- }
+private:
+ QPixmap * splash_;
};
+
} // namespace anon
struct GuiView::GuiViewPrivate
{
- vector<string> tabnames;
string cur_title;
- TabWidget* tabWidget;
-
int posx_offset;
int posy_offset;
- GuiViewPrivate() : tabWidget(0), posx_offset(0), posy_offset(0)
+ QTabWidget * tab_widget_;
+ QStackedWidget * stack_widget_;
+ BackgroundWidget * bg_widget_;
+
+ GuiViewPrivate() : posx_offset(0), posy_offset(0)
{}
unsigned int smallIconSize;
return menu;
}
+
+ void initBackground()
+ {
+ bg_widget_ = 0;
+ LYXERR(Debug::GUI) << "show banner: " << lyxrc.show_banner << endl;
+ /// The text to be written on top of the pixmap
+ QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
+ FileName const file = support::libFileSearch("images", "banner", "png");
+ if (file.empty())
+ return;
+
+ bg_widget_ = new BackgroundWidget(toqstr(file.absFilename()), text);
+ }
+
+ void setBackground()
+ {
+ if (!bg_widget_)
+ return;
+
+ stack_widget_->setCurrentWidget(bg_widget_);
+ bg_widget_->setUpdatesEnabled(true);
+ }
};
setWindowIcon(QPixmap(toqstr(iconname.absFilename())));
#endif
+ d.tab_widget_ = new QTabWidget;
+
+ QPushButton * closeTabButton = new QPushButton(this);
+ FileName const file = support::libFileSearch("images", "closetab", "xpm");
+ if (!file.empty()) {
+ QPixmap pm(toqstr(file.absFilename()));
+ closeTabButton->setIcon(QIcon(pm));
+ closeTabButton->setMaximumSize(pm.size());
+ closeTabButton->setFlat(true);
+ } else {
+ closeTabButton->setText("Close");
+ }
+ closeTabButton->setCursor(Qt::ArrowCursor);
+ closeTabButton->setToolTip(tr("Close tab"));
+ closeTabButton->setEnabled(true);
+
+ QObject::connect(d.tab_widget_, SIGNAL(currentChanged(int)),
+ this, SLOT(currentTabChanged(int)));
+ QObject::connect(closeTabButton, SIGNAL(clicked()),
+ this, SLOT(closeCurrentTab()));
+
+ d.tab_widget_->setCornerWidget(closeTabButton);
+#if QT_VERSION >= 0x040200
+ d.tab_widget_->setUsesScrollButtons(true);
+#endif
+
+ d.initBackground();
+ if (d.bg_widget_) {
+ lyxerr << "stack widget!" << endl;
+ d.stack_widget_ = new QStackedWidget;
+ d.stack_widget_->addWidget(d.bg_widget_);
+ d.stack_widget_->addWidget(d.tab_widget_);
+ setCentralWidget(d.stack_widget_);
+ } else {
+ d.stack_widget_ = 0;
+ setCentralWidget(d.tab_widget_);
+ }
+
// For Drag&Drop.
setAcceptDrops(true);
}
void GuiView::setFocus()
{
- BOOST_ASSERT(work_area_);
- static_cast<GuiWorkArea *>(work_area_)->setFocus();
+ if (d.tab_widget_->count())
+ d.tab_widget_->currentWidget()->setFocus();
}
QObject::connect(&statusbar_timer_, SIGNAL(timeout()),
this, SLOT(update_view_state_qt()));
- BOOST_ASSERT(work_area_);
- if (!work_area_->bufferView().buffer() && !theBufferList().empty())
- setBuffer(theBufferList().first());
-
- // make sure the buttons are disabled if needed
- updateToolbars();
- updateLayoutChoice();
- updateMenubar();
+ if (d.stack_widget_)
+ d.stack_widget_->setCurrentWidget(d.bg_widget_);
}
quitting = true;
- if (view()->buffer()) {
- // save cursor position for opened files to .lyx/session
- // only bottom (whole doc) level pit and pos is saved.
- LyX::ref().session().lastFilePos().save(
- FileName(buffer()->fileName()),
- boost::tie(view()->cursor().bottom().pit(),
- view()->cursor().bottom().pos()));
- }
-
// this is the place where we leave the frontend.
// it is the only point at which we start quitting.
saveGeometry();
(void)geometryArg;
#endif
}
-
+
+ d.setBackground();
+
show();
// For an unknown reason, the Window title update is not effective for
}
-void GuiView::initTab(QWidget* workarea)
-{
- // construct the TabWidget with 'false' to have the tabbar at the bottom
- d.tabWidget = new TabWidget(workarea, true);
- setCentralWidget(d.tabWidget);
- QObject::connect(d.tabWidget->tabbar, SIGNAL(currentChanged(int)),
- this, SLOT(currentTabChanged(int)));
- QObject::connect(d.tabWidget->closeTabButton, SIGNAL(clicked()),
- this, SLOT(closeCurrentTab()));
-}
-
-
-void GuiView::updateTab()
-{
- std::vector<string> const & names = theBufferList().getFileNames();
-
- string cur_title;
- if (view()->buffer()) {
- cur_title = view()->buffer()->fileName();
- }
-
- // avoid unnecessary tabbar rebuild:
- // check if something has changed
- if (d.tabnames == names && d.cur_title == cur_title)
- return;
- d.tabnames = names;
- d.cur_title = cur_title;
-
- QTabBar & tabbar = *d.tabWidget->tabbar;
-
- // update when all is done
- tabbar.blockSignals(true);
-
- // remove all tab bars
- d.tabWidget->clearTabbar();
-
- // rebuild tabbar and function map from scratch
- if (names.size() > 1) {
- for(size_t i = 0; i < names.size(); i++) {
- tabbar.addTab(toqstr(makeDisplayPath(names[i], 30)));
- // set current tab
- if (names[i] == cur_title)
- tabbar.setCurrentIndex(i);
- }
- }
- tabbar.blockSignals(false);
- d.tabWidget->hideTabsIfNecessary();
-}
-
-
void GuiView::closeCurrentTab()
{
dispatch(FuncRequest(LFUN_BUFFER_CLOSE));
void GuiView::currentTabChanged(int i)
{
- BOOST_ASSERT(i >= 0 && size_type(i) < d.tabnames.size());
- dispatch(FuncRequest(LFUN_BUFFER_SWITCH, d.tabnames[i]));
+ disconnectBuffer();
+ disconnectBufferView();
+ GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(d.tab_widget_->widget(i));
+ BOOST_ASSERT(wa);
+ BufferView & bv = wa->bufferView();
+ connectBufferView(bv);
+ connectBuffer(*bv.buffer());
+ bv.updateMetrics(false);
+ bv.cursor().fixIfBroken();
+ wa->setUpdatesEnabled(true);
+ wa->redraw();
+ wa->setFocus();
+
+ updateToc();
+ // Buffer-dependent dialogs should be updated or
+ // hidden. This should go here because some dialogs (eg ToC)
+ // require bv_->text.
+ getDialogs().updateBufferDependent(true);
+ updateMenubar();
+ updateToolbars();
+ updateLayoutChoice();
+ updateWindowTitle();
+ updateStatusBar();
+
+ lyxerr << "currentTabChanged " << i
+ << "File" << wa->bufferView().buffer()->fileName() << endl;
}
case QEvent::ShortcutOverride: {
QKeyEvent * ke = static_cast<QKeyEvent*>(e);
+ if (d.tab_widget_->count() == 0) {
+ theLyXFunc().setLyXView(this);
+ boost::shared_ptr<QKeySymbol> sym(new QKeySymbol);
+ sym->set(ke);
+ theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
+ e->accept();
+ return true;
+ }
if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
boost::shared_ptr<QKeySymbol> sym(new QKeySymbol);
sym->set(ke);
- BOOST_ASSERT(work_area_);
- work_area_->processKeySym(sym, key_modifier::none);
+ currentWorkArea()->processKeySym(sym, key_modifier::none);
e->accept();
return true;
}
void GuiView::busy(bool yes)
{
- BOOST_ASSERT(work_area_);
- static_cast<GuiWorkArea *>(work_area_)->setUpdatesEnabled(!yes);
+ if (d.tab_widget_->count()) {
+ GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(d.tab_widget_->currentWidget());
+ BOOST_ASSERT(wa);
+ wa->setUpdatesEnabled(!yes);
+ if (yes)
+ wa->stopBlinkingCursor();
+ else
+ wa->startBlinkingCursor();
+ }
- if (yes) {
- work_area_->stopBlinkingCursor();
+ if (yes)
QApplication::setOverrideCursor(Qt::WaitCursor);
- }
- else {
- work_area_->startBlinkingCursor();
+ else
QApplication::restoreOverrideCursor();
- }
}
return Toolbars::ToolbarPtr(Tb);
}
+
+WorkArea * GuiView::workArea(Buffer & buffer)
+{
+ for (int i = 0; i != d.tab_widget_->count(); ++i) {
+ GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(d.tab_widget_->widget(i));
+ BOOST_ASSERT(wa);
+ if (wa->bufferView().buffer() == &buffer)
+ return wa;
+ }
+ return 0;
+}
+
+
+WorkArea * GuiView::addWorkArea(Buffer & buffer)
+{
+ GuiWorkArea * wa = new GuiWorkArea(buffer, *this);
+ d.tab_widget_->addTab(wa, toqstr(makeDisplayPath(buffer.fileName(), 30)));
+ wa->bufferView().updateMetrics(false);
+ if (d.stack_widget_)
+ d.stack_widget_->setCurrentWidget(d.tab_widget_);
+ return wa;
+}
+
+
+WorkArea * GuiView::currentWorkArea()
+{
+ if (d.tab_widget_->count() == 0)
+ return 0;
+ BOOST_ASSERT(dynamic_cast<GuiWorkArea *>(d.tab_widget_->currentWidget()));
+ return dynamic_cast<GuiWorkArea *>(d.tab_widget_->currentWidget());
+}
+
+
+WorkArea const * GuiView::currentWorkArea() const
+{
+ if (d.tab_widget_->count() == 0)
+ return 0;
+ BOOST_ASSERT(dynamic_cast<GuiWorkArea const *>(d.tab_widget_->currentWidget()));
+ return dynamic_cast<GuiWorkArea const *>(d.tab_widget_->currentWidget());
+}
+
+
+void GuiView::setCurrentWorkArea(WorkArea * work_area)
+{
+ BOOST_ASSERT(work_area);
+
+ // Changing work area can result from opening a file so
+ // update the toc in any case.
+ updateToc();
+
+ GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(work_area);
+ BOOST_ASSERT(wa);
+ d.tab_widget_->setCurrentWidget(wa);
+ wa->setFocus();
+}
+
+
+void GuiView::removeWorkArea(WorkArea * work_area)
+{
+ BOOST_ASSERT(work_area);
+ if (work_area == currentWorkArea()) {
+ disconnectBuffer();
+ disconnectBufferView();
+ }
+
+ // removing a work area often results from closing a file so
+ // update the toc in any case.
+ updateToc();
+
+ GuiWorkArea * gwa = dynamic_cast<GuiWorkArea *>(work_area);
+ BOOST_ASSERT(gwa);
+ int index = d.tab_widget_->indexOf(gwa);
+ d.tab_widget_->removeTab(index);
+
+ delete gwa;
+
+ if (d.tab_widget_->count()) {
+ // make sure the next work area is enabled.
+ d.tab_widget_->currentWidget()->setUpdatesEnabled(true);
+ return;
+ }
+
+ getDialogs().hideBufferDependent();
+ if (d.stack_widget_) {
+ // No more work area, switch to the background widget.
+ d.setBackground();
+ }
+}
+
+
} // namespace frontend
} // namespace lyx
virtual void clearMessage();
virtual bool hasFocus() const;
- virtual void updateTab();
-
/// show - display the top-level window
void show();
/// menu item has been selected
void activated(FuncRequest const &);
- void initTab(QWidget* workArea);
-
QMenu* createPopupMenu();
Q_SIGNALS:
///
virtual void moveEvent(QMoveEvent * e);
+ /// \return the \c Workarea associated to \p Buffer
+ /// \retval 0 if no \c WorkArea is found.
+ WorkArea * workArea(Buffer & buffer);
+
+ /// Add a \c WorkArea
+ /// \return the \c Workarea associated to \p Buffer
+ /// \retval 0 if no \c WorkArea is found.
+ WorkArea * addWorkArea(Buffer & buffer);
+ void setCurrentWorkArea(WorkArea * work_area);
+ void removeWorkArea(WorkArea * work_area);
+ WorkArea const * currentWorkArea() const;
+ WorkArea * currentWorkArea();
+
private:
///
void dragEnterEvent(QDragEnterEvent * ev);
{}
-GuiWorkArea::GuiWorkArea(int w, int h, int id, LyXView & lyx_view)
- : WorkArea(id, lyx_view), need_resize_(false), schedule_redraw_(false),
+GuiWorkArea::GuiWorkArea(Buffer & buf, LyXView & lv)
+ : WorkArea(buf, lv), need_resize_(false), schedule_redraw_(false),
preedit_lines_(1)
{
screen_ = QPixmap(viewport()->width(), viewport()->height());
viewport()->setCursor(Qt::IBeamCursor);
- resize(w, h);
-
synthetic_mouse_event_.timeout.timeout.connect(
boost::bind(&GuiWorkArea::generateSyntheticMouseEvent,
this));
// if (theApp() == 0 || &lyx_view_ == theApp()->currentView())
// return;
- theApp()->setCurrentView(lyx_view_);
+ theApp()->setCurrentView(*lyx_view_);
// Repaint the whole screen.
// Note: this is different from redraw() as only the backing pixmap
// will be redrawn, which is cheap.
viewport()->repaint();
- // FIXME: it would be better to send a signal "newBuffer()"
- // in BufferList that could be connected to the different tabbars.
- lyx_view_.updateTab();
-
startBlinkingCursor();
}
}
-void GuiWorkArea::doGreyOut(QLPainter & pain)
-{
- pain.fillRectangle(0, 0, width(), height(),
- Color::bottomarea);
-
- //if (!lyxrc.show_banner)
- // return;
- LYXERR(Debug::GUI) << "show banner: " << lyxrc.show_banner << endl;
- /// The text to be written on top of the pixmap
- QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
- FileName const file = support::libFileSearch("images", "banner", "png");
- if (file.empty())
- return;
-
- QPixmap pm(toqstr(file.absFilename()));
- if (!pm) {
- lyxerr << "could not load splash screen: '" << file << "'" << endl;
- return;
- }
-
- QFont font;
- // The font used to display the version info
- font.setStyleHint(QFont::SansSerif);
- font.setWeight(QFont::Bold);
- font.setPointSize(convert<int>(lyxrc.font_sizes[Font::SIZE_LARGE]));
-
- int const w = pm.width();
- int const h = pm.height();
-
- int x = (width() - w) / 2;
- int y = (height() - h) / 2;
-
- pain.drawPixmap(x, y, pm);
-
- x += 260;
- y += 270;
-
- pain.setPen(QColor(255, 255, 0));
- pain.setFont(font);
- pain.drawText(x, y, text);
-}
-
-
void GuiWorkArea::paintEvent(QPaintEvent * ev)
{
QRect const rc = ev->rect();
void GuiWorkArea::updateScreen()
{
QLPainter pain(&screen_);
-
- if (greyed_out_) {
- LYXERR(Debug::GUI) << "splash screen requested" << endl;
- verticalScrollBar()->hide();
- doGreyOut(pain);
- return;
- }
-
verticalScrollBar()->show();
paintText(*buffer_view_, pain);
}
void GuiWorkArea::showCursor(int x, int y, int h, CursorShape shape)
{
if (schedule_redraw_) {
- if (buffer_view_ && buffer_view_->buffer()) {
- buffer_view_->update(Update::Force);
- updateScreen();
- viewport()->update(QRect(0, 0, viewport()->width(), viewport()->height()));
- }
+ buffer_view_->update(Update::Force);
+ updateScreen();
+ viewport()->update(QRect(0, 0, viewport()->width(), viewport()->height()));
schedule_redraw_ = false;
// Show the cursor immediately after the update.
hideCursor();
docstring const & preedit_string
= qstring_to_ucs4(e->preeditString());
- if(greyed_out_) {
- e->ignore();
- return;
- }
-
if (!commit_string.isEmpty()) {
LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
public:
///
- GuiWorkArea(int width, int height, int id, LyXView & lyx_view);
+ GuiWorkArea(Buffer & buffer, LyXView & lv);
///
bool hasFocus() const { return QAbstractScrollArea::hasFocus(); }
+ bool isVisible() const { return QAbstractScrollArea::isVisible(); }
/// return the width of the content pane
virtual int width() const { return viewport()->width(); }
} // namespace anon
-
-Buffer * loadIfNeeded(Buffer const & buffer, InsetCommandParams const & params)
+/// return true if the file is or got loaded.
+Buffer * loadIfNeeded(Buffer const & parent, InsetCommandParams const & params)
{
if (isVerbatim(params) || isListings(params))
return 0;
- FileName const included_file = includedFilename(buffer, params);
+ string const parent_filename = parent.fileName();
+ FileName const included_file = makeAbsPath(to_utf8(params["filename"]),
+ onlyPath(parent_filename));
+
if (!isLyXFilename(included_file.absFilename()))
return 0;
- Buffer * buf = theBufferList().getBuffer(included_file.absFilename());
- if (!buf) {
+ Buffer * child = theBufferList().getBuffer(included_file.absFilename());
+ if (!child) {
// the readonly flag can/will be wrong, not anymore I think.
if (!fs::exists(included_file.toFilesystemEncoding()))
- return false;
- if (use_gui) {
- lyx::dispatch(FuncRequest(LFUN_BUFFER_CHILD_OPEN,
- included_file.absFilename() + "|true"));
- buf = theBufferList().getBuffer(included_file.absFilename());
- }
- else {
- buf = theBufferList().newBuffer(included_file.absFilename());
- if (!loadLyXFile(buf, included_file)) {
- //close the buffer we just opened
- theBufferList().close(buf, false);
- return false;
- }
+ return 0;
+
+ child = theBufferList().newBuffer(included_file.absFilename());
+ if (!loadLyXFile(child, included_file)) {
+ //close the buffer we just opened
+ theBufferList().close(child, false);
+ return 0;
}
}
- buf->setParentName(parentFilename(buffer));
- return buf;
+ child->setParentName(parent_filename);
+ return child;
}
bool InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const
{
- BOOST_ASSERT(mi.base.bv && mi.base.bv->buffer());
+ BOOST_ASSERT(mi.base.bv);
bool use_preview = false;
if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {
{
setPosCache(pi, x, y);
- BOOST_ASSERT(pi.base.bv && pi.base.bv->buffer());
+ BOOST_ASSERT(pi.base.bv);
bool use_preview = false;
if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {