]> git.lyx.org Git - lyx.git/blob - src/lyx_cb.C
Change the latex font names in order to match the names of type1inst.
[lyx.git] / src / lyx_cb.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright 1995 Matthias Ettrich,
7  *          Copyright 1995-2001 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include "lyx_cb.h"
14 #include "lyx_main.h"
15 #include "buffer.h"
16 #include "bufferlist.h"
17 #include "bufferview_funcs.h"
18 #include "debug.h"
19 #include "lastfiles.h"
20 #include "LyXView.h"
21 #include "lyxrc.h"
22 #include "lyxtext.h"
23 #include "gettext.h"
24 #include "BufferView.h"
25 #include "lyxtextclasslist.h"
26
27 #include "insets/insetlabel.h"
28
29 #include "frontends/Alert.h"
30 #include "frontends/FileDialog.h"
31 #include "frontends/GUIRunTime.h"
32
33 #include "support/FileInfo.h"
34 #include "support/filetools.h"
35 #include "support/path.h"
36 #include "support/syscall.h"
37 #include "support/lstrings.h"
38
39 #include <fstream>
40 #include <algorithm>
41 #include <utility> 
42 #include <iostream>
43
44 using std::vector;
45 using std::ifstream;
46 using std::copy;
47 using std::endl;
48 using std::ios;
49 using std::back_inserter;
50 using std::istream_iterator;
51 using std::pair;
52 using std::make_pair;
53
54 extern BufferList bufferlist;
55 // this should be static, but I need it in buffer.C
56 bool quitting;  // flag, that we are quitting the program
57 extern bool finished; // all cleanup done just let it run through now.
58
59 /* 
60    This is the inset locking stuff needed for mathed --------------------
61
62    an inset can simple call LockInset in it's edit call and *ONLY* in it's
63    edit call.
64    Inset::Edit() can only be called by the main lyx module.
65
66    Then the inset may modify the menu's and/or iconbars. 
67
68    Unlocking is either done by LyX or the inset itself with a UnlockInset-call
69
70    During the lock, all button and keyboard events will be modified
71    and send to the inset through the following inset-features. Note that
72    Inset::insetUnlock will be called from inside UnlockInset. It is meant
73    to contain the code for restoring the menus and things like this.
74
75    
76    virtual void insetButtonPress(int x, int y, int button);
77    virtual void insetButtonRelease(int x, int y, int button);
78    virtual void insetKeyPress(XKeyEvent *ev);
79    virtual void insetMotionNotify(int x, int y, int state);
80    virtual void insetUnlock();
81
82    If a inset wishes any redraw and/or update it just has to call
83    UpdateInset(this).
84    It's is completly irrelevant, where the inset is. UpdateInset will
85    find it in any paragraph in any buffer. 
86    Of course the_locking_inset and the insets in the current paragraph/buffer
87    are checked first, so no performance problem should occur.
88    
89    Hope that's ok for the beginning, Alejandro,
90    sorry that I needed so much time,
91
92                   Matthias
93    */
94
95 //void UpdateInset(BufferView * bv, Inset * inset, bool mark_dirty = true);
96
97 /* these functions return 1 if an error occured, 
98    otherwise 0 */
99 // Now they work only for updatable insets. [Alejandro 080596]
100 //int LockInset(UpdatableInset * inset);
101 void ToggleLockedInsetCursor(int x, int y, int asc, int desc);
102 //void FitLockedInsetCursor(long x, long y, int asc, int desc);
103 //int UnlockInset(UpdatableInset * inset);
104 //void LockedInsetStoreUndo(Undo::undo_kind kind);
105
106 /* this is for asyncron updating. UpdateInsetUpdateList will be called
107    automatically from LyX. Just insert the Inset into the Updatelist */
108 //void UpdateInsetUpdateList();
109 //void PutInsetIntoInsetUpdateList(Inset * inset);
110
111 //InsetUpdateStruct * InsetUpdateList = 0;
112
113
114 /*
115   -----------------------------------------------------------------------
116  */
117
118
119 void ShowMessage(Buffer const * buf,
120                  string const & msg1,
121                  string const & msg2,
122                  string const & msg3)
123 {
124         if (lyxrc.use_gui
125             && buf && buf->getUser() && buf->getUser()->owner()) {
126                         string const str = msg1 + ' ' + msg2 + ' ' + msg3;
127                         buf->getUser()->owner()->message(str);
128         } else
129                 lyxerr << msg1 << msg2 << msg3 << endl;
130 }
131
132
133 //
134 // Menu callbacks
135 //
136
137 //
138 // File menu
139 //
140 // should be moved to lyxfunc.C
141 bool MenuWrite(BufferView * bv, Buffer * buffer)
142 {
143         // FIXME: needed ?
144         XFlush(GUIRunTime::x11Display());
145  
146         if (!buffer->save()) {
147                 if (Alert::askQuestion(_("Save failed. Rename and try again?"),
148                                 MakeDisplayPath(buffer->fileName(), 50),
149                                 _("(If not, document is not saved.)"))) {
150                         return WriteAs(bv, buffer);
151                 }
152                 return false;
153         } else
154                 lastfiles->newFile(buffer->fileName());
155         return true;
156 }
157
158
159
160 // should be moved to BufferView.C
161 // Half of this func should be in LyXView, the rest in BufferView.
162 bool WriteAs(BufferView * bv, Buffer * buffer, string const & filename)
163 {
164         string fname = buffer->fileName();
165         string const oldname = fname;
166
167         if (filename.empty()) {
168
169                 FileDialog fileDlg(bv->owner(),
170                                    _("Choose a filename to save document as"),
171                         LFUN_WRITEAS,
172                         make_pair(string(_("Documents|#o#O")),
173                                   string(lyxrc.document_path)),
174                         make_pair(string(_("Templates|#T#t")),
175                                   string(lyxrc.template_path)));
176
177                 if (!IsLyXFilename(fname))
178                         fname += ".lyx";
179
180                 FileDialog::Result result =
181                         fileDlg.Select(OnlyPath(fname),
182                                        _("*.lyx|LyX Documents (*.lyx)"),
183                                        OnlyFilename(fname));
184
185                 if (result.first == FileDialog::Later)
186                         return false;
187
188                 fname = result.second;
189
190                 if (fname.empty())
191                         return false;
192
193                 // Make sure the absolute filename ends with appropriate suffix
194                 fname = MakeAbsPath(fname);
195                 if (!IsLyXFilename(fname))
196                         fname += ".lyx";
197         } else
198                 fname = filename;
199
200         // Same name as we have already?
201         if (!buffer->isUnnamed() && fname == oldname) {
202                 if (!Alert::askQuestion(_("Same name as document already has:"),
203                                  MakeDisplayPath(fname, 50),
204                                  _("Save anyway?")))
205                         return false;
206                 // Falls through to name change and save
207         } 
208         // No, but do we have another file with this name open?
209         else if (!buffer->isUnnamed() && bufferlist.exists(fname)) {
210                 if (Alert::askQuestion(_("Another document with same name open!"),
211                                 MakeDisplayPath(fname, 50),
212                                 _("Replace with current document?")))
213                         {
214                                 bufferlist.close(bufferlist.getBuffer(fname));
215
216                                 // Ok, change the name of the buffer, but don't save!
217                                 buffer->setFileName(fname);
218                                 buffer->markDirty();
219
220                                 ShowMessage(buffer, _("Document renamed to '"),
221                                                 MakeDisplayPath(fname), _("', but not saved..."));
222                 }
223                 return false;
224         } // Check whether the file exists
225         else {
226                 FileInfo const myfile(fname);
227                 if (myfile.isOK() && !Alert::askQuestion(_("Document already exists:"), 
228                                                   MakeDisplayPath(fname, 50),
229                                                   _("Replace file?")))
230                         return false;
231         }
232
233         // Ok, change the name of the buffer
234         buffer->setFileName(fname);
235         buffer->markDirty();
236         bool unnamed = buffer->isUnnamed();
237         buffer->setUnnamed(false);
238
239         if (!MenuWrite(bv, buffer)) {
240             buffer->setFileName(oldname);
241             buffer->setUnnamed(unnamed);
242             ShowMessage(buffer, _("Document could not be saved!"),
243                         _("Holding the old name."), MakeDisplayPath(oldname));
244             return false;
245         }
246         // now remove the oldname autosave file if existant!
247         removeAutosaveFile(oldname);
248         return true;
249 }
250
251
252 int MenuRunChktex(Buffer * buffer)
253 {
254         int ret;
255
256         if (buffer->isSGML()) {
257                 Alert::alert(_("Chktex does not work with SGML derived documents."));
258                 return 0;
259         } else 
260                 ret = buffer->runChktex();
261    
262         if (ret >= 0) {
263                 string s;
264                 string t;
265                 if (ret == 0) {
266                         s = _("No warnings found.");
267                 } else if (ret == 1) {
268                         s = _("One warning found.");
269                         t = _("Use `Navigate->Error' to find it.");
270                 } else {
271                         s += tostr(ret);
272                         s += _(" warnings found.");
273                         t = _("Use `Navigate->Error' to find them.");
274                 }
275                 Alert::alert(_("Chktex run successfully"), s, t);
276         } else {
277                 Alert::alert(_("Error!"), _("It seems chktex does not work."));
278         }
279         return ret;
280 }
281
282
283 void QuitLyX()
284 {
285         lyxerr[Debug::INFO] << "Running QuitLyX." << endl;
286
287         if (lyxrc.use_gui) {
288                 if (!bufferlist.qwriteAll())
289                         return;
290
291                 lastfiles->writeFile(lyxrc.lastfiles);
292         }
293
294         // Set a flag that we do quitting from the program,
295         // so no refreshes are necessary.
296         quitting = true;
297
298         // close buffers first
299         bufferlist.closeAll();
300
301         // do any other cleanup procedures now
302         lyxerr[Debug::INFO] << "Deleting tmp dir " << system_tempdir << endl;
303
304         DestroyLyXTmpDir(system_tempdir);
305
306         finished = true;
307 }
308
309
310
311 void AutoSave(BufferView * bv)
312         // should probably be moved into BufferList (Lgb)
313         // Perfect target for a thread...
314 {
315         if (!bv->available())
316                 return;
317
318         if (bv->buffer()->isBakClean() || bv->buffer()->isReadonly()) {
319                 // We don't save now, but we'll try again later
320                 bv->owner()->resetAutosaveTimer();
321                 return;
322         }
323
324         bv->owner()->message(_("Autosaving current document..."));
325         
326         // create autosave filename
327         string fname =  bv->buffer()->filePath();
328         fname += "#";
329         fname += OnlyFilename(bv->buffer()->fileName());
330         fname += "#";
331         
332         // tmp_ret will be located (usually) in /tmp
333         // will that be a problem?
334         pid_t const pid = fork(); // If you want to debug the autosave
335         // you should set pid to -1, and comment out the
336         // fork.
337         if (pid == 0 || pid == -1) {
338                 // pid = -1 signifies that lyx was unable
339                 // to fork. But we will do the save
340                 // anyway.
341                 bool failed = false;
342                 
343                 string const tmp_ret = lyx::tempName(string(), "lyxauto");
344                 if (!tmp_ret.empty()) {
345                         bv->buffer()->writeFile(tmp_ret, 1);
346                         // assume successful write of tmp_ret
347                         if (!lyx::rename(tmp_ret, fname)) {
348                                 failed = true;
349                                 // most likely couldn't move between filesystems
350                                 // unless write of tmp_ret failed
351                                 // so remove tmp file (if it exists)
352                                 lyx::unlink(tmp_ret);
353                         }
354                 } else {
355                         failed = true;
356                 }
357                 
358                 if (failed) {
359                         // failed to write/rename tmp_ret so try writing direct
360                         if (!bv->buffer()->writeFile(fname, 1)) {
361                                 // It is dangerous to do this in the child,
362                                 // but safe in the parent, so...
363                                 if (pid == -1)
364                                         bv->owner()->message(_("Autosave failed!"));
365                         }
366                 }
367                 if (pid == 0) { // we are the child so...
368                         _exit(0);
369                 }
370         }
371         
372         bv->buffer()->markBakClean();
373         bv->owner()->resetAutosaveTimer();
374 }
375
376
377 //
378 // Copyright CHT Software Service GmbH
379 // Uwe C. Schroeder
380 //
381 // create new file with template
382 // SERVERCMD !
383 //
384 Buffer * NewLyxFile(string const & filename)
385 {
386         // Split argument by :
387         string name;
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, "\\"))) {
393                 name += ':';
394                 name += token(tmpname, ':', 0);
395                 tmpname = split(tmpname, ':');
396         }
397 #endif
398         lyxerr[Debug::INFO] << "Arg is " << filename
399                             << "\nName is " << name
400                             << "\nTemplate is " << tmpname << endl;
401
402         // find a free buffer 
403         Buffer * tmpbuf = bufferlist.newFile(name, tmpname);
404         if (tmpbuf)
405                 lastfiles->newFile(tmpbuf->fileName());
406         return tmpbuf;
407 }
408
409
410 // Insert ascii file (if filename is empty, prompt for one)
411 void InsertAsciiFile(BufferView * bv, string const & f, bool asParagraph)
412 {
413         string fname = f;
414
415         if (!bv->available()) 
416                 return;
417      
418         if (fname.empty()) {
419                 FileDialog fileDlg(bv->owner(), _("Select file to insert"),
420                         (asParagraph) ? LFUN_FILE_INSERT_ASCII_PARA : LFUN_FILE_INSERT_ASCII);
421  
422                 FileDialog::Result result = fileDlg.Select(bv->owner()->buffer()->filePath());
423
424                 if (result.first == FileDialog::Later)
425                         return;
426
427                 fname = result.second;
428
429                 if (fname.empty()) 
430                         return;
431         }
432
433         FileInfo fi(fname);
434
435         if (!fi.readable()) {
436                 Alert::err_alert(_("Error! Specified file is unreadable: "),
437                              MakeDisplayPath(fname, 50));
438                 return;
439         }
440
441         ifstream ifs(fname.c_str());
442         if (!ifs) {
443                 Alert::err_alert(_("Error! Cannot open specified file: "),
444                              MakeDisplayPath(fname, 50));
445                 return;
446         }
447
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...
453         vector<char> tmp;
454         copy(ii, end, back_inserter(tmp));
455         string const tmpstr(tmp.begin(), tmp.end());
456 #else
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:
461         string tmpstr;
462         copy(ii, end, back_inserter(tmpstr));
463 #endif
464         // insert the string
465         bv->hideCursor();
466         
467         // clear the selection
468         bv->beforeChange(bv->text);
469         if (!asParagraph)
470                 bv->text->insertStringAsLines(bv, tmpstr);
471         else
472                 bv->text->insertStringAsParagraphs(bv, tmpstr);
473         bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
474 }
475
476
477 void MenuInsertLabel(BufferView * bv, string const & arg)
478 {
479         string label(arg);
480         bv->owner()->prohibitInput();
481         if (label.empty()) {
482                 Paragraph * par = bv->getLyXText()->cursor.par();
483                 LyXLayout const * layout =
484                         &textclasslist.Style(bv->buffer()->params.textclass,
485                                              par->getLayout());
486
487                 if (layout->latextype == LATEX_PARAGRAPH && par->previous()) {
488                         Paragraph * par2 = par->previous();
489                         LyXLayout const * layout2 =
490                                 &textclasslist.Style(bv->buffer()->params.textclass,
491                                                      par2->getLayout());
492                         if (layout2->latextype != LATEX_PARAGRAPH) {
493                                 par = par2;
494                                 layout = layout2;
495                         }
496                 }
497                 string text = layout->latexname().substr(0, 3);
498                 if (layout->latexname() == "theorem")
499                         text = "thm"; // Create a correct prefix for prettyref
500
501                 text += ":";
502                 if (layout->latextype == LATEX_PARAGRAPH ||
503                     lyxrc.label_init_length < 0)
504                         text.erase();
505                 string par_text = par->asString(bv->buffer(), false);
506                 for (int i = 0; i < lyxrc.label_init_length; ++i) {
507                         if (par_text.empty())
508                                 break;
509                         string head;
510                         par_text = split(par_text, head, ' ');
511                         if (i > 0)
512                                 text += '-'; // Is it legal to use spaces in
513                                              // labels ?
514                         text += head;
515                 }
516
517                 pair<bool, string> result =
518                         Alert::askForText(_("Enter new label to insert:"), text);
519                 if (result.first) {
520                         label = frontStrip(strip(result.second));
521                 }
522         }
523         if (!label.empty()) {
524                 InsetCommandParams p( "label", label );
525                 InsetLabel * inset = new InsetLabel( p );
526                 bv->insertInset( inset );
527         }
528         bv->owner()->allowInput();
529 }
530
531
532 // This function runs "configure" and then rereads lyx.defaults to
533 // reconfigure the automatic settings.
534 void Reconfigure(BufferView * bv)
535 {
536         bv->owner()->message(_("Running configure..."));
537
538         // Run configure in user lyx directory
539         Path p(user_lyxdir);
540         Systemcalls one(Systemcalls::System, 
541                         AddName(system_lyxdir, "configure"));
542         p.pop();
543         bv->owner()->message(_("Reloading configuration..."));
544         lyxrc.read(LibFileSearch(string(), "lyxrc.defaults"));
545         Alert::alert(_("The system has been reconfigured."), 
546                    _("You need to restart LyX to make use of any"),
547                    _("updated document class specifications."));
548 }