1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich,
7 * Copyright 1995-2000 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"
42 using std::back_inserter;
43 using std::istream_iterator;
47 extern BufferList bufferlist;
48 // this should be static, but I need it in buffer.C
49 bool quitting; // flag, that we are quitting the program
50 extern bool finished; // all cleanup done just let it run through now.
53 This is the inset locking stuff needed for mathed --------------------
55 an inset can simple call LockInset in it's edit call and *ONLY* in it's
57 Inset::Edit() can only be called by the main lyx module.
59 Then the inset may modify the menu's and/or iconbars.
61 Unlocking is either done by LyX or the inset itself with a UnlockInset-call
63 During the lock, all button and keyboard events will be modified
64 and send to the inset through the following inset-features. Note that
65 Inset::InsetUnlock will be called from inside UnlockInset. It is meant
66 to contain the code for restoring the menus and things like this.
69 virtual void InsetButtonPress(int x, int y, int button);
70 virtual void InsetButtonRelease(int x, int y, int button);
71 virtual void InsetKeyPress(XKeyEvent *ev);
72 virtual void InsetMotionNotify(int x, int y, int state);
73 virtual void InsetUnlock();
75 If a inset wishes any redraw and/or update it just has to call
77 It's is completly irrelevant, where the inset is. UpdateInset will
78 find it in any paragraph in any buffer.
79 Of course the_locking_inset and the insets in the current paragraph/buffer
80 are checked first, so no performance problem should occur.
82 Hope that's ok for the beginning, Alejandro,
83 sorry that I needed so much time,
88 //void UpdateInset(BufferView * bv, Inset * inset, bool mark_dirty = true);
90 /* these functions return 1 if an error occured,
92 // Now they work only for updatable insets. [Alejandro 080596]
93 //int LockInset(UpdatableInset * inset);
94 void ToggleLockedInsetCursor(int x, int y, int asc, int desc);
95 //void FitLockedInsetCursor(long x, long y, int asc, int desc);
96 //int UnlockInset(UpdatableInset * inset);
97 //void LockedInsetStoreUndo(Undo::undo_kind kind);
99 /* this is for asyncron updating. UpdateInsetUpdateList will be called
100 automatically from LyX. Just insert the Inset into the Updatelist */
101 //void UpdateInsetUpdateList();
102 //void PutInsetIntoInsetUpdateList(Inset * inset);
104 //InsetUpdateStruct * InsetUpdateList = 0;
108 -----------------------------------------------------------------------
112 void ShowMessage(Buffer const * buf,
118 string const str = msg1 + ' ' + msg2 + ' ' + msg3;
119 buf->getUser()->owner()->message(str);
121 lyxerr << msg1 << msg2 << msg3 << endl;
132 // should be moved to lyxfunc.C
133 bool MenuWrite(BufferView * bv, Buffer * buffer)
136 XFlush(fl_get_display());
138 if (!buffer->save()) {
139 string const fname = buffer->fileName();
140 string const s = MakeAbsPath(fname);
141 if (AskQuestion(_("Save failed. Rename and try again?"),
142 MakeDisplayPath(s, 50),
143 _("(If not, document is not saved.)"))) {
144 return WriteAs(bv, buffer);
148 lastfiles->newFile(buffer->fileName());
154 // should be moved to BufferView.C
155 // Half of this func should be in LyXView, the rest in BufferView.
156 bool WriteAs(BufferView * bv, Buffer * buffer, string const & filename)
158 string fname = buffer->fileName();
159 string oldname = fname;
161 if (filename.empty()) {
163 FileDialog fileDlg(bv->owner(),
164 _("Choose a filename to save document as"),
166 make_pair(string(_("Documents")),
167 string(lyxrc.document_path)),
168 make_pair(string(_("Templates")),
169 string(lyxrc.template_path)));
171 if (!IsLyXFilename(fname))
174 FileDialog::Result result =
175 fileDlg.Select(OnlyPath(fname),
176 _("*.lyx|LyX Documents (*.lyx)"),
177 OnlyFilename(fname));
179 if (result.first == FileDialog::Later)
182 fname = result.second;
187 // Make sure the absolute filename ends with appropriate suffix
188 fname = MakeAbsPath(fname);
189 if (!IsLyXFilename(fname))
194 // Same name as we have already?
195 if (!buffer->isUnnamed() && fname == oldname) {
196 if (!AskQuestion(_("Same name as document already has:"),
197 MakeDisplayPath(fname, 50),
200 // Falls through to name change and save
202 // No, but do we have another file with this name open?
203 else if (!buffer->isUnnamed() && bufferlist.exists(fname)) {
204 if (AskQuestion(_("Another document with same name open!"),
205 MakeDisplayPath(fname, 50),
206 _("Replace with current document?")))
208 bufferlist.close(bufferlist.getBuffer(fname));
210 // Ok, change the name of the buffer, but don't save!
211 buffer->setFileName(fname);
214 ShowMessage(buffer, _("Document renamed to '"),
215 MakeDisplayPath(fname), _("', but not saved..."));
218 } // Check whether the file exists
220 FileInfo const myfile(fname);
221 if (myfile.isOK() && !AskQuestion(_("Document already exists:"),
222 MakeDisplayPath(fname, 50),
227 // Ok, change the name of the buffer
228 buffer->setFileName(fname);
230 bool unnamed = buffer->isUnnamed();
231 buffer->setUnnamed(false);
233 if (!MenuWrite(bv, buffer)) {
234 buffer->setFileName(oldname);
235 buffer->setUnnamed(unnamed);
236 ShowMessage(buffer, _("Document could not be saved!"),
237 _("Holding the old name."), MakeDisplayPath(oldname));
240 // now remove the oldname autosave file if existant!
241 removeAutosaveFile(oldname);
246 int MenuRunChktex(Buffer * buffer)
250 if (buffer->isSGML()) {
251 WriteAlert(_("Chktex does not work with SGML derived documents."));
254 ret = buffer->runChktex();
260 s = _("No warnings found.");
261 } else if (ret == 1) {
262 s = _("One warning found.");
263 t = _("Use 'Edit->Go to Error' to find it.");
266 s += _(" warnings found.");
267 t = _("Use 'Edit->Go to Error' to find them.");
269 WriteAlert(_("Chktex run successfully"), s, t);
271 WriteAlert(_("Error!"), _("It seems chktex does not work."));
279 lyxerr.debug() << "Running QuitLyX." << endl;
282 if (!bufferlist.QwriteAll())
285 lastfiles->writeFile(lyxrc.lastfiles);
288 // Set a flag that we do quitting from the program,
289 // so no refreshes are necessary.
292 // close buffers first
293 bufferlist.closeAll();
295 // do any other cleanup procedures now
296 lyxerr.debug() << "Deleting tmp dir " << system_tempdir << endl;
298 DestroyLyXTmpDir(system_tempdir);
305 void AutoSave(BufferView * bv)
306 // should probably be moved into BufferList (Lgb)
307 // Perfect target for a thread...
309 if (!bv->available())
312 if (bv->buffer()->isBakClean() || bv->buffer()->isReadonly()) {
313 // We don't save now, but we'll try again later
314 bv->owner()->resetAutosaveTimer();
318 bv->owner()->message(_("Autosaving current document..."));
320 // create autosave filename
321 string fname = OnlyPath(bv->buffer()->fileName());
323 fname += OnlyFilename(bv->buffer()->fileName());
326 // tmp_ret will be located (usually) in /tmp
327 // will that be a problem?
328 pid_t const pid = fork(); // If you want to debug the autosave
329 // you should set pid to -1, and comment out the
331 if (pid == 0 || pid == -1) {
332 // pid = -1 signifies that lyx was unable
333 // to fork. But we will do the save
337 string const tmp_ret = lyx::tempName(string(), "lyxauto");
338 if (!tmp_ret.empty()) {
339 bv->buffer()->writeFile(tmp_ret, 1);
340 // assume successful write of tmp_ret
341 if (!lyx::rename(tmp_ret, fname)) {
343 // most likely couldn't move between filesystems
344 // unless write of tmp_ret failed
345 // so remove tmp file (if it exists)
346 lyx::unlink(tmp_ret);
353 // failed to write/rename tmp_ret so try writing direct
354 if (!bv->buffer()->writeFile(fname, 1)) {
355 // It is dangerous to do this in the child,
356 // but safe in the parent, so...
358 bv->owner()->message(_("Autosave Failed!"));
361 if (pid == 0) { // we are the child so...
366 bv->buffer()->markBakClean();
367 bv->owner()->resetAutosaveTimer();
372 // Copyright CHT Software Service GmbH
375 // create new file with template
378 Buffer * NewLyxFile(string const & filename)
380 // Split argument by :
382 string tmpname = split(filename, name, ':');
383 #ifdef __EMX__ // Fix me! lyx_cb.C may not be low level enough to allow this.
384 if (name.length() == 1
385 && isalpha(static_cast<unsigned char>(name[0]))
386 && (prefixIs(tmpname, "/") || prefixIs(tmpname, "\\"))) {
388 name += token(tmpname, ':', 0);
389 tmpname = split(tmpname, ':');
392 lyxerr.debug() << "Arg is " << filename
393 << "\nName is " << name
394 << "\nTemplate is " << tmpname << endl;
396 // find a free buffer
397 Buffer * tmpbuf = bufferlist.newFile(name, tmpname);
399 lastfiles->newFile(tmpbuf->fileName());
404 // Insert ascii file (if filename is empty, prompt for one)
405 void InsertAsciiFile(BufferView * bv, string const & f, bool asParagraph)
409 if (!bv->available())
413 FileDialog fileDlg(bv->owner(), _("Select file to insert"),
414 (asParagraph) ? LFUN_FILE_INSERT_ASCII_PARA : LFUN_FILE_INSERT_ASCII);
416 FileDialog::Result result = fileDlg.Select(bv->owner()->buffer()->filepath);
418 if (result.first == FileDialog::Later)
421 fname = result.second;
429 if (!fi.readable()) {
430 WriteFSAlert(_("Error! Specified file is unreadable: "),
431 MakeDisplayPath(fname, 50));
435 ifstream ifs(fname.c_str());
437 WriteFSAlert(_("Error! Cannot open specified file: "),
438 MakeDisplayPath(fname, 50));
442 ifs.unsetf(ios::skipws);
443 istream_iterator<char> ii(ifs);
444 istream_iterator<char> end;
445 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
446 // We use this until the compilers get better...
448 copy(ii, end, back_inserter(tmp));
449 string const tmpstr(tmp.begin(), tmp.end());
451 // This is what we want to use and what we will use once the
452 // compilers get good enough.
453 //string tmpstr(ii, end); // yet a reason for using std::string
454 // alternate approach to get the file into a string:
456 copy(ii, end, back_inserter(tmpstr));
461 // clear the selection
462 bv->beforeChange(bv->text);
464 bv->text->InsertStringA(bv, tmpstr);
466 bv->text->InsertStringB(bv, tmpstr);
467 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
471 void MenuInsertLabel(BufferView * bv, string const & arg)
476 LyXParagraph * par = bv->text->cursor.par();
477 LyXLayout const * layout =
478 &textclasslist.Style(bv->buffer()->params.textclass,
481 if (layout->latextype == LATEX_PARAGRAPH && par->previous()) {
482 LyXParagraph * par2 = par->previous();
483 LyXLayout const * layout2 =
484 &textclasslist.Style(bv->buffer()->params.textclass,
486 if (layout2->latextype != LATEX_PARAGRAPH) {
491 string text = layout->latexname().substr(0, 3);
492 if (layout->latexname() == "theorem")
493 text = "thm"; // Create a correct prefix for prettyref
496 if (layout->latextype == LATEX_PARAGRAPH ||
497 lyxrc.label_init_length < 0)
499 string par_text = par->String(bv->buffer(), false);
500 for (int i = 0; i < lyxrc.label_init_length; ++i) {
501 if (par_text.empty())
504 par_text = split(par_text, head, ' ');
506 text += '-'; // Is it legal to use spaces in
511 pair<bool, string> result =
512 askForText(_("Enter new label to insert:"), text);
514 label = frontStrip(strip(result.second));
517 if (!label.empty()) {
518 InsetCommandParams p( "label", label );
519 InsetLabel * inset = new InsetLabel( p );
520 bv->insertInset( inset );
526 void MenuLayoutSave(BufferView * bv)
528 if (!bv->available())
531 if (AskQuestion(_("Do you want to save the current settings"),
532 _("for Character, Document, Paper and Quotes"),
533 _("as default for new documents?")))
534 bv->buffer()->saveParamsAsDefaults();
538 // This function runs "configure" and then rereads lyx.defaults to
539 // reconfigure the automatic settings.
540 void Reconfigure(BufferView * bv)
542 bv->owner()->message(_("Running configure..."));
544 // Run configure in user lyx directory
546 Systemcalls one(Systemcalls::System,
547 AddName(system_lyxdir, "configure"));
549 bv->owner()->message(_("Reloading configuration..."));
550 lyxrc.read(LibFileSearch(string(), "lyxrc.defaults"));
551 WriteAlert(_("The system has been reconfigured."),
552 _("You need to restart LyX to make use of any"),
553 _("updated document class specifications."));