1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich,
7 * Copyright 1995-2001 The LyX Team.
9 * ====================================================== */
18 #include FORMS_H_LOCATION
21 #include "lyx_gui_misc.h"
23 #include "bufferlist.h"
24 #include "bufferview_funcs.h"
25 #include "lastfiles.h"
29 #include "frontends/FileDialog.h"
30 #include "insets/insetlabel.h"
31 #include "support/FileInfo.h"
32 #include "support/filetools.h"
33 #include "support/path.h"
34 #include "support/syscall.h"
36 #include "BufferView.h"
43 using std::back_inserter;
44 using std::istream_iterator;
48 extern BufferList bufferlist;
49 // this should be static, but I need it in buffer.C
50 bool quitting; // flag, that we are quitting the program
51 extern bool finished; // all cleanup done just let it run through now.
54 This is the inset locking stuff needed for mathed --------------------
56 an inset can simple call LockInset in it's edit call and *ONLY* in it's
58 Inset::Edit() can only be called by the main lyx module.
60 Then the inset may modify the menu's and/or iconbars.
62 Unlocking is either done by LyX or the inset itself with a UnlockInset-call
64 During the lock, all button and keyboard events will be modified
65 and send to the inset through the following inset-features. Note that
66 Inset::insetUnlock will be called from inside UnlockInset. It is meant
67 to contain the code for restoring the menus and things like this.
70 virtual void insetButtonPress(int x, int y, int button);
71 virtual void insetButtonRelease(int x, int y, int button);
72 virtual void insetKeyPress(XKeyEvent *ev);
73 virtual void insetMotionNotify(int x, int y, int state);
74 virtual void insetUnlock();
76 If a inset wishes any redraw and/or update it just has to call
78 It's is completly irrelevant, where the inset is. UpdateInset will
79 find it in any paragraph in any buffer.
80 Of course the_locking_inset and the insets in the current paragraph/buffer
81 are checked first, so no performance problem should occur.
83 Hope that's ok for the beginning, Alejandro,
84 sorry that I needed so much time,
89 //void UpdateInset(BufferView * bv, Inset * inset, bool mark_dirty = true);
91 /* these functions return 1 if an error occured,
93 // Now they work only for updatable insets. [Alejandro 080596]
94 //int LockInset(UpdatableInset * inset);
95 void ToggleLockedInsetCursor(int x, int y, int asc, int desc);
96 //void FitLockedInsetCursor(long x, long y, int asc, int desc);
97 //int UnlockInset(UpdatableInset * inset);
98 //void LockedInsetStoreUndo(Undo::undo_kind kind);
100 /* this is for asyncron updating. UpdateInsetUpdateList will be called
101 automatically from LyX. Just insert the Inset into the Updatelist */
102 //void UpdateInsetUpdateList();
103 //void PutInsetIntoInsetUpdateList(Inset * inset);
105 //InsetUpdateStruct * InsetUpdateList = 0;
109 -----------------------------------------------------------------------
113 void ShowMessage(Buffer const * buf,
119 string const str = msg1 + ' ' + msg2 + ' ' + msg3;
120 buf->getUser()->owner()->message(str);
122 lyxerr << msg1 << msg2 << msg3 << endl;
133 // should be moved to lyxfunc.C
134 bool MenuWrite(BufferView * bv, Buffer * buffer)
137 XFlush(fl_get_display());
139 if (!buffer->save()) {
140 string const fname = buffer->fileName();
141 string const s = MakeAbsPath(fname);
142 if (AskQuestion(_("Save failed. Rename and try again?"),
143 MakeDisplayPath(s, 50),
144 _("(If not, document is not saved.)"))) {
145 return WriteAs(bv, buffer);
149 lastfiles->newFile(buffer->fileName());
155 // should be moved to BufferView.C
156 // Half of this func should be in LyXView, the rest in BufferView.
157 bool WriteAs(BufferView * bv, Buffer * buffer, string const & filename)
159 string fname = buffer->fileName();
160 string oldname = fname;
162 if (filename.empty()) {
164 FileDialog fileDlg(bv->owner(),
165 _("Choose a filename to save document as"),
167 make_pair(string(_("Documents")),
168 string(lyxrc.document_path)),
169 make_pair(string(_("Templates")),
170 string(lyxrc.template_path)));
172 if (!IsLyXFilename(fname))
175 FileDialog::Result result =
176 fileDlg.Select(OnlyPath(fname),
177 _("*.lyx|LyX Documents (*.lyx)"),
178 OnlyFilename(fname));
180 if (result.first == FileDialog::Later)
183 fname = result.second;
188 // Make sure the absolute filename ends with appropriate suffix
189 fname = MakeAbsPath(fname);
190 if (!IsLyXFilename(fname))
195 // Same name as we have already?
196 if (!buffer->isUnnamed() && fname == oldname) {
197 if (!AskQuestion(_("Same name as document already has:"),
198 MakeDisplayPath(fname, 50),
201 // Falls through to name change and save
203 // No, but do we have another file with this name open?
204 else if (!buffer->isUnnamed() && bufferlist.exists(fname)) {
205 if (AskQuestion(_("Another document with same name open!"),
206 MakeDisplayPath(fname, 50),
207 _("Replace with current document?")))
209 bufferlist.close(bufferlist.getBuffer(fname));
211 // Ok, change the name of the buffer, but don't save!
212 buffer->setFileName(fname);
215 ShowMessage(buffer, _("Document renamed to '"),
216 MakeDisplayPath(fname), _("', but not saved..."));
219 } // Check whether the file exists
221 FileInfo const myfile(fname);
222 if (myfile.isOK() && !AskQuestion(_("Document already exists:"),
223 MakeDisplayPath(fname, 50),
228 // Ok, change the name of the buffer
229 buffer->setFileName(fname);
231 bool unnamed = buffer->isUnnamed();
232 buffer->setUnnamed(false);
234 if (!MenuWrite(bv, buffer)) {
235 buffer->setFileName(oldname);
236 buffer->setUnnamed(unnamed);
237 ShowMessage(buffer, _("Document could not be saved!"),
238 _("Holding the old name."), MakeDisplayPath(oldname));
241 // now remove the oldname autosave file if existant!
242 removeAutosaveFile(oldname);
247 int MenuRunChktex(Buffer * buffer)
251 if (buffer->isSGML()) {
252 WriteAlert(_("Chktex does not work with SGML derived documents."));
255 ret = buffer->runChktex();
261 s = _("No warnings found.");
262 } else if (ret == 1) {
263 s = _("One warning found.");
264 t = _("Use 'Edit->Go to Error' to find it.");
267 s += _(" warnings found.");
268 t = _("Use 'Edit->Go to Error' to find them.");
270 WriteAlert(_("Chktex run successfully"), s, t);
272 WriteAlert(_("Error!"), _("It seems chktex does not work."));
280 lyxerr[Debug::INFO] << "Running QuitLyX." << endl;
283 if (!bufferlist.qwriteAll())
286 lastfiles->writeFile(lyxrc.lastfiles);
289 // Set a flag that we do quitting from the program,
290 // so no refreshes are necessary.
293 // close buffers first
294 bufferlist.closeAll();
296 // do any other cleanup procedures now
297 lyxerr[Debug::INFO] << "Deleting tmp dir " << system_tempdir << endl;
299 DestroyLyXTmpDir(system_tempdir);
306 void AutoSave(BufferView * bv)
307 // should probably be moved into BufferList (Lgb)
308 // Perfect target for a thread...
310 if (!bv->available())
313 if (bv->buffer()->isBakClean() || bv->buffer()->isReadonly()) {
314 // We don't save now, but we'll try again later
315 bv->owner()->resetAutosaveTimer();
319 bv->owner()->message(_("Autosaving current document..."));
321 // create autosave filename
322 string fname = OnlyPath(bv->buffer()->fileName());
324 fname += OnlyFilename(bv->buffer()->fileName());
327 // tmp_ret will be located (usually) in /tmp
328 // will that be a problem?
329 pid_t const pid = fork(); // If you want to debug the autosave
330 // you should set pid to -1, and comment out the
332 if (pid == 0 || pid == -1) {
333 // pid = -1 signifies that lyx was unable
334 // to fork. But we will do the save
338 string const tmp_ret = lyx::tempName(string(), "lyxauto");
339 if (!tmp_ret.empty()) {
340 bv->buffer()->writeFile(tmp_ret, 1);
341 // assume successful write of tmp_ret
342 if (!lyx::rename(tmp_ret, fname)) {
344 // most likely couldn't move between filesystems
345 // unless write of tmp_ret failed
346 // so remove tmp file (if it exists)
347 lyx::unlink(tmp_ret);
354 // failed to write/rename tmp_ret so try writing direct
355 if (!bv->buffer()->writeFile(fname, 1)) {
356 // It is dangerous to do this in the child,
357 // but safe in the parent, so...
359 bv->owner()->message(_("Autosave Failed!"));
362 if (pid == 0) { // we are the child so...
367 bv->buffer()->markBakClean();
368 bv->owner()->resetAutosaveTimer();
373 // Copyright CHT Software Service GmbH
376 // create new file with template
379 Buffer * NewLyxFile(string const & filename)
381 // Split argument by :
383 string tmpname = split(filename, name, ':');
384 #ifdef __EMX__ // Fix me! lyx_cb.C may not be low level enough to allow this.
385 if (name.length() == 1
386 && isalpha(static_cast<unsigned char>(name[0]))
387 && (prefixIs(tmpname, "/") || prefixIs(tmpname, "\\"))) {
389 name += token(tmpname, ':', 0);
390 tmpname = split(tmpname, ':');
393 lyxerr[Debug::INFO] << "Arg is " << filename
394 << "\nName is " << name
395 << "\nTemplate is " << tmpname << endl;
397 // find a free buffer
398 Buffer * tmpbuf = bufferlist.newFile(name, tmpname);
400 lastfiles->newFile(tmpbuf->fileName());
405 // Insert ascii file (if filename is empty, prompt for one)
406 void InsertAsciiFile(BufferView * bv, string const & f, bool asParagraph)
410 if (!bv->available())
414 FileDialog fileDlg(bv->owner(), _("Select file to insert"),
415 (asParagraph) ? LFUN_FILE_INSERT_ASCII_PARA : LFUN_FILE_INSERT_ASCII);
417 FileDialog::Result result = fileDlg.Select(bv->owner()->buffer()->filepath);
419 if (result.first == FileDialog::Later)
422 fname = result.second;
430 if (!fi.readable()) {
431 WriteFSAlert(_("Error! Specified file is unreadable: "),
432 MakeDisplayPath(fname, 50));
436 ifstream ifs(fname.c_str());
438 WriteFSAlert(_("Error! Cannot open specified file: "),
439 MakeDisplayPath(fname, 50));
443 ifs.unsetf(ios::skipws);
444 istream_iterator<char> ii(ifs);
445 istream_iterator<char> end;
446 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
447 // We use this until the compilers get better...
449 copy(ii, end, back_inserter(tmp));
450 string const tmpstr(tmp.begin(), tmp.end());
452 // This is what we want to use and what we will use once the
453 // compilers get good enough.
454 //string tmpstr(ii, end); // yet a reason for using std::string
455 // alternate approach to get the file into a string:
457 copy(ii, end, back_inserter(tmpstr));
462 // clear the selection
463 bv->beforeChange(bv->text);
465 bv->text->insertStringAsLines(bv, tmpstr);
467 bv->text->insertStringAsParagraphs(bv, tmpstr);
468 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
472 void MenuInsertLabel(BufferView * bv, string const & arg)
475 bv->owner()->prohibitInput();
477 Paragraph * par = bv->text->cursor.par();
478 LyXLayout const * layout =
479 &textclasslist.Style(bv->buffer()->params.textclass,
482 if (layout->latextype == LATEX_PARAGRAPH && par->previous()) {
483 Paragraph * par2 = par->previous();
484 LyXLayout const * layout2 =
485 &textclasslist.Style(bv->buffer()->params.textclass,
487 if (layout2->latextype != LATEX_PARAGRAPH) {
492 string text = layout->latexname().substr(0, 3);
493 if (layout->latexname() == "theorem")
494 text = "thm"; // Create a correct prefix for prettyref
497 if (layout->latextype == LATEX_PARAGRAPH ||
498 lyxrc.label_init_length < 0)
500 string par_text = par->asString(bv->buffer(), false);
501 for (int i = 0; i < lyxrc.label_init_length; ++i) {
502 if (par_text.empty())
505 par_text = split(par_text, head, ' ');
507 text += '-'; // Is it legal to use spaces in
512 pair<bool, string> result =
513 askForText(_("Enter new label to insert:"), text);
515 label = frontStrip(strip(result.second));
518 if (!label.empty()) {
519 InsetCommandParams p( "label", label );
520 InsetLabel * inset = new InsetLabel( p );
521 bv->insertInset( inset );
523 bv->owner()->allowInput();
527 void MenuLayoutSave(BufferView * bv)
529 if (!bv->available())
532 if (AskQuestion(_("Do you want to save the current settings"),
533 _("for Character, Document, Paper and Quotes"),
534 _("as default for new documents?")))
535 bv->buffer()->saveParamsAsDefaults();
539 // This function runs "configure" and then rereads lyx.defaults to
540 // reconfigure the automatic settings.
541 void Reconfigure(BufferView * bv)
543 bv->owner()->message(_("Running configure..."));
545 // Run configure in user lyx directory
547 Systemcalls one(Systemcalls::System,
548 AddName(system_lyxdir, "configure"));
550 bv->owner()->message(_("Reloading configuration..."));
551 lyxrc.read(LibFileSearch(string(), "lyxrc.defaults"));
552 WriteAlert(_("The system has been reconfigured."),
553 _("You need to restart LyX to make use of any"),
554 _("updated document class specifications."));