]> git.lyx.org Git - lyx.git/blob - src/LyXVC.cpp
More readable latex color (on button and workarea) in dark mode
[lyx.git] / src / LyXVC.cpp
1 /**
2  * \file LyXVC.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author Angus Leeming
9  * \author John Levon
10  * \author André Pönitz
11  * \author Allan Rae
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "LyXVC.h"
19 #include "VCBackend.h"
20 #include "Buffer.h"
21
22 #include "frontends/alert.h"
23
24 #include "support/debug.h"
25 #include "support/filetools.h"
26 #include "support/gettext.h"
27 #include "support/lstrings.h"
28 #include "support/TempFile.h"
29
30 using namespace std;
31 using namespace lyx::support;
32
33 namespace lyx {
34
35 namespace Alert = frontend::Alert;
36
37
38 LyXVC::LyXVC()
39 {
40         owner_ = nullptr;
41 }
42
43
44 docstring LyXVC::vcstatus() const
45 {
46         if (!vcs)
47                 return docstring();
48         if (locking())
49                 return bformat(_("%1$s lock"), from_ascii(vcs->vcname()));
50         else
51                 return from_ascii(vcs->vcname());
52 }
53
54
55 bool LyXVC::fileInVC(FileName const & fn)
56 {
57         if (!RCS::findFile(fn).empty())
58                 return true;
59         if (!CVS::findFile(fn).empty())
60                 return true;
61         if (!SVN::findFile(fn).empty())
62                 return true;
63         if (!GIT::findFile(fn).empty())
64                 return true;
65         return false;
66 }
67
68
69 bool LyXVC::file_found_hook(FileName const & fn)
70 {
71         FileName found_file;
72         // Check if file is under RCS
73         if (!(found_file = RCS::findFile(fn)).empty()) {
74                 vcs.reset(new RCS(found_file, owner_));
75                 return true;
76         }
77         // Check if file is under CVS
78         if (!(found_file = CVS::findFile(fn)).empty()) {
79                 vcs.reset(new CVS(found_file, owner_));
80                 return true;
81         }
82         // Check if file is under SVN
83         if (!(found_file = SVN::findFile(fn)).empty()) {
84                 vcs.reset(new SVN(found_file, owner_));
85                 return true;
86         }
87         // Check if file is under GIT
88         if (!(found_file = GIT::findFile(fn)).empty()) {
89                 vcs.reset(new GIT(found_file, owner_));
90                 return true;
91         }
92
93         // file is not under any VCS.
94         vcs.reset(nullptr);
95         return false;
96 }
97
98
99 bool LyXVC::file_not_found_hook(FileName const & fn)
100 {
101         // Check if file is under RCS.
102         // This happens if we are trying to load non existent
103         // file on disk, but existent in ,v version.
104         bool foundRCS = !RCS::findFile(fn).empty();
105         bool foundCVS = foundRCS ? false : !CVS::findFile(fn).empty();
106         bool foundSVN = (foundRCS || foundCVS) ? false : !SVN::findFile(fn).empty();
107         bool foundGIT = (foundRCS || foundCVS || foundSVN) ? false : !GIT::findFile(fn).empty();
108         if (foundRCS || foundCVS || foundSVN || foundGIT) {
109                 docstring const file = makeDisplayPath(fn.absFileName(), 20);
110                 docstring const text =
111                         bformat(_("Do you want to retrieve the document"
112                                                    " %1$s from version control?"), file);
113                 int const ret = Alert::prompt(_("Retrieve from version control?"),
114                         text, 0, 1, _("&Retrieve"), _("&Cancel"));
115
116                 if (ret == 0) {
117                         // Since the retrieve commands are implemented using
118                         // more general update commands we need to ensure that
119                         // we do not change an existing file by accident.
120                         if (fn.exists())
121                                 return false;
122                         if (foundRCS)
123                                 return RCS::retrieve(fn);
124                         else if (foundCVS)
125                                 return CVS::retrieve(fn);
126                         else if (foundSVN)
127                                 return SVN::retrieve(fn);
128                         else
129                                 return GIT::retrieve(fn);
130                 }
131         }
132         return false;
133 }
134
135
136 void LyXVC::setBuffer(Buffer * buf)
137 {
138         owner_ = buf;
139 }
140
141
142 bool LyXVC::registrer()
143 {
144         FileName const filename = owner_->fileName();
145
146         // there must be a file to save
147         if (!filename.isReadableFile()) {
148                 Alert::error(_("Document not saved"),
149                              _("You must save the document "
150                                             "before it can be registered."));
151                 return false;
152         }
153
154         // it is very likely here that the vcs is not created yet...
155         if (!vcs) {
156                 //check in the root directory of the document
157                 FileName const cvs_entries(onlyPath(filename.absFileName()) + "/CVS/Entries");
158                 FileName const svn_entries(onlyPath(filename.absFileName()) + "/.svn/entries");
159                 FileName const git_index(onlyPath(filename.absFileName()) + "/.git/index");
160
161                 if (git_index.isReadableFile()) {
162                         LYXERR(Debug::LYXVC, "LyXVC: registering "
163                                 << to_utf8(filename.displayName()) << " with GIT");
164                         vcs.reset(new GIT(git_index, owner_));
165
166                 } else if (svn_entries.isReadableFile()) {
167                         LYXERR(Debug::LYXVC, "LyXVC: registering "
168                                 << to_utf8(filename.displayName()) << " with SVN");
169                         vcs.reset(new SVN(svn_entries, owner_));
170
171                 } else if (cvs_entries.isReadableFile()) {
172                         LYXERR(Debug::LYXVC, "LyXVC: registering "
173                                 << to_utf8(filename.displayName()) << " with CVS");
174                         vcs.reset(new CVS(cvs_entries, owner_));
175
176                 } else {
177                         LYXERR(Debug::LYXVC, "LyXVC: registering "
178                                 << to_utf8(filename.displayName()) << " with RCS");
179                         vcs.reset(new RCS(FileName(), owner_));
180                 }
181         }
182
183         LYXERR(Debug::LYXVC, "LyXVC: registrer");
184         docstring response;
185         bool ok = Alert::askForText(response, _("LyX VC: Initial description"),
186                         _("(no initial description)"));
187         if (!ok) {
188                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
189                 vcs.reset(nullptr);
190                 return false;
191         }
192         if (response.empty())
193                 response = _("(no initial description)");
194         vcs->registrer(to_utf8(response));
195         return true;
196 }
197
198
199 string LyXVC::rename(FileName const & fn)
200 {
201         LYXERR(Debug::LYXVC, "LyXVC: rename");
202         if (!vcs || fileInVC(fn))
203                 return string();
204         docstring response;
205         bool ok = Alert::askForText(response, _("LyX VC: Log message"),
206                         _("(no log message)"));
207         if (!ok) {
208                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
209                 return string();
210         }
211         if (response.empty())
212                 response = _("(no log message)");
213         string ret = vcs->rename(fn, to_utf8(response));
214         return ret;
215 }
216
217
218 string LyXVC::copy(FileName const & fn)
219 {
220         LYXERR(Debug::LYXVC, "LyXVC: copy");
221         if (!vcs || fileInVC(fn))
222                 return string();
223         docstring response;
224         bool ok = Alert::askForText(response, _("LyX VC: Log message"),
225                         _("(no log message)"));
226         if (!ok) {
227                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
228                 return string();
229         }
230         if (response.empty())
231                 response = _("(no log message)");
232         string ret = vcs->copy(fn, to_utf8(response));
233         return ret;
234 }
235
236
237 LyXVC::CommandResult LyXVC::checkIn(string & log)
238 {
239         LYXERR(Debug::LYXVC, "LyXVC: checkIn");
240         if (!vcs)
241                 return ErrorBefore;
242         docstring empty(_("(no log message)"));
243         docstring response;
244         bool ok = true;
245         if (vcs->isCheckInWithConfirmation())
246                 ok = Alert::askForText(response, _("LyX VC: Log Message"));
247         if (ok) {
248                 if (response.empty())
249                         response = empty;
250                 //shell collisions
251                 response = subst(response, from_ascii("\""), from_ascii("\\\""));
252                 return vcs->checkIn(to_utf8(response), log);
253         } else {
254                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
255                 return Cancelled;
256         }
257 }
258
259
260 string LyXVC::checkOut()
261 {
262         if (!vcs)
263                 return string();
264         //RCS allows checkOut only in ReadOnly mode
265         if (vcs->toggleReadOnlyEnabled() && !owner_->hasReadonlyFlag())
266                 return string();
267
268         LYXERR(Debug::LYXVC, "LyXVC: checkOut");
269         return vcs->checkOut();
270 }
271
272
273 string LyXVC::repoUpdate()
274 {
275         LYXERR(Debug::LYXVC, "LyXVC: repoUpdate");
276         if (!vcs)
277                 return string();
278         return vcs->repoUpdate();
279 }
280
281
282 string LyXVC::lockingToggle()
283 {
284         LYXERR(Debug::LYXVC, "LyXVC: toggle locking property");
285         if (!vcs)
286                 return string();
287         return vcs->lockingToggle();
288 }
289
290
291 bool LyXVC::revert()
292 {
293         LYXERR(Debug::LYXVC, "LyXVC: revert");
294         if (!vcs)
295                 return false;
296
297         docstring const file = owner_->fileName().displayName(20);
298         docstring text = bformat(_("Reverting to the stored version of the "
299                                 "document %1$s will lose all current changes.\n\n"
300                                 "Do you want to revert to the older version?"), file);
301         int ret = 0;
302         if (vcs->isRevertWithConfirmation())
303                 ret = Alert::prompt(_("Revert to stored version of document?"),
304                         text, 0, 1, _("&Revert"), _("&Cancel"));
305
306         return ret == 0 && vcs->revert();
307 }
308
309
310 void LyXVC::undoLast()
311 {
312         if (!vcs)
313                 return;
314         vcs->undoLast();
315 }
316
317
318 string LyXVC::toggleReadOnly()
319 {
320         if (!vcs)
321                 return string();
322         if (!vcs->toggleReadOnlyEnabled())
323                 return string();
324
325         switch (vcs->status()) {
326         case VCS::UNLOCKED:
327                 LYXERR(Debug::LYXVC, "LyXVC: toggle to locked");
328                 return checkOut();
329         case VCS::LOCKED: {
330                 LYXERR(Debug::LYXVC, "LyXVC: toggle to unlocked");
331                 string log;
332                 if (checkIn(log) != VCSuccess)
333                         return string();
334                 return log;
335         }
336         case VCS::NOLOCKING:
337                 Buffer * b = vcs->owner();
338                 bool const newstate = !b->hasReadonlyFlag();
339                 string result = "LyXVC: toggle to ";
340                 result += (newstate ? "readonly" : "readwrite");
341                 LYXERR(Debug::LYXVC, result);
342                 b->setReadonly(newstate);
343                 return result;
344         }
345         return string();
346 }
347
348
349 bool LyXVC::inUse() const
350 {
351         return vcs != nullptr;
352 }
353
354
355 string const LyXVC::versionString() const
356 {
357         if (!vcs)
358                 return string();
359         return vcs->versionString();
360 }
361
362
363 bool LyXVC::locking() const
364 {
365         if (!vcs)
366                 return false;
367         return vcs->status() != VCS::NOLOCKING;
368 }
369
370
371 string const LyXVC::getLogFile() const
372 {
373         if (!vcs)
374                 return string();
375
376         TempFile tempfile("lyxvclog");
377         tempfile.setAutoRemove(false);
378         FileName const tmpf = tempfile.name();
379         if (tmpf.empty()) {
380                 LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf);
381                 return string();
382         }
383         LYXERR(Debug::LYXVC, "Generating logfile " << tmpf);
384         vcs->getLog(tmpf);
385         return tmpf.absFileName();
386 }
387
388
389 string LyXVC::revisionInfo(RevisionInfo const info) const
390 {
391         if (!vcs)
392                 return string();
393
394         return vcs->revisionInfo(info);
395 }
396
397
398 bool LyXVC::renameEnabled() const
399 {
400         if (!inUse())
401                 return false;
402         return vcs->renameEnabled();
403 }
404
405
406 bool LyXVC::copyEnabled() const
407 {
408         if (!inUse())
409                 return false;
410         return vcs->copyEnabled();
411 }
412
413
414 bool LyXVC::checkOutEnabled() const
415 {
416         return vcs && vcs->checkOutEnabled();
417 }
418
419
420 bool LyXVC::checkInEnabled() const
421 {
422         return vcs && vcs->checkInEnabled();
423 }
424
425
426 bool LyXVC::isCheckInWithConfirmation() const
427 {
428         return vcs && vcs->isCheckInWithConfirmation();
429 }
430
431
432 bool LyXVC::lockingToggleEnabled() const
433 {
434         return vcs && vcs->lockingToggleEnabled();
435 }
436
437
438 bool LyXVC::undoLastEnabled() const
439 {
440         return vcs && vcs->undoLastEnabled();
441 }
442
443
444 bool LyXVC::repoUpdateEnabled() const
445 {
446         return vcs && vcs->repoUpdateEnabled();
447 }
448
449
450 bool LyXVC::prepareFileRevision(string const & rev, std::string & f)
451 {
452         return vcs && vcs->prepareFileRevision(rev, f);
453 }
454
455
456 bool LyXVC::prepareFileRevisionEnabled()
457 {
458         return vcs && vcs->prepareFileRevisionEnabled();
459 }
460
461 } // namespace lyx