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