]> git.lyx.org Git - lyx.git/blob - src/lyxvc.C
db0572eccd4911f12d3ec2a944ae007b3ac0436c
[lyx.git] / src / lyxvc.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include FORMS_H_LOCATION
8 #include "lyxvc.h"
9 #include "error.h"
10 #include "lyx_gui_misc.h"
11 #include "bufferlist.h"
12 #include "support/syscall.h"
13 #include "pathstack.h"
14 #include "support/filetools.h"
15 #include "support/FileInfo.h"
16 #include "gettext.h"
17 #include "LyXView.h"
18 #include "lyxfunc.h"
19 #include "latexoptions.h"
20
21 extern BufferList bufferlist;
22 extern void MenuWrite(Buffer *);
23
24 #if 0
25 extern bool gsworking();
26 #endif
27
28 LyXVC::LyXVC()
29 {
30         backend = UNKNOWN_VCS;
31         _owner = 0;
32         browser = 0;
33 }
34
35
36 LyXVC::~LyXVC()
37 {
38         if (browser) {
39                 if (browser->LaTeXLog->visible)
40                         fl_hide_form(browser->LaTeXLog);
41                 fl_free_form(browser->LaTeXLog);
42         }
43 }
44
45
46 bool LyXVC::file_found_hook(string const & fn)
47 {
48         string tmp(fn);
49         FileInfo f;
50         // Check if *,v exists.
51         tmp += ",v";
52         lyxerr.debug(string("Checking if file is under vc: ") + tmp, Error::LYXVC);
53         if (f.newFile(tmp).readable()) {
54                 lyxerr.debug("Yes it is under vc.", Error::LYXVC);
55                 master = tmp;
56                 backend = RCS_VCS;
57                 scanMaster();
58                 return true;
59         } else {
60                 // Check if RCS/*,v exists.
61                 tmp = AddName(AddPath(OnlyPath(fn), "RCS"), fn);
62                 tmp += ",v";
63                 lyxerr.debug("Checking if file is under vc: " + tmp, Error::LYXVC);
64                 if (f.newFile(tmp).readable()) {
65                         lyxerr.debug("Yes it is under vc.", Error::LYXVC);
66                         master = tmp;
67                         backend = RCS_VCS;
68                         scanMaster();
69                         return true;
70                 }
71         }
72         // If either one, return true
73
74         // file is not under any VCS.
75         return false;
76 }
77
78
79 bool LyXVC::file_not_found_hook(string const &)
80 {
81         // file is not under any VCS.
82         return false;
83 }
84
85
86 void LyXVC::scanMaster()
87 {
88         lyxerr.debug("LyXVC: This file is a VC file.", Error::LYXVC);
89
90         LyXLex lex(0, 0);
91         lex.setFile(master);
92
93         string token;
94         bool read_enough = false;
95         while (lex.IsOK() && !read_enough) {
96                 lex.next();
97                 token = lex.GetString();
98                 
99                 lyxerr.debug("LyXVC::scanMaster: current lex text: `"
100                                 +token+"'", Error::LYXVC);
101
102                 if (token.empty())
103                         continue;
104                 else if (token == "head") {
105                         // get version here
106                         lex.next();
107                         string tmv = strip(lex.GetString(), ';');
108                         version = tmv;
109                 } else if (contains(token, "access")
110                            || contains(token, "symbols")
111                            || contains(token, "strict")) {
112                         // nothing
113                 } else if (contains(token, "locks")) {
114                         // get locker here
115                         if (contains(token, ";")) {
116                                 locker = "Unlocked";
117                                 vcstat = UNLOCKED;
118                                 continue;
119                         }
120                         string tmpt, s1, s2;
121                         do {
122                                 lex.next();
123                                 s1 = strip(tmpt = lex.GetString(), ';');
124                                 // tmp is now in the format <user>:<version>
125                                 s1 = split(s1, s2, ':');
126                                 // s2 is user, and s1 is version
127                                 if (s1 == version) {
128                                         locker = s2;
129                                         vcstat = LOCKED;
130                                         break;
131                                 }
132                         } while (!contains(tmpt, ";"));
133                         
134                 } else if (token == "comment") {
135                         // we don't need to read any further than this.
136                         read_enough = true;
137                 } else {
138                         // unexpected
139                         lyxerr.debug("LyXVC::scanMaster(): unexpected token", Error::LYXVC);
140                 }
141         }
142 }
143
144
145 void LyXVC::setBuffer(Buffer *buf)
146 {
147         _owner = buf;
148 }
149
150
151 //
152 // I will probably add some backend_xxxx functions later to perform the
153 // version control system specific commands. Something like:
154 // void backend_revert(<params>) {
155 //        if (backend == "RCS") {
156 //        } else if (backend == "CVS") {
157 //        } else if (backend == "SCCS") {
158 //        }
159 //
160 // But for 0.12 we will only support RCS.
161 //
162
163 void LyXVC::registrer()
164 {
165         // If the document is changed, we might want to save it
166         if (!_owner->isLyxClean() && 
167             AskQuestion(_("Changes in document:"),
168                         MakeDisplayPath(_owner->getFileName(),50),
169                         _("Save document and proceed?"))) {
170                 MenuWrite(_owner);
171         }
172
173         // Maybe the save fails, or we answered "no". In both cases,
174         // the document will be dirty, and we abort.
175         if (!_owner->isLyxClean()) {
176                 return;
177         }
178
179         lyxerr.debug("LyXVC: registrer", Error::LYXVC);
180         string tmp = askForText(_("LyX VC: Initial description"),
181                                  _("(no initial description)"));
182         if (tmp.empty()) {
183                 lyxerr.debug("LyXVC: user cancelled", Error::LYXVC);
184                 WriteAlert(_("Info"), _("This document has NOT been registered."));
185                 return;
186         }
187         string cmd = "ci -q -u -i -t-\"";
188         cmd += tmp;
189         cmd += "\" \"";
190         cmd += OnlyFilename(_owner->getFileName());
191         cmd += "\"";
192         doVCCommand(cmd);
193         _owner->getUser()->getOwner()->getLyXFunc()->Dispatch("buffer-reload");
194 }
195
196
197 void LyXVC::checkIn()
198 {
199         // If the document is changed, we might want to save it
200         if (!_owner->isLyxClean() && 
201             AskQuestion(_("Changes in document:"),
202                         MakeDisplayPath(_owner->getFileName(),50),
203                         _("Save document and proceed?"))) {
204                 MenuWrite(_owner);
205         }
206
207         // Maybe the save fails, or we answered "no". In both cases,
208         // the document will be dirty, and we abort.
209         if (!_owner->isLyxClean()) {
210                 return;
211         }
212
213         lyxerr.debug("LyXVC: checkIn", Error::LYXVC);
214         _owner->getUser()->getOwner()->getLyXFunc()->Dispatch(LFUN_MENUWRITE);
215         string tmp = askForText(_("LyX VC: Log Message"));
216         if (tmp.empty()) tmp = "(no log msg)";
217         doVCCommand("ci -q -u -m\"" + tmp + "\" \""
218                     + OnlyFilename(_owner->getFileName()) + "\"");
219         _owner->getUser()->getOwner()->getLyXFunc()->Dispatch("buffer-reload");
220 }
221
222
223 void LyXVC::checkOut()
224 {
225         lyxerr.debug("LyXVC: checkOut", Error::LYXVC);
226         if (!_owner->isLyxClean() 
227             && !AskQuestion(_("Changes in document:"),
228                            MakeDisplayPath(_owner->getFileName(),50),
229                            _("Ignore changes and proceed with check out?"))) {
230                 return;
231         }
232
233         _owner->markLyxClean();
234         doVCCommand("co -q -l \""
235                     + OnlyFilename(_owner->getFileName()) + "\"");
236         _owner->getUser()->getOwner()->getLyXFunc()->Dispatch("buffer-reload");
237 }
238
239
240 void LyXVC::revert()
241 {
242         lyxerr.debug("LyXVC: revert", Error::LYXVC);
243         // Here we should check if the buffer is dirty. And if it is
244         // we should warn the user that reverting will discard all
245         // changes made since the last check in.
246         if (AskQuestion(_("When you revert, you will loose all changes made"),
247                         _("to the document since the last check in."),
248                         _("Do you still want to do it?"))) {
249                 
250                 doVCCommand("co -f -u" + getVersion() + " \""
251                             + OnlyFilename(_owner->getFileName()) + "\"");
252                 // We ignore changes and just reload!
253                 _owner->markLyxClean();
254                 _owner->getUser()->getOwner()->
255                         getLyXFunc()->Dispatch("buffer-reload");
256         }
257 }
258
259
260 void LyXVC::undoLast()
261 {
262         lyxerr.debug("LyXVC: undoLast", Error::LYXVC);
263         doVCCommand("rcs -o" + getVersion() + " \""
264                     + OnlyFilename(_owner->getFileName()) + "\"");
265 }
266
267
268 void LyXVC::toggleReadOnly()
269 {
270         switch (vcstat) {
271         case UNLOCKED:
272                 checkOut();
273                 break;
274         case LOCKED:
275                 checkIn();
276                 break;
277         }
278 }
279
280
281 bool LyXVC::inUse()
282 {
283         if (!master.empty())
284                 return true;
285         return false;
286 }
287
288
289 string const LyXVC::getVersion() const
290 {
291         return version;
292 }
293
294
295 string const LyXVC::getLocker() const
296 {
297         return locker;
298 }
299
300 // This is a hack anyway so I'll put it here in the mean time.
301 void LyXVC::logClose(FL_OBJECT *obj, long)
302 {
303         LyXVC *This = (LyXVC*)obj->form->u_vdata;
304         fl_hide_form(This->browser->LaTeXLog);
305 }
306
307
308 void LyXVC::logUpdate(FL_OBJECT *obj, long)
309 {
310         LyXVC *This = (LyXVC*)obj->form->u_vdata;
311         This->showLog();
312 }
313
314
315 void LyXVC::viewLog(string const & fil)
316 {
317         if (!browser) {
318                 FL_OBJECT *obj;
319                 browser = (FD_LaTeXLog *) fl_calloc(1, sizeof(*browser));
320                 
321                 browser->LaTeXLog = fl_bgn_form(FL_NO_BOX, 470, 380);
322                 browser->LaTeXLog->u_vdata = (void*)this;
323                 obj = fl_add_box(FL_UP_BOX, 0, 0, 470, 380, "");
324                 browser->browser_latexlog = fl_add_browser(FL_NORMAL_BROWSER, 10, 10, 450, 320, "");
325                 obj = fl_add_button(FL_RETURN_BUTTON, 270, 340, 90, 30, _("Close"));
326                 fl_set_object_lsize(obj, FL_NORMAL_SIZE);
327                 fl_set_object_callback(obj, logClose, 0);
328                 obj = fl_add_button(FL_NORMAL_BUTTON,370,340,90,30,
329                                     idex(_("Update|#Uu")));
330                 fl_set_button_shortcut(obj,scex(_("Update|#Uu")),1);
331                 fl_set_object_lsize(obj,FL_NORMAL_SIZE);
332                 fl_set_object_callback(obj,logUpdate,0);
333                 fl_end_form();
334                 fl_set_form_atclose(browser->LaTeXLog, CancelCloseBoxCB, 0);
335         }
336
337         if (!fl_load_browser(browser->browser_latexlog, fil.c_str()))
338                 fl_add_browser_line(browser->browser_latexlog, _("No RCS History!"));
339         
340         if (browser->LaTeXLog->visible) {
341                 fl_raise_form(browser->LaTeXLog);
342         } else {
343                 fl_show_form(browser->LaTeXLog,
344                              FL_PLACE_MOUSE | FL_FREE_SIZE, FL_FULLBORDER,
345                              _("RCS History"));
346         }
347 }
348
349
350 void LyXVC::showLog()
351 {
352         // This I really don't like, but we'll look at this problem
353         // in 0.13. Then we can make a clean solution.
354 #if 0
355         if (gsworking()) {
356                 WriteAlert(_("Sorry, can't do this while"
357                              " pictures are being rendered."),
358                            _("Please wait a few seconds for"
359                              " this to finish and try again."),
360                            _("(or kill runaway gs processes"
361                              " by hand and try again.)"));
362                 return;
363         }
364         extern pid_t isp_pid; // from spellchecker.C
365         if(isp_pid != -1) {
366                 WriteAlert(_("Can't do this while the"
367                              " spellchecker is running."),
368                            _("Stop the spellchecker first."));
369                 return;
370         }
371 #endif
372         string tmpf = tmpnam(0);
373         doVCCommand("rlog \""
374                     + OnlyFilename(_owner->getFileName()) + "\" > " + tmpf);
375         viewLog(tmpf);
376         unlink(tmpf.c_str());
377 }
378
379
380 int LyXVC::doVCCommand(string const & cmd)
381 {
382         lyxerr.debug("doVCCommand: " + cmd, Error::LYXVC);
383         Systemcalls one;
384         PathPush(_owner->filepath);
385         int ret = one.Startscript(Systemcalls::System, cmd);
386         PathPop();
387         return ret;
388 }