-#include <config.h>
+/**
+ * \file lyxvc.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ * \author Angus Leeming
+ * \author John Levon
+ * \author André Pönitz
+ * \author Allan Rae
+ *
+ * Full author contact details are available in file CREDITS.
+ */
-#ifdef __GNUG__
-#pragma implementation
-#endif
+#include <config.h>
-#include FORMS_H_LOCATION
#include "lyxvc.h"
+#include "vc-backend.h"
#include "debug.h"
-#include "lyx_gui_misc.h"
-#include "bufferlist.h"
-#include "support/syscall.h"
-#include "pathstack.h"
-#include "support/filetools.h"
-#include "support/FileInfo.h"
+#include "buffer.h"
#include "gettext.h"
-#include "LyXView.h"
-#include "lyxfunc.h"
-#include "latexoptions.h"
-extern BufferList bufferlist;
-extern void MenuWrite(Buffer *);
+#include "frontends/Alert.h"
+
+#include "support/filetools.h"
+#include "support/lyxlib.h"
+
+using lyx::support::bformat;
+using lyx::support::IsFileReadable;
+using lyx::support::MakeDisplayPath;
+using lyx::support::tempName;
+
+using std::endl;
+using std::string;
+using std::pair;
-#if 0
-extern bool gsworking();
-#endif
LyXVC::LyXVC()
{
- backend = UNKNOWN_VCS;
- _owner = 0;
- browser = 0;
+ owner_ = 0;
}
+// for the sake of boost::scoped_ptr
LyXVC::~LyXVC()
-{
- if (browser) {
- if (browser->LaTeXLog->visible)
- fl_hide_form(browser->LaTeXLog);
- fl_free_form(browser->LaTeXLog);
- }
-}
+{}
bool LyXVC::file_found_hook(string const & fn)
{
- string tmp(fn);
- FileInfo f;
- // Check if *,v exists.
- tmp += ",v";
- lyxerr[Debug::LYXVC] << "Checking if file is under vc: "
- << tmp << endl;
- if (f.newFile(tmp).readable()) {
- lyxerr[Debug::LYXVC] << "Yes it is under vc." << endl;
- master = tmp;
- backend = RCS_VCS;
- scanMaster();
+ string found_file;
+ // Check if file is under RCS
+ if (!(found_file = RCS::find_file(fn)).empty()) {
+ vcs.reset(new RCS(found_file));
+ vcs->owner(owner_);
+ return true;
+ }
+ // Check if file is under CVS
+ if (!(found_file = CVS::find_file(fn)).empty()) {
+ vcs.reset(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::LYXVC] << "Checking if file is under vc: "
- << tmp << endl;
- if (f.newFile(tmp).readable()) {
- lyxerr[Debug::LYXVC] << "Yes it is under vc."<< endl;
- 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(string 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] << "LyXVC: This file is a VC file." << endl;
-
- LyXLex lex(0, 0);
- lex.setFile(master);
-
- string token;
- bool read_enough = false;
- while (lex.IsOK() && !read_enough) {
- lex.next();
- token = lex.GetString();
-
- lyxerr[Debug::LYXVC] <<"LyXVC::scanMaster: current lex text: `"
- << token << "'" << endl;
-
- if (token.empty())
- continue;
- else if (token == "head") {
- // get version here
- lex.next();
- string tmv = strip(lex.GetString(), ';');
- version = tmv;
- } else if (contains(token, "access")
- || contains(token, "symbols")
- || contains(token, "strict")) {
- // nothing
- } else if (contains(token, "locks")) {
- // get locker here
- if (contains(token, ";")) {
- locker = "Unlocked";
- vcstat = UNLOCKED;
- continue;
- }
- string tmpt, s1, s2;
- do {
- lex.next();
- s1 = strip(tmpt = lex.GetString(), ';');
- // tmp is now in the format <user>:<version>
- s1 = split(s1, s2, ':');
- // s2 is user, and s1 is version
- if (s1 == version) {
- locker = s2;
- vcstat = LOCKED;
- break;
- }
- } while (!contains(tmpt, ";"));
-
- } else if (token == "comment") {
- // we don't need to read any further than this.
- read_enough = true;
- } else {
- // unexpected
- lyxerr[Debug::LYXVC]
- << "LyXVC::scanMaster(): unexpected token"
- << endl;
- }
- }
+ owner_ = buf;
}
-void LyXVC::setBuffer(Buffer *buf)
+void LyXVC::registrer()
{
- _owner = buf;
-}
+ 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;
+ }
-//
-// 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.
-//
+ // it is very likely here that the vcs is not created yet...
+ if (!vcs) {
+ string const cvs_entries = "CVS/Entries";
-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);
- }
+ if (IsFileReadable(cvs_entries)) {
+ lyxerr[Debug::LYXVC]
+ << "LyXVC: registering "
+ << MakeDisplayPath(filename)
+ << " with CVS" << endl;
+ vcs.reset(new CVS(cvs_entries, filename));
- // Maybe the save fails, or we answered "no". In both cases,
- // the document will be dirty, and we abort.
- if (!_owner->isLyxClean()) {
- return;
+ } else {
+ lyxerr[Debug::LYXVC]
+ << "LyXVC: registering "
+ << MakeDisplayPath(filename)
+ << " with RCS" << endl;
+ vcs.reset(new RCS(filename));
+ }
+
+ vcs->owner(owner_);
}
lyxerr[Debug::LYXVC] << "LyXVC: registrer" << endl;
- string tmp = askForText(_("LyX VC: Initial description"),
- _("(no initial description)"));
- if (tmp.empty()) {
+ 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;
- WriteAlert(_("Info"), _("This document has NOT been registered."));
return;
}
- string 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);
- }
-
- // Maybe the save fails, or we answered "no". In both cases,
- // the document will be dirty, and we abort.
- if (!_owner->isLyxClean()) {
- return;
- }
lyxerr[Debug::LYXVC] << "LyXVC: checkIn" << endl;
- _owner->getUser()->getOwner()->getLyXFunc()->Dispatch(LFUN_MENUWRITE);
- string 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");
+ 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] << "LyXVC: checkOut" << endl;
- if (!_owner->isLyxClean()
- && !AskQuestion(_("Changes in document:"),
- MakeDisplayPath(_owner->getFileName(),50),
- _("Ignore changes and proceed with check out?"))) {
- 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] << "LyXVC: revert" << endl;
- // 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");
- }
+
+ 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] << "LyXVC: undoLast" << endl;
- 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;
}
-string const LyXVC::getVersion() const
-{
- return version;
-}
-
-
-string const LyXVC::getLocker() const
-{
- return locker;
-}
+//string const & LyXVC::version() const
+//{
+// return vcs->version();
+//}
-// This is a hack anyway so I'll put it here in the mean time.
-void LyXVC::logClose(FL_OBJECT *obj, long)
+string const LyXVC::versionString() const
{
- 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(string const & fil)
+string const 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, 0);
- }
-
- 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
- string tmpf = tmpnam(0);
- doVCCommand("rlog \""
- + OnlyFilename(_owner->getFileName()) + "\" > " + tmpf);
- viewLog(tmpf);
- unlink(tmpf.c_str());
-}
-
-
-int LyXVC::doVCCommand(string const & cmd)
-{
- lyxerr[Debug::LYXVC] << "doVCCommand: " << cmd << endl;
- Systemcalls one;
- PathPush(_owner->filepath);
- int ret = one.Startscript(Systemcalls::System, cmd);
- PathPop();
- return ret;
+ string tmpf = tempName(string(), "lyxvclog");
+ lyxerr[Debug::LYXVC] << "Generating logfile " << tmpf << endl;
+ vcs->getLog(tmpf);
+ return tmpf;
}