]> git.lyx.org Git - lyx.git/blob - src/LyXVC.cpp
Avoid full metrics computation with Update:FitCursor
[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))
62                 return true;
63         if (GIT::findFile(fn))
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 (SVN::findFile(fn)) {
84                 vcs_.reset(new SVN(owner_));
85                 return true;
86         }
87         // Check if file is under GIT
88         if (GIT::findFile(fn)) {
89                 vcs_.reset(new GIT(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 version control.
102         // This happens if we are trying to load file that does not exist.
103         // It may yet exist in the repository and so could be checked out.
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);
107         bool foundGIT = (foundRCS || foundCVS || foundSVN) ? false : GIT::findFile(fn);
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                 FileName found = VCS::checkParentDirs(filename, ".git/index");
157
158                 if (!found.empty()) {
159                         LYXERR(Debug::LYXVC, "LyXVC: registering "
160                                 << to_utf8(filename.displayName()) << " with GIT");
161                         vcs_.reset(new GIT(owner_));
162
163                 } else {
164                         found = VCS::checkParentDirs(filename, ".svn/entries");
165                         if (!found.empty()) {
166                                 LYXERR(Debug::LYXVC, "LyXVC: registering "
167                                         << to_utf8(filename.displayName()) << " with SVN");
168                                 vcs_.reset(new SVN(owner_));
169
170                         } else {
171                                 // We only need to check the current directory, since CVS meta-data
172                                 // is in every sub-directory.
173                                 FileName const cvs_entries(onlyPath(filename.absFileName()) + "/CVS/Entries");
174                                 if (cvs_entries.isReadableFile()) {
175                                         LYXERR(Debug::LYXVC, "LyXVC: registering "
176                                                 << to_utf8(filename.displayName()) << " with CVS");
177                                         vcs_.reset(new CVS(cvs_entries, owner_));
178
179                                 } else {
180                                         // If all else fails, use RCS
181                                         LYXERR(Debug::LYXVC, "LyXVC: registering "
182                                                 << to_utf8(filename.displayName()) << " with RCS");
183                                         vcs_.reset(new RCS(FileName(), owner_));
184                                 }
185                         }
186                 }
187         }
188
189         LYXERR(Debug::LYXVC, "LyXVC: registrer");
190         docstring response;
191         bool ok = Alert::askForText(response, _("LyX VC: Initial description"),
192                         _("(no initial description)"));
193         if (!ok) {
194                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
195                 vcs_.reset(nullptr);
196                 return false;
197         }
198         if (response.empty())
199                 response = _("(no initial description)");
200         vcs_->registrer(to_utf8(response));
201         return true;
202 }
203
204
205 string LyXVC::rename(FileName const & fn)
206 {
207         LYXERR(Debug::LYXVC, "LyXVC: rename");
208         if (!vcs_ || fileInVC(fn))
209                 return string();
210         docstring response;
211         bool ok = Alert::askForText(response, _("LyX VC: Log message"),
212                         _("(no log message)"));
213         if (!ok) {
214                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
215                 return string();
216         }
217         if (response.empty())
218                 response = _("(no log message)");
219         string ret = vcs_->rename(fn, to_utf8(response));
220         return ret;
221 }
222
223
224 string LyXVC::copy(FileName const & fn)
225 {
226         LYXERR(Debug::LYXVC, "LyXVC: copy");
227         if (!vcs_ || fileInVC(fn))
228                 return string();
229         docstring response;
230         bool ok = Alert::askForText(response, _("LyX VC: Log message"),
231                         _("(no log message)"));
232         if (!ok) {
233                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
234                 return string();
235         }
236         if (response.empty())
237                 response = _("(no log message)");
238         string ret = vcs_->copy(fn, to_utf8(response));
239         return ret;
240 }
241
242
243 LyXVC::CommandResult LyXVC::checkIn(string & log)
244 {
245         LYXERR(Debug::LYXVC, "LyXVC: checkIn");
246         if (!vcs_)
247                 return ErrorBefore;
248         docstring empty(_("(no log message)"));
249         docstring response;
250         bool ok = true;
251         if (vcs_->isCheckInWithConfirmation())
252                 ok = Alert::askForText(response, _("LyX VC: Log Message"));
253         if (ok) {
254                 if (response.empty())
255                         response = empty;
256                 //shell collisions
257                 response = subst(response, from_ascii("\""), from_ascii("\\\""));
258                 return vcs_->checkIn(to_utf8(response), log);
259         } else {
260                 LYXERR(Debug::LYXVC, "LyXVC: user cancelled");
261                 return Cancelled;
262         }
263 }
264
265
266 string LyXVC::checkOut()
267 {
268         if (!vcs_)
269                 return string();
270         //RCS allows checkOut only in ReadOnly mode
271         if (vcs_->toggleReadOnlyEnabled() && !owner_->hasReadonlyFlag())
272                 return string();
273
274         LYXERR(Debug::LYXVC, "LyXVC: checkOut");
275         return vcs_->checkOut();
276 }
277
278
279 string LyXVC::repoUpdate()
280 {
281         LYXERR(Debug::LYXVC, "LyXVC: repoUpdate");
282         if (!vcs_)
283                 return string();
284         return vcs_->repoUpdate();
285 }
286
287
288 string LyXVC::lockingToggle()
289 {
290         LYXERR(Debug::LYXVC, "LyXVC: toggle locking property");
291         if (!vcs_)
292                 return string();
293         return vcs_->lockingToggle();
294 }
295
296
297 bool LyXVC::revert()
298 {
299         LYXERR(Debug::LYXVC, "LyXVC: revert");
300         if (!vcs_)
301                 return false;
302
303         docstring const file = owner_->fileName().displayName(20);
304         docstring text = bformat(_("Reverting to the stored version of the "
305                                 "document %1$s will lose all current changes.\n\n"
306                                 "Do you want to revert to the older version?"), file);
307         int ret = 0;
308         if (vcs_->isRevertWithConfirmation())
309                 ret = Alert::prompt(_("Revert to stored version of document?"),
310                         text, 0, 1, _("&Revert"), _("&Cancel"));
311
312         return ret == 0 && vcs_->revert();
313 }
314
315
316 void LyXVC::undoLast()
317 {
318         if (!vcs_)
319                 return;
320         vcs_->undoLast();
321 }
322
323
324 string LyXVC::toggleReadOnly()
325 {
326         if (!vcs_)
327                 return string();
328         if (!vcs_->toggleReadOnlyEnabled())
329                 return string();
330
331         switch (vcs_->status()) {
332         case VCS::UNLOCKED:
333                 LYXERR(Debug::LYXVC, "LyXVC: toggle to locked");
334                 return checkOut();
335         case VCS::LOCKED: {
336                 LYXERR(Debug::LYXVC, "LyXVC: toggle to unlocked");
337                 string log;
338                 if (checkIn(log) != VCSuccess)
339                         return string();
340                 return log;
341         }
342         case VCS::NOLOCKING:
343                 Buffer * b = vcs_->owner();
344                 bool const newstate = !b->hasReadonlyFlag();
345                 string result = "LyXVC: toggle to ";
346                 result += (newstate ? "readonly" : "readwrite");
347                 LYXERR(Debug::LYXVC, result);
348                 b->setReadonly(newstate);
349                 return result;
350         }
351         return string();
352 }
353
354
355 bool LyXVC::inUse() const
356 {
357         return vcs_ != nullptr;
358 }
359
360
361 string const LyXVC::versionString() const
362 {
363         if (!vcs_)
364                 return string();
365         return vcs_->versionString();
366 }
367
368
369 bool LyXVC::locking() const
370 {
371         if (!vcs_)
372                 return false;
373         return vcs_->status() != VCS::NOLOCKING;
374 }
375
376
377 string const LyXVC::getLogFile() const
378 {
379         if (!vcs_)
380                 return string();
381
382         TempFile tempfile("lyxvclog");
383         tempfile.setAutoRemove(false);
384         FileName const tmpf = tempfile.name();
385         if (tmpf.empty()) {
386                 LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf);
387                 return string();
388         }
389         LYXERR(Debug::LYXVC, "Generating logfile " << tmpf);
390         vcs_->getLog(tmpf);
391         return tmpf.absFileName();
392 }
393
394
395 string LyXVC::revisionInfo(RevisionInfo const info) const
396 {
397         if (!vcs_)
398                 return string();
399
400         return vcs_->revisionInfo(info);
401 }
402
403
404 bool LyXVC::renameEnabled() const
405 {
406         if (!inUse())
407                 return false;
408         return vcs_->renameEnabled();
409 }
410
411
412 bool LyXVC::copyEnabled() const
413 {
414         if (!inUse())
415                 return false;
416         return vcs_->copyEnabled();
417 }
418
419
420 bool LyXVC::checkOutEnabled() const
421 {
422         return vcs_ && vcs_->checkOutEnabled();
423 }
424
425
426 bool LyXVC::checkInEnabled() const
427 {
428         return vcs_ && vcs_->checkInEnabled();
429 }
430
431
432 bool LyXVC::isCheckInWithConfirmation() const
433 {
434         return vcs_ && vcs_->isCheckInWithConfirmation();
435 }
436
437
438 bool LyXVC::lockingToggleEnabled() const
439 {
440         return vcs_ && vcs_->lockingToggleEnabled();
441 }
442
443
444 bool LyXVC::undoLastEnabled() const
445 {
446         return vcs_ && vcs_->undoLastEnabled();
447 }
448
449
450 bool LyXVC::repoUpdateEnabled() const
451 {
452         return vcs_ && vcs_->repoUpdateEnabled();
453 }
454
455
456 bool LyXVC::prepareFileRevision(string const & rev, std::string & f)
457 {
458         return vcs_ && vcs_->prepareFileRevision(rev, f);
459 }
460
461
462 bool LyXVC::prepareFileRevisionEnabled()
463 {
464         return vcs_ && vcs_->prepareFileRevisionEnabled();
465 }
466
467 } // namespace lyx