Fix Undocked Outliner & multiple window crashes (#11004).

There are more independent crashes occuring in this scenario and this
fix targets only one of them, in particular the one in which different
window's outliner sends outliner command to a wrong window. The fix
itself gives an option for lfun to know which window it belongs to.

https://www.mail-archive.com/lyx-devel@lists.lyx.org/msg203619.html
This commit is contained in:
Pavel Sanda 2018-03-12 14:34:24 +01:00
parent e41c80e224
commit 8725614e3f
7 changed files with 56 additions and 16 deletions

View File

@ -31,38 +31,39 @@ FuncRequest const FuncRequest::noaction(LFUN_NOACTION);
FuncRequest::FuncRequest(Origin o) FuncRequest::FuncRequest(Origin o)
: action_(LFUN_NOACTION), origin_(o), x_(0), y_(0), : action_(LFUN_NOACTION), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier) button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{} {}
FuncRequest::FuncRequest(FuncCode act, Origin o) FuncRequest::FuncRequest(FuncCode act, Origin o)
: action_(act), origin_(o), x_(0), y_(0), : action_(act), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier) button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{} {}
FuncRequest::FuncRequest(FuncCode act, docstring const & arg, Origin o) FuncRequest::FuncRequest(FuncCode act, docstring const & arg, Origin o)
: action_(act), argument_(arg), origin_(o), x_(0), y_(0), : action_(act), argument_(arg), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier) button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{} {}
FuncRequest::FuncRequest(FuncCode act, string const & arg, Origin o) FuncRequest::FuncRequest(FuncCode act, string const & arg, Origin o)
: action_(act), argument_(from_utf8(arg)), origin_(o), x_(0), y_(0), : action_(act), argument_(from_utf8(arg)), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier) button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{} {}
FuncRequest::FuncRequest(FuncCode act, int ax, int ay, FuncRequest::FuncRequest(FuncCode act, int ax, int ay,
mouse_button::state but, KeyModifier modifier, Origin o) mouse_button::state but, KeyModifier modifier, Origin o)
: action_(act), origin_(o), x_(ax), y_(ay), button_(but), : action_(act), origin_(o), x_(ax), y_(ay), button_(but),
modifier_(modifier) modifier_(modifier), view_origin_(0)
{} {}
FuncRequest::FuncRequest(FuncRequest const & cmd, docstring const & arg, Origin o) FuncRequest::FuncRequest(FuncRequest const & cmd, docstring const & arg, Origin o)
: action_(cmd.action()), argument_(arg), origin_(o), : action_(cmd.action()), argument_(arg), origin_(o),
x_(cmd.x_), y_(cmd.y_), button_(cmd.button_), modifier_(NoModifier) x_(cmd.x_), y_(cmd.y_), button_(cmd.button_), modifier_(NoModifier),
view_origin_(0)
{} {}

View File

