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