#include "lyxsocket.h"
#include "lyxtextclasslist.h"
#include "MenuBackend.h"
+#include "messages.h"
#include "mover.h"
#include "ToolbarBackend.h"
#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 <boost/bind.hpp>
#include <boost/filesystem/operations.hpp>
#include <iostream>
#include <csignal>
+#include <map>
+#include <string>
+#include <vector>
namespace lyx {
using support::addName;
using support::addPath;
using support::bformat;
+using support::changeExtension;
using support::createDirectory;
using support::createLyXTmpDir;
using support::destroyDir;
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;
/// 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_;
/// lyx session, containing lastfiles, lastfilepos, and lastopened
boost::scoped_ptr<Session> session_;
+ /// Files to load at start.
+ vector<FileName> files_to_load_;
+
+ /// The messages translators.
+ map<string, Messages> 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_->application();
+ 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();
}
{
singleton_ = this;
pimpl_.reset(new Singletons);
- geometryArg.clear();
}
}
-IconvProcessor & LyX::iconvProcessor()
+Converters & LyX::converters()
{
- return pimpl_->iconv;
+ return pimpl_->converters_;
+}
+
+
+Converters & LyX::systemConverters()
+{
+ return pimpl_->system_converters_;
}
}
+Messages & LyX::getMessages(std::string const & language)
+{
+ map<string, Messages>::iterator it = pimpl_->messages_.find(language);
+
+ if (it != pimpl_->messages_.end())
+ return it->second;
+
+ std::pair<map<string, Messages>::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)
// 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<string> 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;
}
// 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));
// 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();
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
* 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;
}
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();
}
}
-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);
- }
-}
-
-
-int LyX::loadFiles(int & argc, char * argv[],
- vector<string> & files)
+int LyX::init(int & argc, char * argv[])
{
// check for any spurious extra arguments
// other than documents
}
// Initialization of LyX (reads lyxrc and more)
- lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
+ LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
bool success = init();
- lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
+ LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
if (!success)
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<string>::const_iterator it = files.begin();
- vector<string>::const_iterator end = files.end();
+
+void LyX::loadFiles()
+{
+ vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
+ vector<FileName>::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;
- lyxerr[Debug::INIT] << "About to handle -x '"
+ LYXERR(Debug::INIT) << "About to handle -x '"
<< batch_command << '\'' << endl;
pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
}
-void LyX::restoreGuiSession(vector<string> 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<string> 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<FileName> 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();
}
unsigned int height = 510;
// default icon size, will be overwritten by stored session value
unsigned int iconSizeXY = 0;
- bool maximize = false;
+ int maximized = LyXView::NotMaximized;
// first try lyxrc
if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
width = lyxrc.geometry_width;
val = session().sessionInfo().load("WindowHeight");
if (!val.empty())
height = convert<unsigned int>(val);
- if (session().sessionInfo().load("WindowIsMaximized") == "yes")
- maximize = true;
+ val = session().sessionInfo().load("WindowMaximized");
+ if (!val.empty())
+ maximized = convert<int>(val);
val = session().sessionInfo().load("IconSizeXY");
if (!val.empty())
iconSizeXY = convert<unsigned int>(val);
}
// create the main window
- LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximize, iconSizeXY, geometryArg);
+ LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximized, iconSizeXY, geometryArg);
return view;
}
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
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;
// Load the layouts
- lyxerr[Debug::INIT] << "Reading layouts..." << endl;
+ LYXERR(Debug::INIT) << "Reading layouts..." << endl;
if (!LyXSetStyle())
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());
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();
lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
}
- lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
+ LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
// This must happen after package initialization and after lyxrc is
// 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));
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")
bool LyX::readRcFile(string const & name)
{
- lyxerr[Debug::INIT] << "About to read " << name << "... ";
+ LYXERR(Debug::INIT) << "About to read " << name << "... ";
FileName const lyxrc_path = libFileSearch(string(), name);
if (!lyxrc_path.empty()) {
- lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
+ LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
if (lyxrc.read(lyxrc_path) < 0) {
showFileError(name);
return false;
}
} else
- lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
+ LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
return true;
}
// Read the ui file `name'
-bool LyX::readUIFile(string const & name)
+bool LyX::readUIFile(string const & name, bool include)
{
enum Uitags {
ui_menuset = 1,
std::list<string>::const_iterator end = uifiles.end();
it = std::find(it, end, name);
if (it != end) {
- lyxerr[Debug::INIT] << "UI file '" << name
+ LYXERR(Debug::INIT) << "UI file '" << name
<< "' has been read already. "
<< "Is this an include loop?"
<< endl;
return false;
}
- lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
-
- FileName const ui_path = libFileSearch("ui", name, "ui");
+ LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
+
+ 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;
+ LYXERR(Debug::INIT) << "Could not find " << name << endl;
showFileError(name);
return false;
}
+
uifiles.push_back(name);
- lyxerr[Debug::INIT] << "Found " << name
+ LYXERR(Debug::INIT) << "Found " << name
<< " in " << ui_path << endl;
LyXLex lex(uitags, ui_last - 1);
lex.setFile(ui_path);
case ui_include: {
lex.next(true);
string const file = lex.getString();
- if (!readUIFile(file))
+ if (!readUIFile(file, true))
return false;
break;
}
// Read the languages file `name'
bool LyX::readLanguagesFile(string const & name)
{
- lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
+ LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
FileName const lang_path = libFileSearch(string(), name);
if (lang_path.empty()) {
// 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;
}
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;
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;
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;
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);
}
-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