@ -24,6 +24,10 @@ namespace lyx {
class LyXErr; class LyXErr;
namespace frontend {
class GuiView;
}
/** /**
* This class encapsulates a LyX action and its argument * This class encapsulates a LyX action and its argument
* in order to pass it around easily. * in order to pass it around easily.
@ -70,6 +74,10 @@ public:
/// ///
void setOrigin(Origin o) { origin_ = o; } void setOrigin(Origin o) { origin_ = o; }
/// ///
frontend::GuiView* view_origin() const { return view_origin_; }
///
void setViewOrigin(frontend::GuiView* o) { view_origin_ = o; }
///
int x() const { return x_; } int x() const { return x_; }
/// ///
int y() const { return y_; } int y() const { return y_; }
@ -97,6 +105,9 @@ private:
docstring argument_; docstring argument_;
/// who initiated the action /// who initiated the action
Origin origin_; Origin origin_;
/// to which view should be this command sent (see bug #11004)
/// NULL=current view
frontend::GuiView* view_origin_;
/// the x coordinate of a mouse press /// the x coordinate of a mouse press
int x_; int x_;
/// the y coordinate of a mouse press /// the y coordinate of a mouse press

View File

@ -1387,7 +1387,16 @@ static docstring makeDispatchMessage(docstring const & msg,
DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd) DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd)
{ {
DispatchResult dr;
Buffer * buffer = 0; Buffer * buffer = 0;
if (cmd.view_origin() && current_view_ != cmd.view_origin()) {
//setCurrentView(cmd.view_origin); //does not work
dr.setError(true);
dr.setMessage(_("Wrong focus!"));
d->dispatch_result_ = dr;
return d->dispatch_result_;
}
if (current_view_ && current_view_->currentBufferView()) { if (current_view_ && current_view_->currentBufferView()) {
current_view_->currentBufferView()->cursor().saveBeforeDispatchPosXY(); current_view_->currentBufferView()->cursor().saveBeforeDispatchPosXY();
buffer = &current_view_->currentBufferView()->buffer(); buffer = &current_view_->currentBufferView()->buffer();
@ -1395,7 +1404,6 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd)
// This handles undo groups automagically // This handles undo groups automagically
UndoGroupHelper ugh(buffer); UndoGroupHelper ugh(buffer);
DispatchResult dr;
// redraw the screen at the end (first of the two drawing steps). // redraw the screen at the end (first of the two drawing steps).
// This is done unless explicitly requested otherwise // This is done unless explicitly requested otherwise
dr.screenUpdate(Update::FitCursor); dr.screenUpdate(Update::FitCursor);

View File

@ -303,17 +303,17 @@ QModelIndex TocModels::currentIndex(QString const & type,
} }
void TocModels::goTo(QString const & type, QModelIndex const & index) const FuncRequest TocModels::goTo(QString const & type, QModelIndex const & index) const
{ {
const_iterator it = models_.find(type); const_iterator it = models_.find(type);
if (it == models_.end() || !index.isValid()) { if (it == models_.end() || !index.isValid()) {
LYXERR(Debug::GUI, "TocModels::goTo(): QModelIndex is invalid!"); LYXERR(Debug::GUI, "TocModels::goTo(): QModelIndex is invalid!");
return; return FuncRequest(LFUN_NOACTION);
} }
LASSERT(index.model() == it.value()->model(), return); LASSERT(index.model() == it.value()->model(), return FuncRequest(LFUN_NOACTION));
TocItem const item = it.value()->tocItem(index); TocItem const item = it.value()->tocItem(index);
LYXERR(Debug::GUI, "TocModels::goTo " << item.asString()); LYXERR(Debug::GUI, "TocModels::goTo " << item.asString());
dispatch(item.action()); return item.action();
} }

View File

@ -22,6 +22,7 @@ namespace lyx {
class Buffer; class Buffer;
class BufferView; class BufferView;
class DocIterator; class DocIterator;
class FuncRequest;
namespace frontend { namespace frontend {
@ -124,9 +125,7 @@ public:
QModelIndex currentIndex(QString const & type, QModelIndex currentIndex(QString const & type,
DocIterator const & dit) const; DocIterator const & dit) const;
/// ///
void goTo(QString const & type, QModelIndex const & index) const; FuncRequest goTo(QString const & type, QModelIndex const & index) const;
///
void init(Buffer const & buffer);
/// ///
void updateItem(QString const & type, DocIterator const & dit); void updateItem(QString const & type, DocIterator const & dit);
/// ///

View File

@ -178,6 +178,7 @@ bool TocWidget::getStatus(Cursor & cur, FuncRequest const & cmd,
void TocWidget::doDispatch(Cursor & cur, FuncRequest const & cmd) void TocWidget::doDispatch(Cursor & cur, FuncRequest const & cmd)
{ {
Inset * inset = itemInset(); Inset * inset = itemInset();
FuncRequest tmpcmd(cmd); FuncRequest tmpcmd(cmd);
@ -235,6 +236,7 @@ void TocWidget::on_tocTV_activated(QModelIndex const & index)
void TocWidget::on_tocTV_pressed(QModelIndex const & index) void TocWidget::on_tocTV_pressed(QModelIndex const & index)
{ {
Qt::MouseButtons const button = QApplication::mouseButtons(); Qt::MouseButtons const button = QApplication::mouseButtons();
if (button & Qt::LeftButton) { if (button & Qt::LeftButton) {
goTo(index); goTo(index);
@ -249,7 +251,7 @@ void TocWidget::goTo(QModelIndex const & index)
LYXERR(Debug::GUI, "goto " << index.row() LYXERR(Debug::GUI, "goto " << index.row()
<< ", " << index.column()); << ", " << index.column());
gui_view_.tocModels().goTo(current_type_, index); sendDispatch(gui_view_.tocModels().goTo(current_type_, index));
} }
@ -314,6 +316,7 @@ void TocWidget::setTreeDepth(int depth)
void TocWidget::on_typeCO_currentIndexChanged(int index) void TocWidget::on_typeCO_currentIndexChanged(int index)
{ {
if (index == -1) if (index == -1)
return; return;
current_type_ = typeCO->itemData(index).toString(); current_type_ = typeCO->itemData(index).toString();
@ -328,14 +331,29 @@ void TocWidget::outline(FuncCode func_code)
QModelIndexList const & list = tocTV->selectionModel()->selectedIndexes(); QModelIndexList const & list = tocTV->selectionModel()->selectedIndexes();
if (list.isEmpty()) if (list.isEmpty())
return; return;
//if another window is active, this attempt will fail,
//but it will work at least for the second attempt
gui_view_.activateWindow();
enableControls(false); enableControls(false);
goTo(list[0]); goTo(list[0]);
dispatch(FuncRequest(func_code)); sendDispatch(FuncRequest(func_code));
enableControls(true); enableControls(true);
gui_view_.setFocus(); gui_view_.setFocus();
} }
void TocWidget::sendDispatch(FuncRequest fr)
{
fr.setViewOrigin(&gui_view_);
DispatchResult dr=dispatch(fr);
if (dr.error())
gui_view_.message(dr.message());
}
void TocWidget::on_moveUpTB_clicked() void TocWidget::on_moveUpTB_clicked()
{ {
outline(LFUN_OUTLINE_UP); outline(LFUN_OUTLINE_UP);

View File

@ -40,6 +40,9 @@ public:
void init(QString const & str); void init(QString const & str);
/// ///
void doDispatch(Cursor & cur, FuncRequest const & fr); void doDispatch(Cursor & cur, FuncRequest const & fr);
///send request to lyx::dispatch with proper guiview handle
///(if ToC is detached current_view can be different window)
void sendDispatch(FuncRequest fr);
/// ///
bool getStatus(Cursor & cur, FuncRequest const & fr, FuncStatus & status) bool getStatus(Cursor & cur, FuncRequest const & fr, FuncStatus & status)
const; const;