X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyxfunc.C;h=4570bfba8f511ab85c6e4ac5f501e9d105ff67ce;hb=969ab85d985485f503790cb13f98a582d4e1cdb5;hp=1ff7b537544c90f421cb00b610c80e488232fe48;hpb=de6418f37765fe452f135f96dee6d49897bff215;p=lyx.git diff --git a/src/lyxfunc.C b/src/lyxfunc.C index 1ff7b53754..4570bfba8f 100644 --- a/src/lyxfunc.C +++ b/src/lyxfunc.C @@ -27,6 +27,7 @@ #include "bufferlist.h" #include "bufferparams.h" #include "BufferView.h" +#include "bufferview_funcs.h" #include "cursor.h" #include "CutAndPaste.h" #include "debug.h" @@ -78,6 +79,7 @@ #include "frontends/Dialogs.h" #include "frontends/FileDialog.h" #include "frontends/FontLoader.h" +#include "frontends/Gui.h" #include "frontends/LyXKeySym.h" #include "frontends/LyXView.h" #include "frontends/Menubar.h" @@ -112,6 +114,7 @@ using support::bformat; using support::changeExtension; using support::contains; using support::FileFilterList; +using support::FileName; using support::fileSearch; using support::ForkedcallsController; using support::i18nLibFileSearch; @@ -228,8 +231,8 @@ void LyXFunc::handleKeyFunc(kb_action action) if (keyseq->length()) c = 0; - lyx_view_->view()->getIntl().getTransManager() - .deadkey(c, get_accent(action).accent, view()->getLyXText()); + lyx_view_->view()->getIntl().getTransManager().deadkey( + c, get_accent(action).accent, view()->getLyXText(), view()->cursor()); // Need to clear, in case the minibuffer calls these // actions keyseq->clear(); @@ -239,6 +242,42 @@ void LyXFunc::handleKeyFunc(kb_action action) } +void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer) +{ + BOOST_ASSERT(lyx_view_); + if (!LyX::ref().session().bookmarks().isValid(idx)) + return; + BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx); + BOOST_ASSERT(!bm.filename.empty()); + string const file = bm.filename.absFilename(); + // if the file is not opened, open it. + if (!theBufferList().exists(file)) { + if (openFile) + dispatch(FuncRequest(LFUN_FILE_OPEN, file)); + else + 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; + int new_id; + boost::tie(new_pit, new_id) = view()->moveToPosition(bm.par_pit, bm.par_id, bm.par_pos); + // if par_id or pit has been changed, reset par_pit and par_id + // see http://bugzilla.lyx.org/show_bug.cgi?id=3092 + if (bm.par_pit != new_pit || bm.par_id != new_id) + const_cast(bm).setPos(new_pit, new_id); + } +} + + void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state) { lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl; @@ -257,7 +296,9 @@ void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state) //Encoding const * encoding = view()->cursor().getEncoding(); //encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : ""); - size_t encoded_last_key = keysym->getUCSEncoded(); + // FIXME: encoded_last_key shadows the member variable of the same + // name. Is that intended? + char_type encoded_last_key = keysym->getUCSEncoded(); // Do a one-deep top-level lookup for // cancel and meta-fake keys. RVDK_PATCH_5 @@ -291,7 +332,7 @@ void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state) lyxerr << BOOST_CURRENT_FUNCTION << " Key [action=" << func.action << "][" - << keyseq->print() << ']' + << to_utf8(keyseq->print(false)) << ']' << endl; } @@ -300,7 +341,7 @@ void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state) // num_bytes == 0? (Lgb) if (keyseq->length() > 1) { - lyx_view_->message(from_utf8(keyseq->print())); + lyx_view_->message(keyseq->print(true)); } @@ -346,6 +387,7 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const { //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl; FuncStatus flag; + LCursor & cur = view()->cursor(); /* In LyX/Mac, when a dialog is open, the menus of the @@ -356,11 +398,9 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const 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 && !lyx_view_->hasFocus()) + Buffer * buf = lyx_view_? lyx_view_->buffer() : 0; + if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus()) buf = 0; - else - buf = lyx_view_->buffer(); if (cmd.action == LFUN_NOACTION) { flag.message(from_utf8(N_("Nothing to do"))); @@ -496,9 +536,10 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const 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); + if (!inset->getStatus(cur, fr, fs)) { + // Every inset is supposed to handle this + BOOST_ASSERT(false); + } flag |= fs; } else { FuncRequest fr(LFUN_INSET_INSERT, cmd.argument()); @@ -522,7 +563,7 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const else if (name == "character" || name == "mathpanel") enable = cur.inset().lyxCode() != InsetBase::ERT_CODE; else if (name == "latexlog") - enable = isFileReadable(buf->getLogName().second); + enable = isFileReadable(FileName(buf->getLogName().second)); #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL) else if (name == "spellchecker") enable = false; @@ -536,6 +577,11 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const case LFUN_DIALOG_SHOW_NEW_INSET: enable = cur.inset().lyxCode() != InsetBase::ERT_CODE; + if (cur.inset().lyxCode() == InsetBase::CAPTION_CODE) { + FuncStatus flag; + if (cur.inset().getStatus(cur, cmd, flag)) + return flag; + } break; case LFUN_DIALOG_UPDATE: { @@ -557,6 +603,23 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const break; } + case LFUN_BOOKMARK_GOTO: { + const unsigned int num = convert(to_utf8(cmd.argument())); + enable = LyX::ref().session().bookmarks().isValid(num); + break; + } + + case LFUN_BOOKMARK_CLEAR: + enable = LyX::ref().session().bookmarks().size() > 0; + break; + + case LFUN_TOOLBAR_TOGGLE_STATE: { + ToolbarBackend::Flags flags = lyx_view_->getToolbarState(to_utf8(cmd.argument())); + if (!(flags & ToolbarBackend::AUTO)) + flag.setOnOff(flags & ToolbarBackend::ON); + break; + } + // this one is difficult to get right. As a half-baked // solution, we consider only the first action of the sequence case LFUN_COMMAND_SEQUENCE: { @@ -580,7 +643,6 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const case LFUN_BUFFER_UPDATE: case LFUN_BUFFER_VIEW: case LFUN_BUFFER_IMPORT: - case LFUN_LYX_QUIT: case LFUN_TOC_VIEW: case LFUN_BUFFER_AUTO_SAVE: case LFUN_RECONFIGURE: @@ -619,6 +681,8 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const case LFUN_BUFFER_NEXT: case LFUN_BUFFER_PREVIOUS: case LFUN_WINDOW_NEW: + case LFUN_WINDOW_CLOSE: + case LFUN_LYX_QUIT: // these are handled in our dispatch() break; @@ -716,7 +780,6 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new); void LyXFunc::dispatch(FuncRequest const & cmd) { - BOOST_ASSERT(view()); string const argument = to_utf8(cmd.argument()); kb_action const action = cmd.action; @@ -729,9 +792,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) // redraw the screen at the end (first of the two drawing steps). //This is done unless explicitely requested otherwise - bool update = true; - // also do the second redrawing step. Only done if requested. - bool updateforce = false; + Update::flags updateFlags = Update::FitCursor; FuncStatus const flag = getStatus(cmd); if (!flag.enabled()) { @@ -746,12 +807,13 @@ void LyXFunc::dispatch(FuncRequest const & cmd) case LFUN_WORD_FIND_FORWARD: case LFUN_WORD_FIND_BACKWARD: { - static string last_search; - string searched_string; + BOOST_ASSERT(lyx_view_ && lyx_view_->view()); + static docstring last_search; + docstring searched_string; - if (!argument.empty()) { - last_search = argument; - searched_string = argument; + if (!cmd.argument().empty()) { + last_search = cmd.argument(); + searched_string = cmd.argument(); } else { searched_string = last_search; } @@ -760,22 +822,25 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; bool const fw = action == LFUN_WORD_FIND_FORWARD; - string const data = + docstring const data = find2string(searched_string, true, false, fw); find(view(), FuncRequest(LFUN_WORD_FIND, data)); break; } case LFUN_COMMAND_PREFIX: - lyx_view_->message(from_utf8(keyseq->printOptions())); + BOOST_ASSERT(lyx_view_); + lyx_view_->message(keyseq->printOptions(true)); break; case LFUN_COMMAND_EXECUTE: + BOOST_ASSERT(lyx_view_); lyx_view_->getToolbars().display("minibuffer", true); lyx_view_->focus_command_buffer(); break; case LFUN_CANCEL: + BOOST_ASSERT(lyx_view_ && lyx_view_->view()); keyseq->reset(); meta_fake_bit = key_modifier::none; if (view()->buffer()) @@ -786,10 +851,11 @@ void LyXFunc::dispatch(FuncRequest const & cmd) case LFUN_META_PREFIX: meta_fake_bit = key_modifier::alt; - setMessage(from_utf8(keyseq->print())); + setMessage(keyseq->print(true)); break; case LFUN_BUFFER_TOGGLE_READ_ONLY: + BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer()); if (lyx_view_->buffer()->lyxvc().inUse()) lyx_view_->buffer()->lyxvc().toggleReadOnly(); else @@ -808,26 +874,31 @@ void LyXFunc::dispatch(FuncRequest const & cmd) case LFUN_BUFFER_CLOSE: closeBuffer(); + view()->update(); break; case LFUN_BUFFER_WRITE: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); if (!lyx_view_->buffer()->isUnnamed()) { docstring const str = bformat(_("Saving document %1$s..."), makeDisplayPath(lyx_view_->buffer()->fileName())); lyx_view_->message(str); menuWrite(lyx_view_->buffer()); lyx_view_->message(str + _(" done.")); - } else - writeAs(lyx_view_->buffer()); - update = false; + } else { + writeAs(lyx_view_->buffer()); + } + updateFlags = Update::None; break; case LFUN_BUFFER_WRITE_AS: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); writeAs(lyx_view_->buffer(), argument); - update = false; + updateFlags = Update::None; break; case LFUN_BUFFER_RELOAD: { + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); docstring const file = makeDisplayPath(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); @@ -835,27 +906,32 @@ void LyXFunc::dispatch(FuncRequest const & cmd) text, 0, 1, _("&Revert"), _("&Cancel")); if (ret == 0) - view()->reload(); + reloadBuffer(); break; } case LFUN_BUFFER_UPDATE: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); Exporter::Export(lyx_view_->buffer(), argument, true); break; case LFUN_BUFFER_VIEW: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); Exporter::preview(lyx_view_->buffer(), argument); break; case LFUN_BUILD_PROGRAM: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); Exporter::Export(lyx_view_->buffer(), "program", true); break; case LFUN_BUFFER_CHKTEX: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); lyx_view_->buffer()->runChktex(); break; case LFUN_BUFFER_EXPORT: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); if (argument == "custom") lyx_view_->getDialogs().show("sendto"); else { @@ -864,6 +940,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; case LFUN_BUFFER_EXPORT_CUSTOM: { + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); string format_name; string command = split(argument, format_name, ' '); Format const * format = formats.getFormat(format_name); @@ -887,7 +964,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) format->extension()); filename = addName(buffer->temppath(), filename); - if (!buffer->writeFile(filename)) + if (!buffer->writeFile(FileName(filename))) break; } else { @@ -906,6 +983,7 @@ 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, ' '), @@ -982,9 +1060,20 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } else { // case 1: print to a file + FileName const filename(makeAbsPath(target_name, path)); + if (fs::exists(filename.toFilesystemEncoding())) { + docstring text = bformat( + _("The file %1$s already exists.\n\n" + "Do you want to over-write that file?"), + makeDisplayPath(filename.absFilename())); + if (Alert::prompt(_("Over-write file?"), + text, 0, 1, _("&Over-write"), _("&Cancel")) != 0) { + showPrintError(buffer->fileName()); + break; + } + } command += lyxrc.print_to_file - + quoteName(makeAbsPath(target_name, - path)) + + quoteName(filename.toFilesystemEncoding()) + ' ' + quoteName(dviname); res = one.startscript(Systemcall::DontWait, @@ -1001,17 +1090,15 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; case LFUN_LYX_QUIT: - if (view()->buffer()) { - // save cursor Position for opened files to .lyx/session - LyX::ref().session().saveFilePosition(lyx_view_->buffer()->fileName(), - boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); - // save bookmarks to .lyx/session - view()->saveSavedPositions(); - } - LyX::ref().quit(argument == "force"); + // quitting is triggered by the gui code + // (leaving the event loop). + lyx_view_->message(from_utf8(N_("Exiting."))); + if (theBufferList().quitWriteAll()) + theApp()->gui().closeAllViews(); break; case LFUN_TOC_VIEW: { + BOOST_ASSERT(lyx_view_); InsetCommandParams p("tableofcontents"); string const data = InsetCommandMailer::params2string("toc", p); lyx_view_->getDialogs().show("toc", data, 0); @@ -1023,98 +1110,114 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; case LFUN_RECONFIGURE: - reconfigure(view()); + BOOST_ASSERT(lyx_view_); + reconfigure(*lyx_view_); break; case LFUN_HELP_OPEN: { + BOOST_ASSERT(lyx_view_); string const arg = argument; if (arg.empty()) { setErrorMessage(_("Missing argument")); break; } - string const fname = i18nLibFileSearch("doc", arg, "lyx"); + FileName const fname = i18nLibFileSearch("doc", arg, "lyx"); if (fname.empty()) { lyxerr << "LyX: unable to find documentation file `" << arg << "'. Bad installation?" << endl; break; } lyx_view_->message(bformat(_("Opening help file %1$s..."), - makeDisplayPath(fname))); + makeDisplayPath(fname.absFilename()))); lyx_view_->loadLyXFile(fname, false); break; } // --- version control ------------------------------- case LFUN_VC_REGISTER: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); if (!ensureBufferClean(view())) break; if (!lyx_view_->buffer()->lyxvc().inUse()) { lyx_view_->buffer()->lyxvc().registrer(); - view()->reload(); + reloadBuffer(); } + updateFlags = Update::Force; break; case LFUN_VC_CHECK_IN: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); if (!ensureBufferClean(view())) break; if (lyx_view_->buffer()->lyxvc().inUse() && !lyx_view_->buffer()->isReadonly()) { lyx_view_->buffer()->lyxvc().checkIn(); - view()->reload(); + reloadBuffer(); } break; case LFUN_VC_CHECK_OUT: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); if (!ensureBufferClean(view())) break; if (lyx_view_->buffer()->lyxvc().inUse() && lyx_view_->buffer()->isReadonly()) { lyx_view_->buffer()->lyxvc().checkOut(); - view()->reload(); + reloadBuffer(); } break; case LFUN_VC_REVERT: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); lyx_view_->buffer()->lyxvc().revert(); - view()->reload(); + reloadBuffer(); break; case LFUN_VC_UNDO_LAST: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); lyx_view_->buffer()->lyxvc().undoLast(); - view()->reload(); + reloadBuffer(); break; // --- buffers ---------------------------------------- case LFUN_BUFFER_SWITCH: + BOOST_ASSERT(lyx_view_); lyx_view_->setBuffer(theBufferList().getBuffer(argument)); break; case LFUN_BUFFER_NEXT: + BOOST_ASSERT(lyx_view_); lyx_view_->setBuffer(theBufferList().next(view()->buffer())); break; case LFUN_BUFFER_PREVIOUS: + BOOST_ASSERT(lyx_view_); lyx_view_->setBuffer(theBufferList().previous(view()->buffer())); break; case LFUN_FILE_NEW: + BOOST_ASSERT(lyx_view_); newFile(view(), argument); break; case LFUN_FILE_OPEN: + BOOST_ASSERT(lyx_view_); open(argument); break; case LFUN_DROP_LAYOUTS_CHOICE: + BOOST_ASSERT(lyx_view_); lyx_view_->getToolbars().openLayoutList(); break; case LFUN_MENU_OPEN: + BOOST_ASSERT(lyx_view_); lyx_view_->getMenubar().openByName(from_utf8(argument)); break; // --- lyxserver commands ---------------------------- case LFUN_SERVER_GET_NAME: + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); setMessage(from_utf8(lyx_view_->buffer()->fileName())); lyxerr[Debug::INFO] << "FNAME[" << lyx_view_->buffer()->fileName() @@ -1122,11 +1225,12 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; case LFUN_SERVER_NOTIFY: - dispatch_buffer = from_utf8(keyseq->print()); + dispatch_buffer = keyseq->print(false); theLyXServer().notifyClient(to_utf8(dispatch_buffer)); break; case LFUN_SERVER_GOTO_FILE_ROW: { + BOOST_ASSERT(lyx_view_); string file_name; int row; istringstream is(argument); @@ -1138,10 +1242,10 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } else { // Must replace extension of the file to be .lyx // and get full path - string const s = changeExtension(file_name, ".lyx"); + FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx"); // Either change buffer or load the file - if (theBufferList().exists(s)) { - lyx_view_->setBuffer(theBufferList().getBuffer(s)); + if (theBufferList().exists(s.absFilename())) { + lyx_view_->setBuffer(theBufferList().getBuffer(s.absFilename())); } else { lyx_view_->loadLyXFile(s); } @@ -1149,12 +1253,12 @@ void LyXFunc::dispatch(FuncRequest const & cmd) view()->setCursorFromRow(row); - view()->center(); - // see BufferView::center() + updateFlags = Update::FitCursor; break; } case LFUN_DIALOG_SHOW: { + BOOST_ASSERT(lyx_view_); string const name = cmd.getArg(0); string data = trim(to_utf8(cmd.argument()).substr(name.size())); @@ -1185,18 +1289,25 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_DIALOG_SHOW_NEW_INSET: { + BOOST_ASSERT(lyx_view_); string const name = cmd.getArg(0); string data = trim(to_utf8(cmd.argument()).substr(name.size())); if (name == "bibitem" || name == "bibtex" || name == "index" || name == "label" || + name == "nomenclature" || name == "ref" || name == "toc" || name == "url") { InsetCommandParams p(name); data = InsetCommandMailer::params2string(name, p); } else if (name == "include") { + // data is the include type: one of "include", + // "input", "verbatiminput" or "verbatiminput*" + if (data.empty()) + // default type is requested + data = "include"; InsetCommandParams p(data); data = InsetIncludeMailer::params2string(p); } else if (name == "box") { @@ -1237,6 +1348,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_DIALOG_UPDATE: { + BOOST_ASSERT(lyx_view_); string const & name = argument; // Can only update a dialog connected to an existing inset InsetBase * inset = lyx_view_->getDialogs().getOpenInset(name); @@ -1256,11 +1368,13 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; case LFUN_DIALOG_DISCONNECT_INSET: + BOOST_ASSERT(lyx_view_); lyx_view_->getDialogs().disconnect(argument); break; case LFUN_CITATION_INSERT: { + BOOST_ASSERT(lyx_view_); if (!argument.empty()) { // we can have one optional argument, delimited by '|' // citation-insert | @@ -1284,15 +1398,16 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_BUFFER_CHILD_OPEN: { - string const filename = + BOOST_ASSERT(lyx_view_); + FileName const filename = makeAbsPath(argument, lyx_view_->buffer()->filePath()); // FIXME Should use bformat setMessage(_("Opening child document ") + - makeDisplayPath(filename) + "..."); - view()->savePosition(0); + makeDisplayPath(filename.absFilename()) + "..."); + view()->saveBookmark(false); string const parentfilename = lyx_view_->buffer()->fileName(); - if (theBufferList().exists(filename)) - lyx_view_->setBuffer(theBufferList().getBuffer(filename)); + if (theBufferList().exists(filename.absFilename())) + lyx_view_->setBuffer(theBufferList().getBuffer(filename.absFilename())); else lyx_view_->loadLyXFile(filename); // Set the parent name of the child document. @@ -1303,22 +1418,27 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR: + BOOST_ASSERT(lyx_view_); lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar; break; case LFUN_KEYMAP_OFF: + BOOST_ASSERT(lyx_view_); lyx_view_->view()->getIntl().keyMapOn(false); break; case LFUN_KEYMAP_PRIMARY: + BOOST_ASSERT(lyx_view_); lyx_view_->view()->getIntl().keyMapPrim(); break; case LFUN_KEYMAP_SECONDARY: + BOOST_ASSERT(lyx_view_); lyx_view_->view()->getIntl().keyMapSec(); break; case LFUN_KEYMAP_TOGGLE: + BOOST_ASSERT(lyx_view_); lyx_view_->view()->getIntl().toggleKeyMap(); break; @@ -1349,17 +1469,20 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_PREFERENCES_SAVE: { - support::Path p(package().user_support()); - lyxrc.write("preferences", false); + lyxrc.write(makeAbsPath("preferences", + package().user_support()), + false); break; } case LFUN_SCREEN_FONT_UPDATE: + BOOST_ASSERT(lyx_view_); // handle the screen font changes. lyxrc.set_font_norm_type(); theFontLoader().update(); - // All visible buffers will need resize - view()->resize(); + /// FIXME: only the current view will be updated. the Gui + /// class is able to furnish the list of views. + updateFlags = Update::Force; break; case LFUN_SET_COLOR: { @@ -1384,7 +1507,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; } - theApp->updateColor(lcolor.getFromLyXName(lyx_name)); + theApp()->updateColor(lcolor.getFromLyXName(lyx_name)); if (graphicsbg_changed) { #ifdef WITH_WARNINGS @@ -1398,10 +1521,12 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_MESSAGE: + BOOST_ASSERT(lyx_view_); lyx_view_->message(from_utf8(argument)); break; case LFUN_EXTERNAL_EDIT: { + BOOST_ASSERT(lyx_view_); FuncRequest fr(action, argument); InsetExternal().dispatch(view()->cursor(), fr); break; @@ -1414,6 +1539,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_INSET_APPLY: { + BOOST_ASSERT(lyx_view_); string const name = cmd.getArg(0); InsetBase * inset = lyx_view_->getDialogs().getOpenInset(name); if (inset) { @@ -1425,11 +1551,12 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } // ideally, the update flag should be set by the insets, // but this is not possible currently - updateforce = true; + updateFlags = Update::Force | Update::FitCursor; break; } case LFUN_ALL_INSETS_TOGGLE: { + BOOST_ASSERT(lyx_view_); string action; string const name = split(argument, action, ' '); InsetBase::Code const inset_code = @@ -1449,11 +1576,12 @@ void LyXFunc::dispatch(FuncRequest const & cmd) it->dispatch(tmpcur, fr); } } - updateforce = true; + updateFlags = Update::Force | Update::FitCursor; break; } case LFUN_BUFFER_LANGUAGE: { + BOOST_ASSERT(lyx_view_); Buffer & buffer = *lyx_view_->buffer(); Language const * oldL = buffer.params().language; Language const * newL = languages.getLanguage(argument); @@ -1486,7 +1614,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) << endl; } - if (defaults.writeFile(defaults.fileName())) + if (defaults.writeFile(FileName(defaults.fileName()))) // FIXME Should use bformat setMessage(_("Document defaults saved in ") + makeDisplayPath(fname)); @@ -1496,6 +1624,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_BUFFER_PARAMS_APPLY: { + BOOST_ASSERT(lyx_view_); biblio::CiteEngine const engine = lyx_view_->buffer()->params().cite_engine; @@ -1527,6 +1656,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } case LFUN_TEXTCLASS_APPLY: { + BOOST_ASSERT(lyx_view_); Buffer * buffer = lyx_view_->buffer(); textclass_type const old_class = @@ -1558,7 +1688,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) buffer->errors("Class Switch"); updateLabels(*buffer); - updateforce = true; + updateFlags = Update::Force | Update::FitCursor; break; } @@ -1580,38 +1710,72 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } actOnUpdatedPrefs(lyxrc_orig, lyxrc); + + /// We force the redraw in any case because there might be + /// some screen font changes. + /// FIXME: only the current view will be updated. the Gui + /// class is able to furnish the list of views. + updateFlags = Update::Force; break; } case LFUN_WINDOW_NEW: - BOOST_ASSERT(theApp); LyX::ref().newLyXView(); + break; + + case LFUN_WINDOW_CLOSE: + BOOST_ASSERT(lyx_view_); + BOOST_ASSERT(theApp()); + // update bookmark pit of the current buffer before window close + for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) + gotoBookmark(i+1, false, false); + // ask the user for saving changes or cancel quit + if (!theBufferList().quitWriteAll()) + break; + lyx_view_->close(); + return; + + case LFUN_BOOKMARK_GOTO: + // go to bookmark, open unopened file and switch to buffer if necessary + gotoBookmark(convert(to_utf8(cmd.argument())), true, true); + break; + + case LFUN_BOOKMARK_CLEAR: + LyX::ref().session().bookmarks().clear(); + break; + + case LFUN_TOOLBAR_TOGGLE_STATE: + lyx_view_->toggleToolbarState(argument); + break; default: { + BOOST_ASSERT(lyx_view_); view()->cursor().dispatch(cmd); - update = false; - updateforce |= view()->cursor().result().update(); + updateFlags = view()->cursor().result().update(); if (!view()->cursor().result().dispatched()) - updateforce |= view()->dispatch(cmd); + updateFlags = view()->dispatch(cmd); break; } } - if (view()->buffer()) { - // Redraw screen unless explicitly told otherwise. - // This also initializes the position cache for all insets - // in (at least partially) visible top-level paragraphs. - if (updateforce) - view()->update(Update::FitCursor | Update::Force); - else if (update) - view()->update(Update::FitCursor); + if (lyx_view_ && view()->buffer()) { + // BufferView::update() updates the ViewMetricsInfo and + // also initializes the position cache for all insets in + // (at least partially) visible top-level paragraphs. + // We will redraw the screen only if needed. + if (view()->update(updateFlags)) { + // 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_->redrawWorkArea(); + lyx_view_->updateStatusBar(); // if we executed a mutating lfun, mark the buffer as dirty if (flag.enabled() - && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) - && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)) + && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer) + && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly)) view()->buffer()->markDirty(); if (view()->cursor().inTexted()) { @@ -1619,26 +1783,18 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } } } - if (!quitting) - // FIXME UNICODE: _() does not support anything but ascii. - // Do we need a to_ascii() method? + if (!quitting) { + lyx_view_->updateMenubar(); + lyx_view_->updateToolbars(); sendDispatchMessage(getMessage(), cmd); + } } void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd) { - /* 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) { - lyx_view_->updateMenubar(); - lyx_view_->updateToolbars(); - } - - const bool verbose = (cmd.origin == FuncRequest::UI + const bool verbose = (cmd.origin == FuncRequest::MENU + || cmd.origin == FuncRequest::TOOLBAR || cmd.origin == FuncRequest::COMMANDBUFFER); if (cmd.action == LFUN_SELF_INSERT || !verbose) { @@ -1652,27 +1808,27 @@ void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd if (!dispatch_msg.empty()) dispatch_msg += ' '; - string comname = lyxaction.getActionName(cmd.action); + docstring comname = from_utf8(lyxaction.getActionName(cmd.action)); bool argsadded = false; if (!cmd.argument().empty()) { if (cmd.action != LFUN_UNKNOWN_ACTION) { - comname += ' ' + to_utf8(cmd.argument()); + comname += ' ' + cmd.argument(); argsadded = true; } } - string const shortcuts = theTopLevelKeymap().printbindings(cmd); + docstring const shortcuts = theTopLevelKeymap().printbindings(cmd); if (!shortcuts.empty()) comname += ": " + shortcuts; else if (!argsadded && !cmd.argument().empty()) - comname += ' ' + to_utf8(cmd.argument()); + comname += ' ' + cmd.argument(); if (!comname.empty()) { comname = rtrim(comname); - dispatch_msg += from_utf8('(' + rtrim(comname) + ')'); + dispatch_msg += '(' + rtrim(comname) + ')'; } lyxerr[Debug::ACTION] << "verbose dispatch msg " @@ -1684,13 +1840,14 @@ void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd void LyXFunc::menuNew(string const & name, bool fromTemplate) { + // FIXME: initpath is not used. What to do? string initpath = lyxrc.document_path; string filename(name); if (view()->buffer()) { string const trypath = lyx_view_->buffer()->filePath(); // If directory is writeable, use this as default. - if (isDirWriteable(trypath)) + if (isDirWriteable(FileName(trypath))) initpath = trypath; } @@ -1699,7 +1856,8 @@ void LyXFunc::menuNew(string const & name, bool fromTemplate) if (filename.empty()) { filename = addName(lyxrc.document_path, "newfile" + convert(++newfile_number) + ".lyx"); - while (theBufferList().exists(filename) || fs::is_readable(filename)) { + while (theBufferList().exists(filename) || + fs::is_readable(FileName(filename).toFilesystemEncoding())) { ++newfile_number; filename = addName(lyxrc.document_path, "newfile" + convert(newfile_number) + @@ -1740,7 +1898,7 @@ void LyXFunc::open(string const & fname) if (view()->buffer()) { string const trypath = lyx_view_->buffer()->filePath(); // If directory is writeable, use this as default. - if (isDirWriteable(trypath)) + if (isDirWriteable(FileName(trypath))) initpath = trypath; } @@ -1772,15 +1930,12 @@ void LyXFunc::open(string const & fname) // get absolute path of file and add ".lyx" to the filename if // necessary - string const fullpath = fileSearch(string(), filename, "lyx"); - if (!fullpath.empty()) { - filename = fullpath; - } - - docstring const disp_fn = makeDisplayPath(filename); + FileName const fullname = fileSearch(string(), filename, "lyx"); + if (!fullname.empty()) + filename = fullname.absFilename(); // if the file doesn't exist, let the user create one - if (!fs::exists(filename)) { + if (!fs::exists(fullname.toFilesystemEncoding())) { // the user specifically chose this name. Believe him. Buffer * const b = newFile(filename, string(), true); if (b) @@ -1788,10 +1943,11 @@ void LyXFunc::open(string const & fname) return; } + docstring const disp_fn = makeDisplayPath(filename); lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn)); docstring str2; - if (lyx_view_->loadLyXFile(filename)) { + if (lyx_view_->loadLyXFile(fullname)) { str2 = bformat(_("Document %1$s opened."), disp_fn); } else { str2 = bformat(_("Could not open document %1$s"), disp_fn); @@ -1815,7 +1971,7 @@ void LyXFunc::doImport(string const & argument) if (view()->buffer()) { string const trypath = lyx_view_->buffer()->filePath(); // If directory is writeable, use this as default. - if (isDirWriteable(trypath)) + if (isDirWriteable(FileName(trypath))) initpath = trypath; } @@ -1853,13 +2009,13 @@ void LyXFunc::doImport(string const & argument) return; // get absolute path of file - filename = makeAbsPath(filename); + FileName const fullname(makeAbsPath(filename)); - string const lyxfile = changeExtension(filename, ".lyx"); + FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx")); // Check if the document already is open - if (use_gui && theBufferList().exists(lyxfile)) { - if (!theBufferList().close(theBufferList().getBuffer(lyxfile), true)) { + if (use_gui && theBufferList().exists(lyxfile.absFilename())) { + if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) { lyx_view_->message(_("Canceled.")); return; } @@ -1867,8 +2023,8 @@ void LyXFunc::doImport(string const & argument) // if the file exists already, and we didn't do // -i lyx thefile.lyx, warn - if (fs::exists(lyxfile) && filename != lyxfile) { - docstring const file = makeDisplayPath(lyxfile, 30); + if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) { + docstring const file = makeDisplayPath(lyxfile.absFilename(), 30); docstring text = bformat(_("The document %1$s already exists.\n\n" "Do you want to over-write that document?"), file); @@ -1882,7 +2038,7 @@ void LyXFunc::doImport(string const & argument) } ErrorList errorList; - Importer::Import(lyx_view_, filename, format, errorList); + Importer::Import(lyx_view_, fullname, format, errorList); // FIXME (Abdel 12/08/06): Is there a need to display the error list here? } @@ -1890,8 +2046,11 @@ void LyXFunc::doImport(string const & argument) void LyXFunc::closeBuffer() { // save current cursor position - LyX::ref().session().saveFilePosition(lyx_view_->buffer()->fileName(), + LyX::ref().session().lastFilePos().save(FileName(lyx_view_->buffer()->fileName()), boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); + // goto bookmark to update bookmark pit. + for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) + gotoBookmark(i+1, false, false); if (theBufferList().close(lyx_view_->buffer(), true) && !quitting) { if (theBufferList().empty()) { // need this otherwise SEGV may occur while @@ -1905,6 +2064,13 @@ void LyXFunc::closeBuffer() } +void LyXFunc::reloadBuffer() +{ + FileName filename(lyx_view_->buffer()->fileName()); + closeBuffer(); + lyx_view_->loadLyXFile(filename); +} + // Each "lyx_view_" should have it's own message method. lyxview and // the minibuffer would use the minibuffer, but lyxserver would // send an ERROR signal to its client. Alejandro 970603 @@ -1924,19 +2090,19 @@ void LyXFunc::setMessage(docstring const & m) const } -string const LyXFunc::viewStatusMessage() +docstring const LyXFunc::viewStatusMessage() { // When meta-fake key is pressed, show the key sequence so far + "M-". if (wasMetaKey()) - return keyseq->print() + "M-"; + return keyseq->print(true) + "M-"; // Else, when a non-complete key sequence is pressed, // show the available options. if (keyseq->length() > 0 && !keyseq->deleted()) - return keyseq->printOptions(); + return keyseq->printOptions(true); if (!view()->buffer()) - return to_utf8(_("Welcome to LyX!")); + return _("Welcome to LyX!"); return view()->cursor().currentState(); } @@ -1968,8 +2134,8 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new) switch (tag) { case LyXRC::RC_ACCEPT_COMPOUND: case LyXRC::RC_ALT_LANG: - case LyXRC::RC_ASCIIROFF_COMMAND: - case LyXRC::RC_ASCII_LINELEN: + case LyXRC::RC_PLAINTEXT_ROFF_COMMAND: + case LyXRC::RC_PLAINTEXT_LINELEN: case LyXRC::RC_AUTOREGIONDELETE: case LyXRC::RC_AUTORESET_OPTIONS: case LyXRC::RC_AUTOSAVE: @@ -1982,6 +2148,7 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new) case LyXRC::RC_LOADSESSION: case LyXRC::RC_CHKTEX_COMMAND: case LyXRC::RC_CONVERTER: + case LyXRC::RC_CONVERTER_CACHE_MAXAGE: case LyXRC::RC_COPIER: case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR: case LyXRC::RC_CUSTOM_EXPORT_COMMAND: @@ -1993,10 +2160,10 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new) case LyXRC::RC_DISPLAY_GRAPHICS: case LyXRC::RC_DOCUMENTPATH: if (lyxrc_orig.document_path != lyxrc_new.document_path) { - if (fs::exists(lyxrc_new.document_path) && - fs::is_directory(lyxrc_new.document_path)) { + string const encoded = FileName( + lyxrc_new.document_path).toFilesystemEncoding(); + if (fs::exists(encoded) && fs::is_directory(encoded)) support::package().document_dir() = lyxrc.document_path; - } } case LyXRC::RC_ESC_CHARS: case LyXRC::RC_FONT_ENCODING: @@ -2078,6 +2245,7 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new) case LyXRC::RC_USER_NAME: case LyXRC::RC_USETEMPDIR: case LyXRC::RC_USE_ALT_LANG: + case LyXRC::RC_USE_CONVERTER_CACHE: case LyXRC::RC_USE_ESC_CHARS: case LyXRC::RC_USE_INP_ENC: case LyXRC::RC_USE_PERS_DICT: