X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLyXFunc.cpp;h=92e83f05cfb511a7ed8de21ebf6518c75cd31eae;hb=4c1144c1876776f52db68283ec9283f93911894a;hp=27f558a5fbb4cfff95810d829d61f6356ced4813;hpb=608603a31d6ae4e3d08ae4e9c18a11d9e705dcf4;p=lyx.git diff --git a/src/LyXFunc.cpp b/src/LyXFunc.cpp index 27f558a5fb..92e83f05cf 100644 --- a/src/LyXFunc.cpp +++ b/src/LyXFunc.cpp @@ -85,7 +85,9 @@ #include "frontends/KeySymbol.h" #include "frontends/LyXView.h" #include "frontends/Menubar.h" +#include "frontends/Selection.h" #include "frontends/Toolbars.h" +#include "frontends/WorkArea.h" #include "support/environment.h" #include "support/FileFilterList.h" @@ -104,11 +106,21 @@ #include +using std::endl; +using std::make_pair; +using std::pair; +using std::string; +using std::istringstream; +using std::ostringstream; + +namespace fs = boost::filesystem; namespace lyx { using bv_funcs::freefont2string; +using frontend::LyXView; + using support::absolutePath; using support::addName; using support::addPath; @@ -135,15 +147,7 @@ using support::token; using support::trim; using support::prefixIs; -using std::endl; -using std::make_pair; -using std::pair; -using std::string; -using std::istringstream; -using std::ostringstream; - namespace Alert = frontend::Alert; -namespace fs = boost::filesystem; namespace { @@ -218,6 +222,10 @@ void LyXFunc::initKeySequences(KeyMap * kb) void LyXFunc::setLyXView(LyXView * 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()); lyx_view_ = lv; } @@ -229,6 +237,7 @@ void LyXFunc::handleKeyFunc(kb_action action) if (keyseq->length()) c = 0; + BOOST_ASSERT(lyx_view_ && lyx_view_->view()); lyx_view_->view()->getIntl().getTransManager().deadkey( c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor()); // Need to clear, in case the minibuffer calls these @@ -256,23 +265,32 @@ void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer) return; } // open may fail, so we need to test it again - if (theBufferList().exists(file)) { - // if the current buffer is not that one, switch to it. - if (lyx_view_->buffer()->fileName() != file) { - if (switchToBuffer) - dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file)); - else - return; - } - // moveToPosition use par_id, and par_pit and return new par_id. - pit_type new_pit; - pos_type new_pos; - int new_id; - boost::tie(new_pit, new_pos, new_id) = view()->moveToPosition(bm.bottom_pit, bm.bottom_pos, bm.top_id, bm.top_pos); - // if bottom_pit, bottom_pos or top_id has been changed, update bookmark - // see http://bugzilla.lyx.org/show_bug.cgi?id=3092 - if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos || bm.top_id != new_id ) - const_cast(bm).updatePos(new_pit, new_pos, new_id); + if (!theBufferList().exists(file)) + return; + + // if the current buffer is not that one, switch to it. + if (lyx_view_->buffer()->fileName() != file) { + if (!switchToBuffer) + return; + dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file)); + } + // moveToPosition try paragraph id first and then paragraph (pit, pos). + if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos, + bm.top_id, bm.top_pos)) + return; + + // Cursor jump succeeded! + Cursor const & cur = view()->cursor(); + pit_type new_pit = cur.pit(); + pos_type new_pos = cur.pos(); + int new_id = cur.paragraph().id(); + + // if bottom_pit, bottom_pos or top_id has been changed, update bookmark + // see http://bugzilla.lyx.org/show_bug.cgi?id=3092 + if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos + || bm.top_id != new_id) { + const_cast(bm).updatePos( + new_pit, new_pos, new_id); } } @@ -377,6 +395,12 @@ void LyXFunc::processKeySym(KeySymbolPtr keysym, key_modifier::state state) } 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(); } @@ -451,7 +475,7 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const case LFUN_BUFFER_SWITCH: // toggle on the current buffer, but do not toggle off // the other ones (is that a good idea?) - if (to_utf8(cmd.argument()) == buf->fileName()) + if (buf && to_utf8(cmd.argument()) == buf->fileName()) flag.setOnOff(true); break; @@ -491,7 +515,8 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const enable = buf->lyxvc().inUse(); break; case LFUN_BUFFER_RELOAD: - enable = !buf->isUnnamed() && !buf->isClean(); + enable = !buf->isUnnamed() && fs::exists(buf->fileName()) + && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method)); break; case LFUN_INSET_SETTINGS: { @@ -602,8 +627,31 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const } case LFUN_BUFFER_WRITE: { - enable = view()->buffer()->isUnnamed() - || !view()->buffer()->isClean(); + enable = lyx_view_->buffer()->isUnnamed() + || !lyx_view_->buffer()->isClean(); + break; + } + + + case LFUN_BUFFER_WRITE_ALL: { + // We enable the command only if there are some modified buffers + Buffer * first = theBufferList().first(); + bool modified = false; + if (first) { + Buffer * b = first; + + // We cannot use a for loop as the buffer list is a cycle. + do { + if (!b->isClean()) { + modified = true; + break; + } + b = theBufferList().next(b); + } while (b != first); + } + + enable = modified; + break; } @@ -725,7 +773,7 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const bool LyXFunc::ensureBufferClean(BufferView * bv) { - Buffer & buf = *bv->buffer(); + Buffer & buf = bv->buffer(); if (buf.isClean()) return true; @@ -848,7 +896,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) BOOST_ASSERT(lyx_view_ && lyx_view_->view()); keyseq->reset(); meta_fake_bit = key_modifier::none; - if (view()->buffer()) + if (lyx_view_->buffer()) // cancel any selection dispatch(FuncRequest(LFUN_MARK_OFF)); setMessage(from_ascii(N_("Cancel"))); @@ -871,15 +919,17 @@ void LyXFunc::dispatch(FuncRequest const & cmd) // --- 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: @@ -902,9 +952,33 @@ void LyXFunc::dispatch(FuncRequest const & cmd) updateFlags = Update::None; break; + case LFUN_BUFFER_WRITE_ALL: { + Buffer * first = theBufferList().first(); + if (first) { + Buffer * b = first; + lyx_view_->message(_("Saving all documents...")); + + // We cannot use a for loop as the buffer list cycles. + do { + if (!b->isClean()) { + if (!b->isUnnamed()) { + menuWrite(b); + lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl; + } else + writeAs(b); + } + b = theBufferList().next(b); + } while (b != first); + lyx_view_->message(_("All documents saved.")); + } + + updateFlags = Update::None; + break; + } + case LFUN_BUFFER_RELOAD: { BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); - docstring const file = makeDisplayPath(view()->buffer()->fileName(), 20); + docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20); docstring text = bformat(_("Any changes will be lost. Are you sure " "you want to revert to the saved version of the document %1$s?"), file); int const ret = Alert::prompt(_("Revert to saved document?"), @@ -989,21 +1063,22 @@ void LyXFunc::dispatch(FuncRequest const & cmd) case LFUN_BUFFER_PRINT: { BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); - string target; - string target_name; - string command = split(split(argument, target, ' '), - target_name, ' '); + // FIXME: cmd.getArg() might fail if one of the arguments + // contains double quotes + string target = cmd.getArg(0); + string target_name = cmd.getArg(1); + string command = cmd.getArg(2); if (target.empty() || target_name.empty() || command.empty()) { lyxerr << "Unable to parse \"" - << argument << '"' << std::endl; + << argument << '"' << endl; break; } if (target != "printer" && target != "file") { lyxerr << "Unrecognized target \"" - << target << '"' << std::endl; + << target << '"' << endl; break; } @@ -1035,13 +1110,13 @@ void LyXFunc::dispatch(FuncRequest const & cmd) // case 3: print using a spool string const psname = changeExtension(dviname,".ps"); - command += lyxrc.print_to_file + command += ' ' + lyxrc.print_to_file + quoteName(psname) + ' ' + quoteName(dviname); string command2 = - lyxrc.print_spool_command +' '; + lyxrc.print_spool_command + ' '; if (target_name != "default") { command2 += lyxrc.print_spool_printerprefix + target_name @@ -1061,7 +1136,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } else { // case 2: print directly to a printer if (target_name != "default") - command += lyxrc.print_to_printer + target_name + ' '; + command += ' ' + lyxrc.print_to_printer + target_name + ' '; res = one.startscript( Systemcall::DontWait, command + quoteName(dviname)); @@ -1069,7 +1144,9 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } else { // case 1: print to a file - FileName const filename(makeAbsPath(target_name, path)); + FileName const filename(makeAbsPath(target_name, + lyx_view_->buffer()->filePath())); + FileName const dvifile(makeAbsPath(dviname, path)); if (fs::exists(filename.toFilesystemEncoding())) { docstring text = bformat( _("The file %1$s already exists.\n\n" @@ -1079,10 +1156,10 @@ void LyXFunc::dispatch(FuncRequest const & cmd) text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0) break; } - command += lyxrc.print_to_file + command += ' ' + lyxrc.print_to_file + quoteName(filename.toFilesystemEncoding()) + ' ' - + quoteName(dviname); + + quoteName(dvifile.toFilesystemEncoding()); res = one.startscript(Systemcall::DontWait, command); } @@ -1128,7 +1205,13 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } 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; } @@ -1182,26 +1265,31 @@ void LyXFunc::dispatch(FuncRequest const & cmd) case LFUN_BUFFER_SWITCH: BOOST_ASSERT(lyx_view_); lyx_view_->setBuffer(theBufferList().getBuffer(argument)); + updateFlags = Update::None; break; case LFUN_BUFFER_NEXT: BOOST_ASSERT(lyx_view_); - lyx_view_->setBuffer(theBufferList().next(view()->buffer())); + lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer())); + updateFlags = Update::None; break; case LFUN_BUFFER_PREVIOUS: BOOST_ASSERT(lyx_view_); - lyx_view_->setBuffer(theBufferList().previous(view()->buffer())); + lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer())); + updateFlags = Update::None; break; case LFUN_FILE_NEW: BOOST_ASSERT(lyx_view_); - newFile(view(), argument); + 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: @@ -1234,24 +1322,35 @@ void LyXFunc::dispatch(FuncRequest const & cmd) 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; } @@ -1366,7 +1465,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_DIALOG_HIDE: - Dialogs::hide(argument, 0); + LyX::cref().hideDialogs(argument, 0); break; case LFUN_DIALOG_TOGGLE: { @@ -1410,34 +1509,36 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } 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), + // 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; break; } @@ -1447,22 +1548,22 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; case LFUN_KEYMAP_OFF: - BOOST_ASSERT(lyx_view_); + BOOST_ASSERT(lyx_view_ && lyx_view_->view()); lyx_view_->view()->getIntl().keyMapOn(false); break; case LFUN_KEYMAP_PRIMARY: - BOOST_ASSERT(lyx_view_); + BOOST_ASSERT(lyx_view_ && lyx_view_->view()); lyx_view_->view()->getIntl().keyMapPrim(); break; case LFUN_KEYMAP_SECONDARY: - BOOST_ASSERT(lyx_view_); + BOOST_ASSERT(lyx_view_ && lyx_view_->view()); lyx_view_->view()->getIntl().keyMapSec(); break; case LFUN_KEYMAP_TOGGLE: - BOOST_ASSERT(lyx_view_); + BOOST_ASSERT(lyx_view_ && lyx_view_->view()); lyx_view_->view()->getIntl().toggleKeyMap(); break; @@ -1534,9 +1635,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) theApp()->updateColor(lcolor.getFromLyXName(lyx_name)); if (graphicsbg_changed) { -#ifdef WITH_WARNINGS -#warning FIXME!! The graphics cache no longer has a changeDisplay method. -#endif + // FIXME: The graphics cache no longer has a changeDisplay method. #if 0 graphics::GCache::get().changeDisplay(true); #endif @@ -1771,18 +1870,22 @@ void LyXFunc::dispatch(FuncRequest const & cmd) string const name = cmd.getArg(0); bool const allowauto = cmd.getArg(1) == "allowauto"; lyx_view_->toggleToolbarState(name, allowauto); - ToolbarInfo::Flags const flags = - lyx_view_->getToolbarState(name); + ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name); + if (!tbi) { + setMessage(bformat(_("Unknown toolbar \"%1$s\""), + from_utf8(name))); + break; + } docstring state; - if (flags & ToolbarInfo::ON) + if (tbi->flags & ToolbarInfo::ON) state = _("on"); - else if (flags & ToolbarInfo::OFF) + else if (tbi->flags & ToolbarInfo::OFF) state = _("off"); - else if (flags & ToolbarInfo::AUTO) + else if (tbi->flags & ToolbarInfo::AUTO) state = _("auto"); setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"), - from_ascii(name), state)); + _(tbi->gui_name), state)); break; } @@ -1796,7 +1899,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } } - if (lyx_view_ && view()->buffer()) { + if (lyx_view_ && lyx_view_->buffer()) { // BufferView::update() updates the ViewMetricsInfo and // also initializes the position cache for all insets in // (at least partially) visible top-level paragraphs. @@ -1805,7 +1908,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) // Buffer::changed() signals that a repaint is needed. // The frontend (WorkArea) knows which area to repaint // thanks to the ViewMetricsInfo updated above. - view()->buffer()->changed(); + lyx_view_->buffer()->changed(); } lyx_view_->updateStatusBar(); @@ -1814,14 +1917,17 @@ void LyXFunc::dispatch(FuncRequest const & cmd) if (flag.enabled() && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer) && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly)) - view()->buffer()->markDirty(); + lyx_view_->buffer()->markDirty(); + + //Do we have a selection? + theSelection().haveSelection(view()->cursor().selection()); if (view()->cursor().inTexted()) { lyx_view_->updateLayoutChoice(); } } } - if (!quitting) { + if (!quitting && lyx_view_) { lyx_view_->updateMenubar(); lyx_view_->updateToolbars(); // Some messages may already be translated, so we cannot use _() @@ -1883,7 +1989,7 @@ void LyXFunc::menuNew(string const & name, bool fromTemplate) string initpath = lyxrc.document_path; string filename(name); - if (view()->buffer()) { + if (lyx_view_->buffer()) { string const trypath = lyx_view_->buffer()->filePath(); // If directory is writeable, use this as default. if (isDirWriteable(FileName(trypath))) @@ -1925,10 +2031,8 @@ void LyXFunc::menuNew(string const & name, bool fromTemplate) } Buffer * const b = newFile(filename, templname, !name.empty()); - if (b) { - updateLabels(*b); + if (b) lyx_view_->setBuffer(b); - } } @@ -1936,7 +2040,7 @@ void LyXFunc::open(string const & fname) { string initpath = lyxrc.document_path; - if (view()->buffer()) { + if (lyx_view_->buffer()) { string const trypath = lyx_view_->buffer()->filePath(); // If directory is writeable, use this as default. if (isDirWriteable(FileName(trypath))) @@ -1988,7 +2092,11 @@ void LyXFunc::open(string const & fname) 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); @@ -2009,7 +2117,7 @@ void LyXFunc::doImport(string const & argument) if (filename.empty()) { string initpath = lyxrc.document_path; - if (view()->buffer()) { + if (lyx_view_->buffer()) { string const trypath = lyx_view_->buffer()->filePath(); // If directory is writeable, use this as default. if (isDirWriteable(FileName(trypath))) @@ -2097,8 +2205,19 @@ void LyXFunc::closeBuffer() 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 @@ -2131,7 +2250,8 @@ docstring const LyXFunc::viewStatusMessage() if (keyseq->length() > 0 && !keyseq->deleted()) return keyseq->printOptions(true); - if (!view()->buffer()) + BOOST_ASSERT(lyx_view_); + if (!lyx_view_->buffer()) return _("Welcome to LyX!"); return view()->cursor().currentState();