]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
Kornel's gcc compile fix.
[lyx.git] / src / Buffer.cpp
index c97a6cddf4d0969f30a58f21874c17e1555d4cb4..94f46af094bb7b2b7cd3878eb17b03541a20f7cc 100644 (file)
@@ -42,6 +42,7 @@
 #include "Lexer.h"
 #include "LyXAction.h"
 #include "LyX.h"
+#include "LyXFunc.h"
 #include "LyXRC.h"
 #include "LyXVC.h"
 #include "output_docbook.h"
@@ -126,7 +127,7 @@ namespace {
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-int const LYX_FORMAT = 369; // vfr: add author ids to list of authors
+int const LYX_FORMAT = 370; // uwestoehr: option to suppress default date
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -312,7 +313,7 @@ Buffer::~Buffer()
        // GuiView already destroyed
        gui_ = 0;
 
-       if (d->unnamed && d->filename.extension() == "internal") {
+       if (isInternal()) {
                // No need to do additional cleanups for internal buffer.
                delete d;
                return;
@@ -328,6 +329,12 @@ Buffer::~Buffer()
                        theBufferList().releaseChild(this, child);
        }
 
+       if (!isClean()) {
+               docstring msg = _("LyX attempted to close a document that had unsaved changes!\n");
+               msg += emergencyWrite();
+               frontend::Alert::warning(_("Attempting to close changed document!"), msg);
+       }
+               
        // clear references to children in macro tables
        d->children_positions.clear();
        d->position_to_children.clear();
@@ -687,6 +694,9 @@ bool Buffer::readDocument(Lexer & lex)
                        }
                }
        }
+       
+       // assure we have a default index
+       params().indiceslist().addDefault(B_("Index"));
 
        // read main text
        bool const res = text().read(lex, errorList, d->inset);
@@ -942,6 +952,63 @@ bool Buffer::writeFile(FileName const & fname) const
 }
 
 
+docstring Buffer::emergencyWrite()
+{
+       // No need to save if the buffer has not changed.
+       if (isClean())
+               return docstring();
+
+       string const doc = isUnnamed() ? onlyFilename(absFileName()) : absFileName();
+
+       docstring user_message = bformat(
+               _("LyX: Attempting to save document %1$s\n"), from_utf8(doc));
+
+       // We try to save three places:
+       // 1) Same place as document. Unless it is an unnamed doc.
+       if (!isUnnamed()) {
+               string s = absFileName();
+               s += ".emergency";
+               LYXERR0("  " << s);
+               if (writeFile(FileName(s))) {
+                       markClean();
+                       user_message += bformat(_("  Saved to %1$s. Phew.\n"), from_utf8(s));
+                       return user_message;
+               } else {
+                       user_message += _("  Save failed! Trying again...\n");
+               }
+       }
+
+       // 2) In HOME directory.
+       string s = addName(package().home_dir().absFilename(), absFileName());
+       s += ".emergency";
+       lyxerr << ' ' << s << endl;
+       if (writeFile(FileName(s))) {
+               markClean();
+               user_message += bformat(_("  Saved to %1$s. Phew.\n"), from_utf8(s));
+               return user_message;
+       }
+
+       user_message += _("  Save failed! Trying yet again...\n");
+
+       // 3) In "/tmp" directory.
+       // MakeAbsPath to prepend the current
+       // drive letter on OS/2
+       s = addName(package().temp_dir().absFilename(), absFileName());
+       s += ".emergency";
+       lyxerr << ' ' << s << endl;
+       if (writeFile(FileName(s))) {
+               markClean();
+               user_message += bformat(_("  Saved to %1$s. Phew.\n"), from_utf8(s));
+               return user_message;
+       }
+
+       user_message += _("  Save failed! Bummer. Document is lost.");
+       // Don't try again.
+       markClean();
+       return user_message;
+}
+
+
 bool Buffer::write(ostream & ofs) const
 {
 #ifdef HAVE_LOCALE
@@ -1567,23 +1634,73 @@ void Buffer::markDepClean(string const & name)
 
 bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 {
+       if (isInternal()) {
+               // FIXME? if there is an Buffer LFUN that can be dispatched even
+               // if internal, put a switch '(cmd.action)' here.
+               return false;
+       }
+
+       bool enable = true;
+
        switch (cmd.action) {
+
+               case LFUN_BUFFER_TOGGLE_READ_ONLY:
+                       flag.setOnOff(isReadonly());
+                       break;
+
+               // FIXME: There is need for a command-line import.
+               //case LFUN_BUFFER_IMPORT:
+
+               case LFUN_BUFFER_AUTO_SAVE:
+                       break;
+
+               case LFUN_BUFFER_EXPORT_CUSTOM:
+                       // FIXME: Nothing to check here?
+                       break;
+
                case LFUN_BUFFER_EXPORT: {
                        docstring const arg = cmd.argument();
-                       bool enable = arg == "custom" || isExportable(to_utf8(arg));
+                       enable = arg == "custom" || isExportable(to_utf8(arg));
                        if (!enable)
                                flag.message(bformat(
                                        _("Don't know how to export to format: %1$s"), arg));
-                       flag.setEnabled(enable);
                        break;
                }
 
+               case LFUN_MASTER_BUFFER_UPDATE:
+               case LFUN_MASTER_BUFFER_VIEW: 
+                       enable = parent() != 0;
+                       break;
+               case LFUN_BUFFER_UPDATE:
+               case LFUN_BUFFER_VIEW: {
+                       string format = to_utf8(cmd.argument());
+                       if (cmd.argument().empty())
+                               format = getDefaultOutputFormat();
+                       typedef vector<Format const *> Formats;
+                       Formats formats;
+                       formats = exportableFormats(true);
+                       Formats::const_iterator fit = formats.begin();
+                       Formats::const_iterator end = formats.end();
+                       enable = false;
+                       for (; fit != end ; ++fit) {
+                               if ((*fit)->name() == format)
+                                       enable = true;
+                       }
+                       break;
+               }
+               case LFUN_BUFFER_CHKTEX:
+                       enable = isLatex() && !lyxrc.chktex_command.empty();
+                       break;
+
+               case LFUN_BUILD_PROGRAM:
+                       enable = isExportable("program");
+                       break;
+
                case LFUN_BRANCH_ACTIVATE: 
                case LFUN_BRANCH_DEACTIVATE: {
                        BranchList const & branchList = params().branchlist();
                        docstring const branchName = cmd.argument();
-                       flag.setEnabled(!branchName.empty()
-                               && branchList.find(branchName));
+                       enable = !branchName.empty() && branchList.find(branchName);
                        break;
                }
 
@@ -1591,12 +1708,16 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                case LFUN_BRANCHES_RENAME:
                case LFUN_BUFFER_PRINT:
                        // if no Buffer is present, then of course we won't be called!
-                       flag.setEnabled(true);
+                       break;
+
+               case LFUN_BUFFER_LANGUAGE:
+                       enable = !isReadonly();
                        break;
 
                default:
                        return false;
        }
+       flag.setEnabled(enable);
        return true;
 }
 
@@ -1612,12 +1733,32 @@ void Buffer::dispatch(string const & command, DispatchResult & result)
 // whether we have a GUI or not. The boolean use_gui holds this information.
 void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 {
+       if (isInternal()) {
+               // FIXME? if there is an Buffer LFUN that can be dispatched even
+               // if internal, put a switch '(cmd.action)' here.
+               dr.dispatched(false);
+               return;
+       }
+       string const argument = to_utf8(func.argument());
        // We'll set this back to false if need be.
        bool dispatched = true;
+       undo().beginUndoGroup();
 
        switch (func.action) {
+       case LFUN_BUFFER_TOGGLE_READ_ONLY:
+               if (lyxvc().inUse())
+                       lyxvc().toggleReadOnly();
+               else
+                       setReadonly(!isReadonly());
+               break;
+
        case LFUN_BUFFER_EXPORT: {
-               bool success = doExport(to_utf8(func.argument()), false);
+               if (argument == "custom") {
+                       lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
+                       break;
+               }
+               doExport(argument, false);
+               bool success = doExport(argument, false);
                dr.setError(success);
                if (!success)
                        dr.setMessage(bformat(_("Error exporting to format: %1$s."), 
@@ -1625,6 +1766,96 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
+       case LFUN_BUFFER_UPDATE: {
+               string format = argument;
+               if (argument.empty())
+                       format = getDefaultOutputFormat();
+               doExport(format, true);
+               break;
+       }
+
+       case LFUN_BUFFER_VIEW: {
+               string format = argument;
+               if (argument.empty())
+                       format = getDefaultOutputFormat();
+               preview(format);
+               break;
+       }
+
+       case LFUN_MASTER_BUFFER_UPDATE: {
+               string format = argument;
+               if (argument.empty())
+                       format = masterBuffer()->getDefaultOutputFormat();
+               masterBuffer()->doExport(format, true);
+               break;
+       }
+
+       case LFUN_MASTER_BUFFER_VIEW: {
+               string format = argument;
+               if (argument.empty())
+                       format = masterBuffer()->getDefaultOutputFormat();
+               masterBuffer()->preview(format);
+               break;
+       }
+
+       case LFUN_BUILD_PROGRAM:
+               doExport("program", true);
+               break;
+
+       case LFUN_BUFFER_CHKTEX:
+               runChktex();
+               break;
+
+       case LFUN_BUFFER_EXPORT_CUSTOM: {
+               string format_name;
+               string command = split(argument, format_name, ' ');
+               Format const * format = formats.getFormat(format_name);
+               if (!format) {
+                       lyxerr << "Format \"" << format_name
+                               << "\" not recognized!"
+                               << endl;
+                       break;
+               }
+
+               // The name of the file created by the conversion process
+               string filename;
+
+               // Output to filename
+               if (format->name() == "lyx") {
+                       string const latexname = latexName(false);
+                       filename = changeExtension(latexname,
+                               format->extension());
+                       filename = addName(temppath(), filename);
+
+                       if (!writeFile(FileName(filename)))
+                               break;
+
+               } else {
+                       doExport(format_name, true, filename);
+               }
+
+               // Substitute $$FName for filename
+               if (!contains(command, "$$FName"))
+                       command = "( " + command + " ) < $$FName";
+               command = subst(command, "$$FName", filename);
+
+               // Execute the command in the background
+               Systemcall call;
+               call.startscript(Systemcall::DontWait, command);
+               break;
+       }
+
+       // FIXME: There is need for a command-line import.
+       /*
+       case LFUN_BUFFER_IMPORT:
+               doImport(argument);
+               break;
+       */
+
+       case LFUN_BUFFER_AUTO_SAVE:
+               autoSave();
+               break;
+
        case LFUN_BRANCH_ADD: {
                BranchList & branchList = params().branchlist();
                docstring const branchName = func.argument();
@@ -1820,11 +2051,22 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
+       case LFUN_BUFFER_LANGUAGE: {
+               Language const * oldL = params().language;
+               Language const * newL = languages.getLanguage(argument);
+               if (!newL || oldL == newL)
+                       break;
+               if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual())
+                       changeLanguage(oldL, newL);
+               break;
+       }
+
        default:
                dispatched = false;
                break;
        }
        dr.dispatched(dispatched);
+       undo().endUndoGroup();
 }
 
 
@@ -1974,7 +2216,17 @@ bool Buffer::isUnnamed() const
 }
 
 
-// FIXME: this function should be moved to buffer_pimpl.C
+/// \note
+/// Don't check unnamed, here: isInternal() is used in
+/// newBuffer(), where the unnamed flag has not been set by anyone
+/// yet. Also, for an internal buffer, there should be no need for
+/// retrieving fileName() nor for checking if it is unnamed or not.
+bool Buffer::isInternal() const
+{
+       return fileName().extension() == "internal";
+}
+
+
 void Buffer::markDirty()
 {
        if (d->lyx_clean) {