#include <config.h>
-#ifdef __GNUG__
-#pragma implementation
-#endif
-
-#include FORMS_H_LOCATION
#include "lyxvc.h"
-#include "error.h"
-#include "lyx_gui_misc.h"
-#include "bufferlist.h"
-#include "syscall.h"
-#include "pathstack.h"
-#include "filetools.h"
-#include "FileInfo.h"
+#include "vc-backend.h"
+#include "debug.h"
+#include "buffer.h"
+#include "BufferView.h"
#include "gettext.h"
-#include "LyXView.h"
-#include "lyxfunc.h"
-#include "latexoptions.h"
+#include "funcrequest.h"
+
+#include "frontends/Alert.h"
+#include "frontends/LyXView.h"
+
+#include "support/filetools.h"
+#include "support/lyxlib.h"
+
+#include <unistd.h>
-extern BufferList bufferlist;
-extern void MenuWrite(Buffer *);
+using std::endl;
+using std::pair;
-#if 0
-extern bool gsworking();
-#endif
+
+/* WARNING: Several of the vcs-> methods end up
+ * deleting this object via BufferView::reload() !
+ */
LyXVC::LyXVC()
{
- backend = UNKNOWN_VCS;
- _owner = 0;
- browser = 0;
+ vcs = 0;
+ owner_ = 0;
}
LyXVC::~LyXVC()
{
- if (browser) {
- if (browser->LaTeXLog->visible)
- fl_hide_form(browser->LaTeXLog);
- fl_free_form(browser->LaTeXLog);
- }
+ delete vcs;
}
-bool LyXVC::file_found_hook(LString const & fn)
+bool LyXVC::file_found_hook(string const & fn)
{
- LString tmp(fn);
- FileInfo f;
- // Check if *,v exists.
- tmp += ",v";
- lyxerr.debug(LString("Checking if file is under vc: ") + tmp, Error::LYXVC);
- if (f.newFile(tmp).readable()) {
- lyxerr.debug("Yes it is under vc.", Error::LYXVC);
- master = tmp;
- backend = RCS_VCS;
- scanMaster();
+ string found_file;
+ // Check if file is under RCS
+ if (!(found_file = RCS::find_file(fn)).empty()) {
+ vcs = new RCS(found_file);
+ vcs->owner(owner_);
+ return true;
+ }
+ // Check if file is under CVS
+ if (!(found_file = CVS::find_file(fn)).empty()) {
+ vcs = new CVS(found_file, fn);
+ vcs->owner(owner_);
return true;
- } else {
- // Check if RCS/*,v exists.
- tmp = AddName(AddPath(OnlyPath(fn), "RCS"), fn);
- tmp += ",v";
- lyxerr.debug("Checking if file is under vc: " + tmp, Error::LYXVC);
- if (f.newFile(tmp).readable()) {
- lyxerr.debug("Yes it is under vc.", Error::LYXVC);
- master = tmp;
- backend = RCS_VCS;
- scanMaster();
- return true;
- }
}
- // If either one, return true
-
// file is not under any VCS.
return false;
}
-bool LyXVC::file_not_found_hook(LString const &)
+bool LyXVC::file_not_found_hook(string const & fn)
{
- // file is not under any VCS.
+ // Check if file is under RCS
+ if (!RCS::find_file(fn).empty())
+ return true;
+ if (!CVS::find_file(fn).empty())
+ return true;
return false;
}
-void LyXVC::scanMaster()
+void LyXVC::buffer(Buffer * buf)
{
- lyxerr.debug("LyXVC: This file is a VC file.", Error::LYXVC);
-
- LyXLex lex(NULL, 0);
- lex.setFile(master);
-
- LString token;
- bool read_enough = false;
- while (lex.IsOK() && !read_enough) {
- lex.next();
- token = lex.GetString();
-
- lyxerr.debug("LyXVC::scanMaster: current lex text: `"
- +token+"'", Error::LYXVC);
-
- if (token.empty())
- continue;
- else if (token == "head") {
- // get version here
- lex.next();
- LString tmv = lex.GetString();
- tmv.strip(';');
- version = tmv;
- } else if (token.contains("access")
- || token.contains("symbols")
- || token.contains("strict")) {
- // nothing
- } else if (token.contains("locks")) {
- // get locker here
- if (token.contains(";")) {
- locker = "Unlocked";
- vcstat = UNLOCKED;
- continue;
- }
- LString tmpt, s1, s2;
- do {
- lex.next();
- tmpt = lex.GetString();
- s1 = tmpt;
- s1.strip(';');
- // tmp is now in the format <user>:<version>
- s1.split(s2, ':');
- // s2 is user, and s1 is version
- if (s1 == version) {
- locker = s2;
- vcstat = LOCKED;
- break;
- }
- } while (!tmpt.contains(";"));
-
- } else if (token == "comment") {
- // we don't need to read any further than this.
- read_enough = true;
- } else {
- // unexpected
- lyxerr.debug("LyXVC::scanMaster(): unexpected token", Error::LYXVC);
- }
- }
+ owner_ = buf;
}
-void LyXVC::setBuffer(Buffer *buf)
+bool LyXVC::ensureClean()
{
- _owner = buf;
-}
+ if (owner_->isClean())
+ return true;
+
+ string const file = MakeDisplayPath(owner_->fileName(), 30);
+ string text = bformat(_("The document %1$s has unsaved changes.\n\n"
+ "Do you want to save the document?"), file);
+ int const ret = Alert::prompt(_("Save changed document?"),
+ text, 0, 1, _("&Save"), _("&Cancel"));
+ if (ret == 0) {
+ vcs->owner()->getUser()->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
+ }
+
+ return owner_->isClean();
+}
-//
-// I will probably add some backend_xxxx functions later to perform the
-// version control system specific commands. Something like:
-// void backend_revert(<params>) {
-// if (backend == "RCS") {
-// } else if (backend == "CVS") {
-// } else if (backend == "SCCS") {
-// }
-//
-// But for 0.12 we will only support RCS.
-//
void LyXVC::registrer()
{
- // If the document is changed, we might want to save it
- if (!_owner->isLyxClean() &&
- AskQuestion(_("Changes in document:"),
- MakeDisplayPath(_owner->getFileName(),50),
- _("Save document and proceed?"))) {
- MenuWrite(_owner);
+ string const filename = owner_->fileName();
+
+ // there must be a file to save
+ if (!IsFileReadable(filename)) {
+ Alert::error(_("Document not saved"),
+ _("You must save the document "
+ "before it can be registered."));
+ return;
+ }
+
+ // it is very likely here that the vcs is not created yet...
+ if (!vcs) {
+ string const cvs_entries = "CVS/Entries";
+
+ if (IsFileReadable(cvs_entries)) {
+ lyxerr[Debug::LYXVC]
+ << "LyXVC: registering "
+ << MakeDisplayPath(filename)
+ << " with CVS" << endl;
+ vcs = new CVS(cvs_entries, filename);
+
+ } else {
+ lyxerr[Debug::LYXVC]
+ << "LyXVC: registering "
+ << MakeDisplayPath(filename)
+ << " with RCS" << endl;
+ vcs = new RCS(filename);
+ }
+
+ vcs->owner(owner_);
}
// Maybe the save fails, or we answered "no". In both cases,
// the document will be dirty, and we abort.
- if (!_owner->isLyxClean()) {
+ if (!ensureClean())
return;
- }
- lyxerr.debug("LyXVC: registrer", Error::LYXVC);
- LString tmp = askForText(_("LyX VC: Initial description"),
- _("(no initial description)"));
- if (tmp.empty()) {
- lyxerr.debug("LyXVC: user cancelled", Error::LYXVC);
- WriteAlert(_("Info"), _("This document has NOT been registered."));
+ lyxerr[Debug::LYXVC] << "LyXVC: registrer" << endl;
+ pair<bool, string> tmp =
+ Alert::askForText(_("LyX VC: Initial description"),
+ _("(no initial description)"));
+ if (!tmp.first || tmp.second.empty()) {
+ // should we insist on checking tmp.second.empty()?
+ lyxerr[Debug::LYXVC] << "LyXVC: user cancelled" << endl;
return;
}
- LString cmd = "ci -q -u -i -t-\"";
- cmd += tmp;
- cmd += "\" \"";
- cmd += OnlyFilename(_owner->getFileName());
- cmd += "\"";
- doVCCommand(cmd);
- _owner->getUser()->getOwner()->getLyXFunc()->Dispatch("buffer-reload");
+
+ vcs->registrer(tmp.second);
}
void LyXVC::checkIn()
{
// If the document is changed, we might want to save it
- if (!_owner->isLyxClean() &&
- AskQuestion(_("Changes in document:"),
- MakeDisplayPath(_owner->getFileName(),50),
- _("Save document and proceed?"))) {
- MenuWrite(_owner);
+ if (!vcs->owner()->isClean()) {
+ vcs->owner()->getUser()->owner()
+ ->dispatch(FuncRequest(LFUN_MENUWRITE));
}
// Maybe the save fails, or we answered "no". In both cases,
// the document will be dirty, and we abort.
- if (!_owner->isLyxClean()) {
+ if (!vcs->owner()->isClean())
return;
- }
- lyxerr.debug("LyXVC: checkIn", Error::LYXVC);
- _owner->getUser()->getOwner()->getLyXFunc()->Dispatch(LFUN_MENUWRITE);
- LString tmp = askForText(_("LyX VC: Log Message"));
- if (tmp.empty()) tmp = "(no log msg)";
- doVCCommand("ci -q -u -m\"" + tmp + "\" \""
- + OnlyFilename(_owner->getFileName()) + "\"");
- _owner->getUser()->getOwner()->getLyXFunc()->Dispatch("buffer-reload");
+ lyxerr[Debug::LYXVC] << "LyXVC: checkIn" << endl;
+ pair<bool, string> tmp = Alert::askForText(_("LyX VC: Log Message"));
+ if (tmp.first) {
+ if (tmp.second.empty()) {
+ tmp.second = _("(no log message)");
+ }
+ vcs->checkIn(tmp.second);
+ } else {
+ lyxerr[Debug::LYXVC] << "LyXVC: user cancelled" << endl;
+ }
}
void LyXVC::checkOut()
{
- lyxerr.debug("LyXVC: checkOut", Error::LYXVC);
- if (!_owner->isLyxClean()
- && !AskQuestion(_("Changes in document:"),
- MakeDisplayPath(_owner->getFileName(),50),
- _("Ignore changes and proceed with check out?"))) {
+ lyxerr[Debug::LYXVC] << "LyXVC: checkOut" << endl;
+ if (!ensureClean())
return;
- }
- _owner->markLyxClean();
- doVCCommand("co -q -l \""
- + OnlyFilename(_owner->getFileName()) + "\"");
- _owner->getUser()->getOwner()->getLyXFunc()->Dispatch("buffer-reload");
+ vcs->checkOut();
}
void LyXVC::revert()
{
- lyxerr.debug("LyXVC: revert", Error::LYXVC);
- // Here we should check if the buffer is dirty. And if it is
- // we should warn the user that reverting will discard all
- // changes made since the last check in.
- if (AskQuestion(_("When you revert, you will loose all changes made"),
- _("to the document since the last check in."),
- _("Do you still want to do it?"))) {
-
- doVCCommand("co -f -u" + getVersion() + " \""
- + OnlyFilename(_owner->getFileName()) + "\"");
- // We ignore changes and just reload!
- _owner->markLyxClean();
- _owner->getUser()->getOwner()->
- getLyXFunc()->Dispatch("buffer-reload");
- }
+ lyxerr[Debug::LYXVC] << "LyXVC: revert" << endl;
+
+ string const file = MakeDisplayPath(owner_->fileName(), 20);
+ string text = bformat(_("Reverting to the stored version of the "
+ "document %1$s will lose all current changes.\n\n"
+ "Do you want to revert to the saved version?"), file);
+ int const ret = Alert::prompt(_("Revert to stored version of document?"),
+ text, 0, 1, _("&Revert"), _("&Cancel"));
+
+ if (ret == 0)
+ vcs->revert();
}
void LyXVC::undoLast()
{
- lyxerr.debug("LyXVC: undoLast", Error::LYXVC);
- doVCCommand("rcs -o" + getVersion() + " \""
- + OnlyFilename(_owner->getFileName()) + "\"");
+ vcs->undoLast();
}
void LyXVC::toggleReadOnly()
{
- switch (vcstat) {
- case UNLOCKED:
+ switch (vcs->status()) {
+ case VCS::UNLOCKED:
+ lyxerr[Debug::LYXVC] << "LyXVC: toggle to locked" << endl;
checkOut();
break;
- case LOCKED:
+ case VCS::LOCKED:
+ lyxerr[Debug::LYXVC] << "LyXVC: toggle to unlocked" << endl;
checkIn();
break;
}
bool LyXVC::inUse()
{
- if (!master.empty())
- return true;
+ if (vcs) return true;
return false;
}
-LString const LyXVC::getVersion() const
-{
- return version;
-}
+//string const & LyXVC::version() const
+//{
+// return vcs->version();
+//}
-
-LString const LyXVC::getLocker() const
+string const LyXVC::versionString() const
{
- return locker;
-}
-
-// This is a hack anyway so I'll put it here in the mean time.
-void LyXVC::logClose(FL_OBJECT *obj, long)
-{
- LyXVC *This = (LyXVC*)obj->form->u_vdata;
- fl_hide_form(This->browser->LaTeXLog);
+ return vcs->versionString();
}
-void LyXVC::logUpdate(FL_OBJECT *obj, long)
+string const & LyXVC::locker() const
{
- LyXVC *This = (LyXVC*)obj->form->u_vdata;
- This->showLog();
+ return vcs->locker();
}
-void LyXVC::viewLog(LString const & fil)
+const string LyXVC::getLogFile() const
{
- if (!browser) {
- FL_OBJECT *obj;
- browser = (FD_LaTeXLog *) fl_calloc(1, sizeof(*browser));
-
- browser->LaTeXLog = fl_bgn_form(FL_NO_BOX, 470, 380);
- browser->LaTeXLog->u_vdata = (void*)this;
- obj = fl_add_box(FL_UP_BOX, 0, 0, 470, 380, "");
- browser->browser_latexlog = fl_add_browser(FL_NORMAL_BROWSER, 10, 10, 450, 320, "");
- obj = fl_add_button(FL_RETURN_BUTTON, 270, 340, 90, 30, _("Close"));
- fl_set_object_lsize(obj, FL_NORMAL_SIZE);
- fl_set_object_callback(obj, logClose, 0);
- obj = fl_add_button(FL_NORMAL_BUTTON,370,340,90,30,
- idex(_("Update|#Uu")));
- fl_set_button_shortcut(obj,scex(_("Update|#Uu")),1);
- fl_set_object_lsize(obj,FL_NORMAL_SIZE);
- fl_set_object_callback(obj,logUpdate,0);
- fl_end_form();
- fl_set_form_atclose(browser->LaTeXLog, CancelCloseBoxCB, NULL);
- }
-
- if (!fl_load_browser(browser->browser_latexlog, fil.c_str()))
- fl_add_browser_line(browser->browser_latexlog, _("No RCS History!"));
-
- if (browser->LaTeXLog->visible) {
- fl_raise_form(browser->LaTeXLog);
- } else {
- fl_show_form(browser->LaTeXLog,
- FL_PLACE_MOUSE | FL_FREE_SIZE, FL_FULLBORDER,
- _("RCS History"));
- }
-}
-
+ if (!vcs)
+ return string();
-void LyXVC::showLog()
-{
- // This I really don't like, but we'll look at this problem
- // in 0.13. Then we can make a clean solution.
-#if 0
- if (gsworking()) {
- WriteAlert(_("Sorry, can't do this while"
- " pictures are being rendered."),
- _("Please wait a few seconds for"
- " this to finish and try again."),
- _("(or kill runaway gs processes"
- " by hand and try again.)"));
- return;
- }
- extern pid_t isp_pid; // from spellchecker.C
- if(isp_pid != -1) {
- WriteAlert(_("Can't do this while the"
- " spellchecker is running."),
- _("Stop the spellchecker first."));
- return;
- }
-#endif
- LString tmpf = tmpnam(NULL);
- doVCCommand("rlog \""
- + OnlyFilename(_owner->getFileName()) + "\" > " + tmpf);
- viewLog(tmpf);
- unlink(tmpf.c_str());
-}
-
-
-int LyXVC::doVCCommand(LString const & cmd)
-{
- lyxerr.debug("doVCCommand: " + cmd, Error::LYXVC);
- Systemcalls one;
- PathPush(_owner->filepath);
- int ret = one.Startscript(Systemcalls::System, cmd);
- PathPop();
- return ret;
+ string tmpf = lyx::tempName(string(), "lyxvclog");
+ lyxerr[Debug::LYXVC] << "Generating logfile " << tmpf << endl;
+ vcs->getLog(tmpf);
+ return tmpf;
}