]> git.lyx.org Git - lyx.git/blob - src/buffer_funcs.cpp
8ac7e9736072598617a2d7dc1f0569e19445b4e8
[lyx.git] / src / buffer_funcs.cpp
1 /**
2  * \file buffer_funcs.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 Alfredo Braunstein
8  *
9  * Full author contact details are available in file CREDITS.
10  *
11  */
12
13 #include <config.h>
14
15 #include "buffer_funcs.h"
16 #include "Buffer.h"
17 #include "BufferList.h"
18 #include "LyXVC.h"
19
20 #include "frontends/alert.h"
21
22 #include "support/lassert.h"
23 #include "support/convert.h"
24 #include "support/debug.h"
25 #include "support/filetools.h"
26 #include "support/gettext.h"
27 #include "support/lstrings.h"
28 #include "support/mutex.h"
29
30 using namespace std;
31 using namespace lyx::support;
32
33 namespace lyx {
34
35 namespace Alert = frontend::Alert;
36
37
38 Buffer * checkAndLoadLyXFile(FileName const & filename, bool const acceptDirty)
39 {
40         // File already open?
41         Buffer * checkBuffer = theBufferList().getBuffer(filename);
42         if (checkBuffer) {
43                 // Sometimes (when setting the master buffer from a child)
44                 // we accept a dirty buffer right away (otherwise we'd get
45                 // an infinite loop (bug 5514).
46                 // We also accept a dirty buffer when the document has not
47                 // yet been saved to disk.
48                 if (checkBuffer->isClean() || acceptDirty || !filename.exists())
49                         return checkBuffer;
50                 docstring const file = makeDisplayPath(filename.absFileName(), 20);
51                 docstring const text = bformat(_(
52                                 "The document %1$s is already loaded and has unsaved changes.\n"
53                                 "Do you want to abandon your changes and reload the version on disk?"), file);
54                 int res = Alert::prompt(_("Reload saved document?"),
55                                         text, 2, 2,  _("Yes, &Reload"), _("No, &Keep Changes"), _("&Cancel"));
56                 switch (res) {
57                         case 0: {
58                                 // reload the document
59                                 if (checkBuffer->reload() != Buffer::ReadSuccess)
60                                         return nullptr;
61                                 return checkBuffer;
62                         }
63                         case 1:
64                                 // keep changes
65                                 return checkBuffer;
66                         case 2:
67                                 // cancel
68                                 return nullptr;
69                 }
70         }
71
72         bool const exists = filename.exists();
73         bool const tryVC = exists ? false : LyXVC::fileInVC(filename);
74         if (exists || tryVC) {
75                 if (exists) {
76                         if (!filename.isReadableFile()) {
77                                 docstring text = bformat(_("The file %1$s exists but is not "
78                                         "readable by the current user."),
79                                         from_utf8(filename.absFileName()));
80                                 Alert::error(_("File not readable!"), text);
81                                 return nullptr;
82                         }
83                         if (filename.extension() == "lyx" && filename.isFileEmpty()) {
84                                 // Makes it possible to open an empty (0 bytes) .lyx file
85                                 return newFile(filename.absFileName(), "", true);
86                         }
87                 }
88                 Buffer * b = theBufferList().newBuffer(filename.absFileName());
89                 if (!b) {
90                         // Buffer creation is not possible.
91                         return nullptr;
92                 }
93                 if (b->loadLyXFile() != Buffer::ReadSuccess) {
94                         // do not save an emergency file when releasing the buffer
95                         b->markClean();
96                         theBufferList().release(b);
97                         return nullptr;
98                 }
99                 return b;
100         }
101
102         docstring text = bformat(_("The document %1$s does not yet "
103                 "exist.\n\nDo you want to create a new document?"),
104                 from_utf8(filename.absFileName()));
105         if (!Alert::prompt(_("Create new document?"),
106                         text, 0, 1, _("&Yes, Create New Document"), _("&No, Do Not Create")))
107                 return newFile(filename.absFileName(), string(), true);
108
109         return nullptr;
110 }
111
112
113 // FIXME newFile() should probably be a member method of Application...
114 Buffer * newFile(string const & filename, string const & templatename,
115                  bool is_named)
116 {
117         // get a free buffer
118         Buffer * b = theBufferList().newBuffer(filename);
119         if (!b)
120                 // Buffer creation is not possible.
121                 return nullptr;
122
123         FileName tname;
124         // use defaults.lyx as a default template if it exists.
125         if (templatename.empty())
126                 tname = libFileSearch("templates", "defaults.lyx");
127         else
128                 tname = makeAbsPath(templatename);
129
130         if (!tname.empty()) {
131                 if (b->loadThisLyXFile(tname) != Buffer::ReadSuccess) {
132                         docstring const file = makeDisplayPath(tname.absFileName(), 50);
133                         docstring const text  = bformat(
134                                 _("The specified document template\n%1$s\ncould not be read."),
135                                 file);
136                         Alert::error(_("Could not read template"), text);
137                         theBufferList().release(b);
138                         return nullptr;
139                 }
140         }
141
142         if (is_named)
143                 // in this case, the user chose the filename, so we
144                 // assume that she really does want this file.
145                 b->markDirty();
146         else
147                 b->setUnnamed();
148
149         b->setReadonly(false);
150         b->setFullyLoaded(true);
151
152         return b;
153 }
154
155
156 Buffer * newUnnamedFile(FileName const & path, string const & prefix,
157                                                 string const & templatename)
158 {
159         static map<string, int> file_number;
160         static Mutex mutex;
161
162         Mutex::Locker locker(&mutex);
163         FileName filename;
164
165         do {
166                 filename.set(path,
167                         prefix + convert<string>(++file_number[prefix]) + ".lyx");
168         }
169         while (theBufferList().exists(filename) || filename.isReadableFile());
170
171         return newFile(filename.absFileName(), templatename, false);
172 }
173
174
175 Buffer * loadIfNeeded(FileName const & fname)
176 {
177         Buffer * buffer = theBufferList().getBuffer(fname);
178         if (!buffer) {
179                 if (!fname.exists() && !LyXVC::fileInVC(fname))
180                         return nullptr;
181
182                 buffer = theBufferList().newBuffer(fname.absFileName());
183                 if (!buffer)
184                         // Buffer creation is not possible.
185                         return nullptr;
186
187                 if (buffer->loadLyXFile() != Buffer::ReadSuccess) {
188                         //close the buffer we just opened
189                         theBufferList().release(buffer);
190                         return nullptr;
191                 }
192         }
193         return buffer;
194 }
195
196
197 } // namespace lyx