#include "insets/insetexternal.h"
#include "insets/insetfloat.h"
#include "insets/insetgraphics.h"
+#include "insets/insetinclude.h"
#include "insets/insetnote.h"
#include "insets/insettabular.h"
#include "insets/insetvspace.h"
#include "support/convert.h"
#include "support/os.h"
+#include <boost/current_function.hpp>
#include <boost/filesystem/operations.hpp>
#include <sstream>
bool getStatus(LCursor cursor,
FuncRequest const & cmd, FuncStatus & status)
{
+ // Try to fix cursor in case it is broken.
+ cursor.fixIfBroken();
+
// This is, of course, a mess. Better create a new doc iterator and use
// this in Inset::getStatus. This might require an additional
// BufferView * arg, though (which should be avoided)
bool res = false;
for ( ; cursor.depth(); cursor.pop()) {
//lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
- DocIterator::idx_type & idx = cursor.idx();
- DocIterator::idx_type const lastidx = cursor.lastidx();
-
- if (idx > lastidx) {
- lyxerr << "wrong idx " << idx << ", max is " << lastidx
- << ". Trying to correct this." << endl;
- idx = lastidx;
- }
-
- DocIterator::pit_type & pit = cursor.pit();
- DocIterator::pit_type const lastpit = cursor.lastpit();
-
- if (pit > lastpit) {
- lyxerr << "wrong par " << pit << ", max is " << lastpit
- << ". Trying to correct this." << endl;
- pit = lastpit;
- }
-
- DocIterator::pos_type & pos = cursor.pos();
- DocIterator::pos_type const lastpos = cursor.lastpos();
-
- if (pos > lastpos) {
- lyxerr << "wrong pos " << pos << ", max is " << lastpos
- << ". Trying to correct this." << endl;
- pos = lastpos;
- }
+ BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
+ BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
+ BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
// The inset's getStatus() will return 'true' if it made
// a definitive decision on whether it want to handle the
return res;
}
+
+/** Return the change status at cursor position, taking in account the
+ * status at each level of the document iterator (a table in a deleted
+ * footnote is deleted).
+ * When \param outer is true, the top slice is not looked at.
+ */
+Change::Type lookupChange(DocIterator const & dit, bool outer = false)
+{
+ size_t const depth = dit.depth() - (outer ? 1 : 0);
+
+ for (size_t i = 0 ; i < depth ; ++i) {
+ CursorSlice const & slice = dit[i];
+ if (!slice.inset().inMathed()
+ && slice.pos() < slice.paragraph().size()) {
+ Change::Type const ch = slice.paragraph().lookupChange(slice.pos());
+ if (ch != Change::UNCHANGED)
+ return ch;
+ }
+ }
+ return Change::UNCHANGED;
+}
+
}
LyXFunc::LyXFunc(LyXView * lv)
application can still be accessed without giving focus to
the main window. In this case, we want to disable the menu
entries that are buffer-related.
+
+ Note that this code is not perfect, as bug 1941 attests:
+ http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
*/
Buffer * buf;
if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
enable = false;
if (!cur)
break;
- UpdatableInset * inset = cur.inset().asUpdatableInset();
- lyxerr << "inset: " << inset << endl;
- if (!inset)
- break;
-
- InsetBase::Code code = inset->lyxCode();
+ InsetBase::Code code = cur.inset().lyxCode();
switch (code) {
case InsetBase::TABULAR_CODE:
enable = cmd.argument == "tabular";
break;
}
+ case LFUN_INSET_APPLY: {
+ string const name = cmd.getArg(0);
+ InsetBase * inset = owner->getDialogs().getOpenInset(name);
+ if (inset) {
+ FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
+ FuncStatus fs;
+ bool const success = inset->getStatus(cur, fr, fs);
+ // Every inset is supposed to handle this
+ BOOST_ASSERT(success);
+ flag |= fs;
+ } else {
+ FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
+ flag |= getStatus(fr);
+ }
+ enable = flag.enabled();
+ break;
+ }
+
case LFUN_DIALOG_SHOW: {
string const name = cmd.getArg(0);
if (!buf)
&& lyxrc.print_command != "none";
else if (name == "character" || name == "mathpanel")
enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
- else if (name == "vclog")
- enable = buf->lyxvc().inUse();
else if (name == "latexlog")
enable = IsFileReadable(buf->getLogName().second);
+#if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
+ else if (name == "spellchecker")
+ enable = false;
+#endif
+ else if (name == "vclog")
+ enable = buf->lyxvc().inUse();
break;
}
break;
}
+ case LFUN_INSERT_CITATION: {
+ FuncRequest fr(LFUN_INSET_INSERT, "citation");
+ enable = getStatus(fr).enabled();
+ break;
+ }
+
// this one is difficult to get right. As a half-baked
// solution, we consider only the first action of the sequence
case LFUN_SEQUENCE: {
flag.enabled(false);
}
+ // Are we in a DELETED change-tracking region?
+ if (buf && buf->params().tracking_changes
+ && lookupChange(cur, true) == Change::DELETED
+ && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
+ && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
+ flag.message(N_("This portion of the document is deleted."));
+ flag.enabled(false);
+ }
+
// the default error message if we disable the command
if (!flag.enabled() && flag.message().empty())
flag.message(N_("Command disabled"));
break;
case LFUN_QUIT:
- QuitLyX();
+ QuitLyX(argument == "force");
break;
case LFUN_TOCVIEW: {
string data = trim(cmd.argument.substr(name.size()));
if (name == "bibitem" ||
name == "bibtex" ||
- name == "include" ||
name == "index" ||
name == "label" ||
name == "ref" ||
name == "url") {
InsetCommandParams p(name);
data = InsetCommandMailer::params2string(name, p);
+ } else if (name == "include") {
+ InsetCommandParams p(data);
+ data = InsetIncludeMailer::params2string(p);
} else if (name == "box") {
// \c data == "Boxed" || "Frameless" etc
InsetBoxParams p(data);
owner->getDialogs().disconnect(argument);
break;
+
+ case LFUN_INSERT_CITATION: {
+ if (!argument.empty()) {
+ // we can have one optional argument, delimited by '|'
+ // citation-insert <key>|<text_before>
+ // this should be enhanced to also support text_after
+ // and citation style
+ string arg = argument;
+ string opt1;
+ if (contains(argument, "|")) {
+ arg = token(argument, '|', 0);
+ opt1 = '[' + token(argument, '|', 1) + ']';
+ }
+ std::ostringstream os;
+ os << "citation LatexCommand\n"
+ << "\\cite" << opt1 << "{" << arg << "}\n"
+ << "\\end_inset";
+ FuncRequest fr(LFUN_INSET_INSERT, os.str());
+ dispatch(fr);
+ } else
+ dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
+ break;
+ }
+
case LFUN_CHILDOPEN: {
string const filename =
MakeAbsPath(argument, owner->buffer()->filePath());
break;
}
+ case LFUN_INSET_APPLY: {
+ string const name = cmd.getArg(0);
+ InsetBase * inset = owner->getDialogs().getOpenInset(name);
+ if (inset) {
+ FuncRequest fr(LFUN_INSET_MODIFY, argument);
+ inset->dispatch(view()->cursor(), fr);
+ } else {
+ FuncRequest fr(LFUN_INSET_INSERT, argument);
+ dispatch(fr);
+ }
+ // ideally, the update flag should be set by the insets,
+ // but this is not possible currently
+ update = true;
+ break;
+ }
+
case LFUN_ALL_INSETS_TOGGLE: {
string action;
string const name = split(argument, action, ' ');
InsetIterator const end = inset_iterator_end(inset);
for (; it != end; ++it) {
if (inset_code == InsetBase::NO_CODE
- || inset_code == it->lyxCode())
- it->dispatch(cur, fr);
+ || inset_code == it->lyxCode()) {
+ LCursor tmpcur = cur;
+ tmpcur.pushLeft(*it);
+ it->dispatch(tmpcur, fr);
+ }
}
+ update = true;
break;
}
break;
owner->message(_("Converting document to new document class..."));
+ recordUndoFullDocument(view());
+ buffer->params().textclass = new_class;
+ StableDocIterator backcur(view()->cursor());
ErrorList el;
- lyx::cap::SwitchLayoutsBetweenClasses(
+ lyx::cap::SwitchBetweenClasses(
old_class, new_class,
buffer->paragraphs(), el);
+ view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
bufferErrors(*buffer, el);
view()->showErrorList(_("Class switch"));
+ updateCounters(*buffer);
+ update = true;
break;
}
default: {
view()->cursor().dispatch(cmd);
update |= view()->cursor().result().update();
- if (!view()->cursor().result().dispatched()) {
+ if (!view()->cursor().result().dispatched())
update |= view()->dispatch(cmd);
- }
-
break;
}
}
// Redraw screen unless explicitly told otherwise.
// This also initializes the position cache for all insets
// in (at least partially) visible top-level paragraphs.
- view()->update(true, update);
+ if (update)
+ view()->update(Update::FitCursor | Update::Force);
+ else
+ view()->update(Update::FitCursor);
// if we executed a mutating lfun, mark the buffer as dirty
+ // FIXME: Why not use flag.enabled() but call getStatus again?
if (getStatus(cmd).enabled()
&& !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
&& !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
view()->owner()->updateLayoutChoice();
}
}
- sendDispatchMessage(getMessage(), cmd);
+ sendDispatchMessage(_(getMessage()), cmd);
}
void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
{
- owner->updateMenubar();
- owner->updateToolbars();
+ /* When an action did not originate from the UI/kbd, it makes
+ * sense to avoid updating the GUI. It turns out that this
+ * fixes bug 1941, for reasons that are described here:
+ * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
+ */
+ if (cmd.origin != FuncRequest::INTERNAL) {
+ owner->updateMenubar();
+ owner->updateToolbars();
+ }
const bool verbose = (cmd.origin == FuncRequest::UI
|| cmd.origin == FuncRequest::COMMANDBUFFER);
string const shortcuts = toplevel_keymap->printbindings(cmd);
- if (!shortcuts.empty()) {
+ if (!shortcuts.empty())
comname += ": " + shortcuts;
- } else if (!argsadded && !cmd.argument.empty()) {
+ else if (!argsadded && !cmd.argument.empty())
comname += ' ' + cmd.argument;
- }
if (!comname.empty()) {
comname = rtrim(comname);
- dispatch_msg += '(' + comname + ')';
+ dispatch_msg += '(' + rtrim(comname) + ')';
}
lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
case LyXRC::RC_SPELL_COMMAND:
case LyXRC::RC_TEMPDIRPATH:
case LyXRC::RC_TEMPLATEPATH:
+ case LyXRC::RC_TEX_ALLOWS_SPACES:
case LyXRC::RC_UIFILE:
case LyXRC::RC_USER_EMAIL:
case LyXRC::RC_USER_NAME: