X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyx_main.C;h=b881f3d78f55f3c383c1ffbaa09bfe24008f2650;hb=ba62665f966508db5a4de6864f4aa7374c5a5356;hp=6c0e575f64b901b5a6be9f4f731864cc36e19172;hpb=9feb262948c91bad850f2d98b0f97ebf22eb8752;p=lyx.git diff --git a/src/lyx_main.C b/src/lyx_main.C index 6c0e575f64..b881f3d78f 100644 --- a/src/lyx_main.C +++ b/src/lyx_main.C @@ -40,6 +40,7 @@ #include "lyxsocket.h" #include "lyxtextclasslist.h" #include "MenuBackend.h" +#include "messages.h" #include "mover.h" #include "ToolbarBackend.h" @@ -50,20 +51,22 @@ #include "support/environment.h" #include "support/filetools.h" -#include "support/fontutils.h" #include "support/lyxlib.h" #include "support/convert.h" +#include "support/ExceptionMessage.h" #include "support/os.h" #include "support/package.h" #include "support/path.h" #include "support/systemcall.h" -#include "support/unicode.h" #include #include #include #include +#include +#include +#include namespace lyx { @@ -71,6 +74,7 @@ namespace lyx { using support::addName; using support::addPath; using support::bformat; +using support::changeExtension; using support::createDirectory; using support::createLyXTmpDir; using support::destroyDir; @@ -89,9 +93,11 @@ namespace os = support::os; namespace fs = boost::filesystem; using std::endl; +using std::for_each; +using std::map; +using std::make_pair; using std::string; using std::vector; -using std::for_each; #ifndef CXX_GLOBAL_CSTD using std::exit; @@ -99,8 +105,6 @@ using std::signal; using std::system; #endif -/// -frontend::Application * theApp = 0; /// are we using the GUI at all? /** @@ -145,8 +149,12 @@ void reconfigureUserLyXDir() /// The main application class private implementation. struct LyX::Singletons { - Singletons(): iconv(ucs4_codeset, "UTF-8") + Singletons() { + // Set the default User Interface language as soon as possible. + // The language used will be derived from the environment + // variables. + messages_["GUI"] = Messages(); } /// our function handler LyXFunc lyxfunc_; @@ -163,20 +171,37 @@ struct LyX::Singletons /// lyx session, containing lastfiles, lastfilepos, and lastopened boost::scoped_ptr session_; + /// Files to load at start. + vector files_to_load_; + + /// The messages translators. + map messages_; + + /// The file converters. + Converters converters_; + + // The system converters copy after reading lyxrc.defaults. + Converters system_converters_; + + /// + Movers movers_; + /// - IconvProcessor iconv; + Movers system_movers_; }; +/// +frontend::Application * theApp() +{ + if (singleton_) + return singleton_->pimpl_->application_.get(); + else + return 0; +} + LyX::~LyX() { - // Static data are not treated in the same way at all on the Mac (and - // the LyX singleton has static methods). This is the reason why the - // exit command on the Mac bypasses our dispatch machinery altogether. - // On Linux and Windows we won't pass a second time through quit() - // because quitting will already be set to true. - if (!quitting) - quit(); } @@ -290,9 +315,15 @@ kb_keymap & LyX::topLevelKeymap() } -IconvProcessor & LyX::iconvProcessor() +Converters & LyX::converters() { - return pimpl_->iconv; + return pimpl_->converters_; +} + + +Converters & LyX::systemConverters() +{ + return pimpl_->system_converters_; } @@ -303,6 +334,33 @@ kb_keymap const & LyX::topLevelKeymap() const } +Messages & LyX::getMessages(std::string const & language) +{ + map::iterator it = pimpl_->messages_.find(language); + + if (it != pimpl_->messages_.end()) + return it->second; + + std::pair::iterator, bool> result = + pimpl_->messages_.insert(std::make_pair(language, Messages(language))); + + BOOST_ASSERT(result.second); + return result.first->second; +} + + +Messages & LyX::getGuiMessages() +{ + return pimpl_->messages_["GUI"]; +} + + +void LyX::setGuiLanguage(std::string const & language) +{ + pimpl_->messages_["GUI"] = Messages(language); +} + + Buffer const * const LyX::updateInset(InsetBase const * inset) const { if (!inset) @@ -328,19 +386,28 @@ int LyX::exec(int & argc, char * argv[]) // we need to parse for "-dbg" and "-help" easyParse(argc, argv); - support::init_package(argv[0], cl_system_support, cl_user_support, - support::top_build_dir_is_one_level_up); + try { support::init_package(to_utf8(from_local8bit(argv[0])), + cl_system_support, cl_user_support, + support::top_build_dir_is_one_level_up); + } catch (support::ExceptionMessage const & message) { + if (message.type_ == support::ErrorException) { + Alert::error(message.title_, message.details_); + exit(1); + } else if (message.type_ == support::WarningException) { + Alert::warning(message.title_, message.details_); + } + } - vector files; - if (!use_gui) { // FIXME: create a ConsoleApplication - int exit_status = loadFiles(argc, argv, files); + int exit_status = init(argc, argv); if (exit_status) { prepareExit(); return exit_status; } + loadFiles(); + if (batch_command.empty() || pimpl_->buffer_list_.empty()) { prepareExit(); return EXIT_SUCCESS; @@ -361,18 +428,16 @@ int LyX::exec(int & argc, char * argv[]) } // Force adding of font path _before_ Application is initialized - support::addFontResources(); + support::os::addFontResources(); // Let the frontend parse and remove all arguments that it knows pimpl_->application_.reset(createApplication(argc, argv)); - // FIXME: this global pointer should probably go. - theApp = pimpl_->application_.get(); initGuiFont(); // Parse and remove all known arguments in the LyX singleton // Give an error for all remaining ones. - int exit_status = loadFiles(argc, argv, files); + int exit_status = init(argc, argv); if (exit_status) { // Kill the application object before exiting. pimpl_->application_.reset(); @@ -381,9 +446,6 @@ int LyX::exec(int & argc, char * argv[]) return exit_status; } - restoreGuiSession(files); - // Start the real execution loop. - // FIXME /* Create a CoreApplication class that will provide the main event loop * and the socket callback registering. With Qt4, only QtCore @@ -391,21 +453,19 @@ int LyX::exec(int & argc, char * argv[]) * When this is done, a server_mode could be created and the following two * line would be moved out from here. */ + // Note: socket callback must be registered after init(argc, argv) + // such that package().temp_dir() is properly initialized. pimpl_->lyx_server_.reset(new LyXServer(&pimpl_->lyxfunc_, lyxrc.lyxpipes)); pimpl_->lyx_socket_.reset(new LyXServerSocket(&pimpl_->lyxfunc_, - support::os::internal_path(package().temp_dir() + "/lyxsocket"))); + os::internal_path(package().temp_dir() + "/lyxsocket"))); + // Start the real execution loop. exit_status = pimpl_->application_->exec(); - // FIXME: Do we still need this reset? - // I assume it is the reason for strange Mac crashs - // Test by reverting rev 16110 (Peter) - // Kill the application object before exiting. This avoid crash - // on exit on Linux. - pimpl_->application_.reset(); + prepareExit(); // Restore original font resources after Application is destroyed. - support::restoreFontResources(); + support::os::restoreFontResources(); return exit_status; } @@ -421,22 +481,30 @@ void LyX::prepareExit() pimpl_->buffer_list_.closeAll(); // do any other cleanup procedures now - lyxerr[Debug::INFO] << "Deleting tmp dir " << package().temp_dir() << endl; - - // Prevent the deletion of /tmp if LyX was called with invalid - // arguments. Does not work on windows. - // FIXME: Fix the real bug instead. - if (package().temp_dir() == "/tmp") { - lyxerr << "Not deleting /tmp." << endl; - return; + if (package().temp_dir() != package().system_temp_dir()) { + lyxerr[Debug::INFO] << "Deleting tmp dir " + << package().temp_dir() << endl; + + if (!destroyDir(FileName(package().temp_dir()))) { + docstring const msg = + bformat(_("Unable to remove the temporary directory %1$s"), + from_utf8(package().temp_dir())); + Alert::warning(_("Unable to remove temporary directory"), msg); + } } - if (!destroyDir(package().temp_dir())) { - docstring const msg = - bformat(_("Unable to remove the temporary directory %1$s"), - from_utf8(package().temp_dir())); - Alert::warning(_("Unable to remove temporary directory"), msg); + if (use_gui) { + if (pimpl_->session_) + pimpl_->session_->writeFile(); + pimpl_->session_.reset(); + pimpl_->lyx_server_.reset(); + pimpl_->lyx_socket_.reset(); } + + // Kill the application object before exiting. This avoids crashes + // when exiting on Linux. + if (pimpl_->application_) + pimpl_->application_.reset(); } @@ -450,25 +518,7 @@ void LyX::earlyExit(int status) } -void LyX::quit() -{ - lyxerr[Debug::INFO] << "Running QuitLyX." << endl; - - prepareExit(); - if (use_gui) { - if (pimpl_->session_) - pimpl_->session_->writeFile(); - pimpl_->lyx_server_.reset(); - pimpl_->lyx_socket_.reset(); - if (pimpl_->application_) - pimpl_->application_->exit(0); - theApp = 0; - } -} - - -int LyX::loadFiles(int & argc, char * argv[], - vector & files) +int LyX::init(int & argc, char * argv[]) { // check for any spurious extra arguments // other than documents @@ -489,52 +539,49 @@ int LyX::loadFiles(int & argc, char * argv[], return EXIT_FAILURE; for (int argi = argc - 1; argi >= 1; --argi) { - // check for any remaining extra arguments other than - // document file names. These will be passed out to the - // frontend. - if (argv[argi][0] == '-') - continue; - files.push_back(os::internal_path(argv[argi])); + // get absolute path of file and add ".lyx" to + // the filename if necessary + pimpl_->files_to_load_.push_back(fileSearch(string(), + os::internal_path(to_utf8(from_local8bit(argv[argi]))), + "lyx", support::allow_unreadable)); } if (first_start) - files.push_back(i18nLibFileSearch("examples", "splash.lyx").absFilename()); + pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx")); - Buffer * last_loaded = 0; + return EXIT_SUCCESS; +} - vector::const_iterator it = files.begin(); - vector::const_iterator end = files.end(); + +void LyX::loadFiles() +{ + vector::const_iterator it = pimpl_->files_to_load_.begin(); + vector::const_iterator end = pimpl_->files_to_load_.end(); for (; it != end; ++it) { - // get absolute path of file and add ".lyx" to - // the filename if necessary - string s = fileSearch(string(), *it, "lyx").absFilename(); - if (s.empty()) { - Buffer * const b = newFile(*it, string(), true); - if (b) - last_loaded = b; - } else { - Buffer * buf = pimpl_->buffer_list_.newBuffer(s, false); - if (loadLyXFile(buf, s)) { - last_loaded = buf; - ErrorList const & el = buf->errorList("Parse"); - if (!el.empty()) - for_each(el.begin(), el.end(), - boost::bind(&LyX::printError, this, _1)); - } - else - pimpl_->buffer_list_.release(buf); + if (it->empty()) + continue; + + Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false); + if (loadLyXFile(buf, *it)) { + ErrorList const & el = buf->errorList("Parse"); + if (!el.empty()) + for_each(el.begin(), el.end(), + boost::bind(&LyX::printError, this, _1)); } + else + pimpl_->buffer_list_.release(buf); } - - files.clear(); // the files are already loaded - - return EXIT_SUCCESS; } void LyX::execBatchCommands() { + // The advantage of doing this here is that the event loop + // is already started. So any need for interaction will be + // aknowledged. + restoreGuiSession(); + // Execute batch commands if available if (batch_command.empty()) return; @@ -546,23 +593,32 @@ void LyX::execBatchCommands() } -void LyX::restoreGuiSession(vector const & files) +void LyX::restoreGuiSession() { LyXView * view = newLyXView(); - // load files - for_each(files.begin(), files.end(), - bind(&LyXView::loadLyXFile, view, _1, true)); - - // if a file is specified, I assume that user wants to edit *that* file - if (files.empty() && lyxrc.load_session) { - vector const & lastopened = pimpl_->session_->lastOpened().getfiles(); - // do not add to the lastfile list since these files are restored from - // last seesion, 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)); + // if some files were specified at command-line we assume that the + // user wants to edit *these* files and not to restore the session. + if (!pimpl_->files_to_load_.empty()) { + for_each(pimpl_->files_to_load_.begin(), + pimpl_->files_to_load_.end(), + 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; + + vector 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)); + // clear this list to save a few bytes of RAM pimpl_->session_->lastOpened().clear(); } @@ -772,6 +828,9 @@ bool LyX::init() if (!readRcFile("lyxrc.dist")) return false; + // Set the language defined by the distributor. + //setGuiLanguage(lyxrc.gui_language); + // Set the PATH correctly. #if !defined (USE_POSIX_PACKAGING) // Add the directory containing the LyX executable to the path @@ -803,15 +862,15 @@ bool LyX::init() system_lyxrc = lyxrc; system_formats = formats; - system_converters = converters; - system_movers = movers; + pimpl_->system_converters_ = pimpl_->converters_; + pimpl_->system_movers_ = pimpl_->movers_; system_lcolor = lcolor; // This one is edited through the preferences dialog. if (!readRcFile("preferences")) return false; - if (!readEncodingsFile("encodings")) + if (!readEncodingsFile("encodings", "unicodesymbols")) return false; if (!readLanguagesFile("languages")) return false; @@ -822,6 +881,9 @@ bool LyX::init() return false; if (use_gui) { + // Set the language defined by the user. + //setGuiLanguage(lyxrc.gui_language); + // Set up bindings pimpl_->toplevel_keymap_.reset(new kb_keymap); defaultKeyBindings(pimpl_->toplevel_keymap_.get()); @@ -841,8 +903,9 @@ bool LyX::init() if (!lyxrc.path_prefix.empty()) prependEnvPath("PATH", lyxrc.path_prefix); - if (fs::exists(lyxrc.document_path) && - fs::is_directory(lyxrc.document_path)) + FileName const document_path(lyxrc.document_path); + if (fs::exists(document_path.toFilesystemEncoding()) && + fs::is_directory(document_path.toFilesystemEncoding())) package().document_dir() = lyxrc.document_path; package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path)).absFilename(); @@ -975,11 +1038,19 @@ namespace { // return true if file does not exist or is older than configure.py. bool needsUpdate(string const & file) { - static string const configure_script = - addName(package().system_support(), "configure.py"); - string const absfile = - addName(package().user_support(), file); + // We cannot initialize configure_script directly because the package + // is not initialized yet when static objects are constructed. + static string configure_script; + static bool firstrun = true; + if (firstrun) { + configure_script = FileName(addName( + package().system_support(), + "configure.py")).toFilesystemEncoding(); + firstrun = false; + } + string const absfile = FileName(addName( + package().user_support(), file)).toFilesystemEncoding(); return (! fs::exists(absfile)) || (fs::last_write_time(configure_script) > fs::last_write_time(absfile)); @@ -991,8 +1062,9 @@ bool needsUpdate(string const & file) bool LyX::queryUserLyXDir(bool explicit_userdir) { // Does user directory exist? - if (fs::exists(package().user_support()) && - fs::is_directory(package().user_support())) { + string const user_support = + FileName(package().user_support()).toFilesystemEncoding(); + if (fs::exists(user_support) && fs::is_directory(user_support)) { first_start = false; return needsUpdate("lyxrc.defaults") @@ -1054,7 +1126,7 @@ bool LyX::readRcFile(string const & name) // Read the ui file `name' -bool LyX::readUIFile(string const & name) +bool LyX::readUIFile(string const & name, bool include) { enum Uitags { ui_menuset = 1, @@ -1086,13 +1158,23 @@ bool LyX::readUIFile(string const & name) lyxerr[Debug::INIT] << "About to read " << name << "..." << endl; - FileName const ui_path = libFileSearch("ui", name, "ui"); - + + FileName ui_path; + if (include) { + ui_path = libFileSearch("ui", name, "inc"); + if (ui_path.empty()) + ui_path = libFileSearch("ui", + changeExtension(name, "inc")); + } + else + ui_path = libFileSearch("ui", name, "ui"); + if (ui_path.empty()) { lyxerr[Debug::INIT] << "Could not find " << name << endl; showFileError(name); return false; } + uifiles.push_back(name); lyxerr[Debug::INIT] << "Found " << name @@ -1112,7 +1194,7 @@ bool LyX::readUIFile(string const & name) case ui_include: { lex.next(true); string const file = lex.getString(); - if (!readUIFile(file)) + if (!readUIFile(file, true)) return false; break; } @@ -1155,16 +1237,24 @@ bool LyX::readLanguagesFile(string const & name) // Read the encodings file `name' -bool LyX::readEncodingsFile(string const & name) +bool LyX::readEncodingsFile(string const & enc_name, + string const & symbols_name) { - lyxerr[Debug::INIT] << "About to read " << name << "..." << endl; + lyxerr[Debug::INIT] << "About to read " << enc_name << " and " + << symbols_name << "..." << endl; + + FileName const symbols_path = libFileSearch(string(), symbols_name); + if (symbols_path.empty()) { + showFileError(symbols_name); + return false; + } - FileName const enc_path = libFileSearch(string(), name); + FileName const enc_path = libFileSearch(string(), enc_name); if (enc_path.empty()) { - showFileError(name); + showFileError(enc_name); return false; } - encodings.read(enc_path); + encodings.read(enc_path, symbols_path); return true; } @@ -1230,7 +1320,8 @@ int parse_version(string const &, string const &) int parse_sysdir(string const & arg, string const &) { if (arg.empty()) { - lyxerr << to_utf8(_("Missing directory for -sysdir switch")) << endl; + Alert::error(_("No system directory"), + _("Missing directory for -sysdir switch")); exit(1); } cl_system_support = arg; @@ -1240,7 +1331,8 @@ int parse_sysdir(string const & arg, string const &) int parse_userdir(string const & arg, string const &) { if (arg.empty()) { - lyxerr << to_utf8(_("Missing directory for -userdir switch")) << endl; + Alert::error(_("No user directory"), + _("Missing directory for -userdir switch")); exit(1); } cl_user_support = arg; @@ -1250,7 +1342,8 @@ int parse_userdir(string const & arg, string const &) int parse_execute(string const & arg, string const &) { if (arg.empty()) { - lyxerr << to_utf8(_("Missing command string after --execute switch")) << endl; + Alert::error(_("Incomplete command"), + _("Missing command string after --execute switch")); exit(1); } batch = arg; @@ -1328,8 +1421,8 @@ void LyX::easyParse(int & argc, char * argv[]) if (it == cmdmap.end()) continue; - string arg((i + 1 < argc) ? argv[i + 1] : ""); - string arg2((i + 2 < argc) ? argv[i + 2] : ""); + string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string()); + string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string()); int const remove = 1 + it->second(arg, arg2); @@ -1394,9 +1487,51 @@ kb_keymap & theTopLevelKeymap() } -IconvProcessor & utf8ToUcs4() +Converters & theConverters() +{ + return LyX::ref().converters(); +} + + +Converters & theSystemConverters() +{ + return LyX::ref().systemConverters(); +} + + +Movers & theMovers() +{ + return LyX::ref().pimpl_->movers_; +} + + +Mover const & getMover(std::string const & fmt) +{ + return LyX::ref().pimpl_->movers_(fmt); +} + + +void setMover(std::string const & fmt, std::string const & command) +{ + LyX::ref().pimpl_->movers_.set(fmt, command); +} + + +Movers & theSystemMovers() +{ + return LyX::ref().pimpl_->system_movers_; +} + + +Messages & getMessages(std::string const & language) +{ + return LyX::ref().getMessages(language); +} + + +Messages & getGuiMessages() { - return LyX::ref().iconvProcessor(); + return LyX::ref().getGuiMessages(); } } // namespace lyx