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"
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()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
123 lyxerr << msg1 << msg2 << msg3 << endl;
134 // should be moved to lyxfunc.C
135 bool MenuWrite(BufferView * bv, Buffer * buffer)
138 XFlush(fl_get_display());
140 if (!buffer->save()) {
141 string const fname = buffer->fileName();
142 string const s = MakeAbsPath(fname);
143 if (AskQuestion(_("Save failed. Rename and try again?"),
144 MakeDisplayPath(s, 50),
145 _("(If not, document is not saved.)"))) {
146 return WriteAs(bv, buffer);
150 lastfiles->newFile(buffer->fileName());
156 // should be moved to BufferView.C
157 // Half of this func should be in LyXView, the rest in BufferView.
158 bool WriteAs(BufferView * bv, Buffer * buffer, string const & filename)
160 string fname = buffer->fileName();
161 string oldname = fname;
163 if (filename.empty()) {
165 FileDialog fileDlg(bv->owner(),
166 _("Choose a filename to save document as"),
168 make_pair(string(_("Documents")),
169 string(lyxrc.document_path)),
170 make_pair(string(_("Templates")),
171 string(lyxrc.template_path)));
173 if (!IsLyXFilename(fname))
176 FileDialog::Result result =
177 fileDlg.Select(OnlyPath(fname),
178 _("*.lyx|LyX Documents (*.lyx)"),
179 OnlyFilename(fname));
181 if (result.first == FileDialog::Later)
184 fname = result.second;
189 // Make sure the absolute filename ends with appropriate suffix
190 fname = MakeAbsPath(fname);
191 if (!IsLyXFilename(fname))
196 // Same name as we have already?
197 if (!buffer->isUnnamed() && fname == oldname) {
198 if (!AskQuestion(_("Same name as document already has:"),
199 MakeDisplayPath(fname, 50),
202 // Falls through to name change and save
204 // No, but do we have another file with this name open?
205 else if (!buffer->isUnnamed() && bufferlist.exists(fname)) {
206 if (AskQuestion(_("Another document with same name open!"),
207 MakeDisplayPath(fname, 50),
208 _("Replace with current document?")))
210 bufferlist.close(bufferlist.getBuffer(fname));
212 // Ok, change the name of the buffer, but don't save!
213 buffer->setFileName(fname);
216 ShowMessage(buffer, _("Document renamed to '"),
217 MakeDisplayPath(fname), _("', but not saved..."));
220 } // Check whether the file exists
222 FileInfo const myfile(fname);
223 if (myfile.isOK() && !AskQuestion(_("Document already exists:"),
224 MakeDisplayPath(fname, 50),
229 // Ok, change the name of the buffer
230 buffer->setFileName(fname);
232 bool unnamed = buffer->isUnnamed();
233 buffer->setUnnamed(false);
235 if (!MenuWrite(bv, buffer)) {
236 buffer->setFileName(oldname);
237 buffer->setUnnamed(unnamed);
238 ShowMessage(buffer, _("Document could not be saved!"),
239 _("Holding the old name."), MakeDisplayPath(oldname));
242 // now remove the oldname autosave file if existant!
243 removeAutosaveFile(oldname);
248 int MenuRunChktex(Buffer * buffer)
252 if (buffer->isSGML()) {
253 WriteAlert(_("Chktex does not work with SGML derived documents."));
256 ret = buffer->runChktex();
262 s = _("No warnings found.");
263 } else if (ret == 1) {
264 s = _("One warning found.");
265 t = _("Use 'Edit->Go to Error' to find it.");
268 s += _(" warnings found.");
269 t = _("Use 'Edit->Go to Error' to find them.");
271 WriteAlert(_("Chktex run successfully"), s, t);
273 WriteAlert(_("Error!"), _("It seems chktex does not work."));
281 lyxerr.debug() << "Running QuitLyX." << endl;
284 if (!bufferlist.QwriteAll())
287 lastfiles->writeFile(lyxrc.lastfiles);
290 // Set a flag that we do quitting from the program,
291 // so no refreshes are necessary.
294 // close buffers first
295 bufferlist.closeAll();
297 // do any other cleanup procedures now
298 lyxerr.debug() << "Deleting tmp dir " << system_tempdir << endl;
300 DestroyLyXTmpDir(system_tempdir);
307 void AutoSave(BufferView * bv)
308 // should probably be moved into BufferList (Lgb)
309 // Perfect target for a thread...
311 if (!bv->available())
314 if (bv->buffer()->isBakClean() || bv->buffer()->isReadonly()) {
315 // We don't save now, but we'll try again later
316 bv->owner()->resetAutosaveTimer();
320 bv->owner()->getLyXFunc()
321 ->Dispatch(LFUN_MESSAGE,
322 _("Autosaving current document..."));
324 // create autosave filename
325 string fname = OnlyPath(bv->buffer()->fileName());
327 fname += OnlyFilename(bv->buffer()->fileName());
330 // tmp_ret will be located (usually) in /tmp
331 // will that be a problem?
332 pid_t const pid = fork(); // If you want to debug the autosave
333 // you should set pid to -1, and comment out the
335 if (pid == 0 || pid == -1) {
336 // pid = -1 signifies that lyx was unable
337 // to fork. But we will do the save
341 string const tmp_ret = lyx::tempName(string(), "lyxauto");
342 if (!tmp_ret.empty()) {
343 bv->buffer()->writeFile(tmp_ret, 1);
344 // assume successful write of tmp_ret
345 if (!lyx::rename(tmp_ret, fname)) {
347 // most likely couldn't move between filesystems
348 // unless write of tmp_ret failed
349 // so remove tmp file (if it exists)
350 lyx::unlink(tmp_ret);
357 // failed to write/rename tmp_ret so try writing direct
358 if (!bv->buffer()->writeFile(fname, 1)) {
359 // It is dangerous to do this in the child,
360 // but safe in the parent, so...
362 bv->owner()->getLyXFunc()
363 ->Dispatch(LFUN_MESSAGE,
364 _("Autosave Failed!"));
367 if (pid == 0) { // we are the child so...
372 bv->buffer()->markBakClean();
373 bv->owner()->resetAutosaveTimer();
378 // Copyright CHT Software Service GmbH
381 // create new file with template
384 Buffer * NewLyxFile(string const & filename)
386 // Split argument by :
388 string tmpname = split(filename, name, ':');
389 #ifdef __EMX__ // Fix me! lyx_cb.C may not be low level enough to allow this.
390 if (name.length() == 1
391 && isalpha(static_cast<unsigned char>(name[0]))
392 && (prefixIs(tmpname, "/") || prefixIs(tmpname, "\\"))) {
394 name += token(tmpname, ':', 0);
395 tmpname = split(tmpname, ':');
398 lyxerr.debug() << "Arg is " << filename
399 << "\nName is " << name
400 << "\nTemplate is " << tmpname << endl;
402 // find a free buffer
403 Buffer * tmpbuf = bufferlist.newFile(name, tmpname);
405 lastfiles->newFile(tmpbuf->fileName());
410 // Insert ascii file (if filename is empty, prompt for one)
411 void InsertAsciiFile(BufferView * bv, string const & f, bool asParagraph)
415 if (!bv->available())
419 FileDialog fileDlg(bv->owner(), _("Select file to insert"),
420 (asParagraph) ? LFUN_FILE_INSERT_ASCII_PARA : LFUN_FILE_INSERT_ASCII);
422 FileDialog::Result result = fileDlg.Select(bv->owner()->buffer()->filepath);
424 if (result.first == FileDialog::Later)
427 fname = result.second;
435 if (!fi.readable()) {
436 WriteFSAlert(_("Error! Specified file is unreadable: "),
437 MakeDisplayPath(fname, 50));
441 ifstream ifs(fname.c_str());
443 WriteFSAlert(_("Error! Cannot open specified file: "),
444 MakeDisplayPath(fname, 50));
448 ifs.unsetf(ios::skipws);
449 istream_iterator<char> ii(ifs);
450 istream_iterator<char> end;
451 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
452 // We use this until the compilers get better...
454 copy(ii, end, back_inserter(tmp));
455 string const tmpstr(tmp.begin(), tmp.end());
457 // This is what we want to use and what we will use once the
458 // compilers get good enough.
459 //string tmpstr(ii, end); // yet a reason for using std::string
460 // alternate approach to get the file into a string:
462 copy(ii, end, back_inserter(tmpstr));
467 // clear the selection
468 bv->beforeChange(bv->text);
470 bv->text->InsertStringA(bv, tmpstr);
472 bv->text->InsertStringB(bv, tmpstr);
473 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
477 void MenuInsertLabel(BufferView * bv, string const & arg)
484 bv->text->cursor.par()->FirstPhysicalPar();
486 LyXParagraph * par = bv->text->cursor.par();
488 LyXLayout const * layout =
489 &textclasslist.Style(bv->buffer()->params.textclass,
493 if (layout->latextype == LATEX_PARAGRAPH && par->previous_) {
494 LyXParagraph * par2 = par->previous_->FirstPhysicalPar();
496 if (layout->latextype == LATEX_PARAGRAPH && par->previous()) {
497 LyXParagraph * par2 = par->previous();
499 LyXLayout const * layout2 =
500 &textclasslist.Style(bv->buffer()->params.textclass,
502 if (layout2->latextype != LATEX_PARAGRAPH) {
507 string text = layout->latexname().substr(0, 3);
508 if (layout->latexname() == "theorem")
509 text = "thm"; // Create a correct prefix for prettyref
511 if (par->footnoteflag==LyXParagraph::OPEN_FOOTNOTE)
512 switch (par->footnotekind) {
513 case LyXParagraph::FIG:
514 case LyXParagraph::WIDE_FIG:
517 case LyXParagraph::TAB:
518 case LyXParagraph::WIDE_TAB:
521 case LyXParagraph::ALGORITHM:
524 case LyXParagraph::FOOTNOTE:
525 case LyXParagraph::MARGIN:
530 if (layout->latextype == LATEX_PARAGRAPH ||
531 lyxrc.label_init_length < 0)
533 string par_text = par->String(bv->buffer(), false);
534 for (int i = 0; i < lyxrc.label_init_length; ++i) {
535 if (par_text.empty())
538 par_text = split(par_text, head, ' ');
540 text += '-'; // Is it legal to use spaces in
545 pair<bool, string> result =
546 askForText(_("Enter new label to insert:"), text);
548 label = frontStrip(strip(result.second));
551 if (!label.empty()) {
552 InsetCommandParams p( "label", label );
553 InsetLabel * inset = new InsetLabel( p );
554 bv->insertInset( inset );
560 void MenuLayoutSave(BufferView * bv)
562 if (!bv->available())
565 if (AskQuestion(_("Do you want to save the current settings"),
566 _("for Character, Document, Paper and Quotes"),
567 _("as default for new documents?")))
568 bv->buffer()->saveParamsAsDefaults();
572 // This function runs "configure" and then rereads lyx.defaults to
573 // reconfigure the automatic settings.
574 void Reconfigure(BufferView * bv)
576 bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
577 _("Running configure..."));
579 // Run configure in user lyx directory
581 Systemcalls one(Systemcalls::System,
582 AddName(system_lyxdir, "configure"));
584 bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE,
585 _("Reloading configuration..."));
586 lyxrc.read(LibFileSearch(string(), "lyxrc.defaults"));
587 WriteAlert(_("The system has been reconfigured."),
588 _("You need to restart LyX to make use of any"),
589 _("updated document class specifications."));