]> git.lyx.org Git - lyx.git/blob - src/MenuBackend.C
More fixes to insettabular/text (and some missing features added).
[lyx.git] / src / MenuBackend.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 The LyX Team.
8  *
9  *
10  * ====================================================== */
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 #include <config.h>
17 #include <memory>
18 #include "support/LAssert.h"
19 #include "MenuBackend.h"
20 #include "lyxlex.h"
21 #include "LyXAction.h"
22 #include "debug.h"
23 #include "gettext.h"
24 #include "lastfiles.h"
25 #include "bufferlist.h"
26 #include "converter.h"
27 #include "exporter.h"
28 #include "importer.h"
29 #include "support/filetools.h"
30 #include "support/lyxfunctional.h"
31
32 extern LyXAction lyxaction;
33 extern LastFiles * lastfiles; 
34 extern BufferList bufferlist;
35
36 using std::endl;
37 using std::vector;
38 using std::pair;
39 using std::find_if;
40 using std::sort;
41
42 // This is the global menu definition
43 MenuBackend menubackend;
44
45
46 MenuItem::MenuItem(Kind kind, string const & label, 
47                    string const & command, bool optional) 
48         : kind_(kind), label_(label), optional_(optional)
49 {
50         switch (kind) {
51         case Separator:
52         case Documents:
53         case Lastfiles:
54         case Toc:
55         case References:
56         case ViewFormats:
57         case UpdateFormats:
58         case ExportFormats:
59         case ImportFormats:
60                 break;
61         case Command:
62                 action_ = lyxaction.LookupFunc(command);
63
64                 if (action_ == LFUN_UNKNOWN_ACTION) {
65                         lyxerr << "MenuItem(): LyX command `"
66                                << command << "' does not exist." << endl; 
67                 }
68                 if (optional_)
69                         lyxerr[Debug::GUI] << "Optional item " 
70                                            << command << endl; 
71                 break;
72         case Submenu:
73                 submenu_ = command;
74                 break;
75         }
76 }
77
78
79 Menu & Menu::add(MenuItem const & i)
80 {
81         items_.push_back(i);
82         return *this;
83 }
84
85
86 Menu & Menu::read(LyXLex & lex)
87 {
88         enum Menutags {
89                 md_item = 1,
90                 md_documents,
91                 md_endmenu,
92                 md_exportformats,
93                 md_importformats,
94                 md_lastfiles,
95                 md_optitem,
96                 md_references,
97                 md_separator,
98                 md_submenu,
99                 md_toc,
100                 md_updateformats,
101                 md_viewformats,
102                 md_last
103         };
104
105         struct keyword_item menutags[md_last - 1] = {
106                 { "documents", md_documents },
107                 { "end", md_endmenu },
108                 { "exportformats", md_exportformats },
109                 { "importformats", md_importformats },
110                 { "item", md_item },
111                 { "lastfiles", md_lastfiles },
112                 { "optitem", md_optitem }, 
113                 { "references", md_references },
114                 { "separator", md_separator },
115                 { "submenu", md_submenu },
116                 { "toc", md_toc },
117                 { "updateformats", md_updateformats },
118                 { "viewformats", md_viewformats }
119         };
120
121         lex.pushTable(menutags, md_last - 1);
122         if (lyxerr.debugging(Debug::PARSER))
123                 lex.printTable(lyxerr);
124
125         bool quit = false;
126         bool optional = false;
127
128         while (lex.IsOK() && !quit) {
129                 switch (lex.lex()) {
130                 case md_optitem:
131                         optional = true;
132                         // fallback to md_item
133                 case md_item: {
134                         lex.next();
135                         string name = _(lex.GetString());
136                         lex.next();
137                         string const command = lex.GetString();
138                         add(MenuItem(MenuItem::Command, name, 
139                                      command, optional));
140                         optional = false;
141                         break;
142                 }
143
144                 case md_separator:
145                         add(MenuItem(MenuItem::Separator));
146                         break;
147
148                 case md_lastfiles:
149                         add(MenuItem(MenuItem::Lastfiles));
150                         break;
151
152                 case md_documents:
153                         add(MenuItem(MenuItem::Documents));
154                         break;
155
156                 case md_toc:
157                         add(MenuItem(MenuItem::Toc));
158                         break;
159
160                 case md_references:
161                         add(MenuItem(MenuItem::References));
162                         break;
163
164                 case md_viewformats:
165                         add(MenuItem(MenuItem::ViewFormats));
166                         break;
167
168                 case md_updateformats:
169                         add(MenuItem(MenuItem::UpdateFormats));
170                         break;
171
172                 case md_exportformats:
173                         add(MenuItem(MenuItem::ExportFormats));
174                         break;
175
176                 case md_importformats:
177                         add(MenuItem(MenuItem::ImportFormats));
178                         break;
179
180                 case md_submenu: {
181                         lex.next();
182                         string mlabel = _(lex.GetString());
183                         lex.next();
184                         string mname = lex.GetString();
185                         add(MenuItem(MenuItem::Submenu, mlabel, mname));
186                         break;
187                 }
188
189                 case md_endmenu:
190                         quit = true;
191                         break;
192
193                 default:
194                         lex.printError("menubar::read: "
195                                        "Unknown menu tag: `$$Token'");
196                         break;
197                 }
198         }
199         lex.popTable();
200         return *this;
201 }
202
203
204 void Menu::checkShortcuts() const
205 {
206         // This is a quadratic algorithm, but we do not care because
207         // it is used for debugging only.
208         for (const_iterator it1 = begin(); it1 != end(); ++it1) {
209                 string shortcut = it1->shortcut();
210                 if (shortcut.empty())
211                         continue;
212                 if (!contains(it1->label(), shortcut))
213                         lyxerr << "Menu warning: menu entry \""
214                                << it1->label()
215                                << "\" does not contain shortcut `"
216                                << shortcut << '\'' << endl;
217                 for (const_iterator it2 = begin(); it2 != it1 ; ++it2) {
218                         if (!compare_no_case(it2->shortcut(), shortcut)) {
219                                 lyxerr << "Menu warning: menu entries "
220                                        << '"' << it1->fulllabel()
221                                        << "\" and \"" << it2->fulllabel()
222                                        << "\" share the same shortcut."
223                                        << endl;
224                         }
225                 }
226         }
227 }
228
229 void Menu::expand(Menu & tomenu, Buffer * buf) const
230 {
231         for (const_iterator cit = begin();
232              cit != end() ; ++cit) {
233                 switch ((*cit).kind()) {
234                 case MenuItem::Lastfiles: {
235                         int ii = 1;
236                         for (LastFiles::const_iterator lfit = lastfiles->begin();
237                              lfit != lastfiles->end() && ii < 10;
238                              ++lfit, ++ii) {
239                                 string label = tostr(ii) + ". "
240                                         + MakeDisplayPath((*lfit), 30)
241                                         + '|' + tostr(ii);
242                                 int action = lyxaction.
243                                         getPseudoAction(LFUN_FILE_OPEN,
244                                                         (*lfit));
245                                 tomenu.add(MenuItem(MenuItem::Command,
246                                                     label, action));
247                         }
248                 }
249                 break;
250                 
251                 case MenuItem::Documents: {
252                         vector<string> names = bufferlist.getFileNames();
253                         
254                         if (names.empty()) {
255                                 tomenu.add(MenuItem(MenuItem::Command,
256                                                     _("No Documents Open!"),
257                                                     LFUN_NOACTION));
258                                 break;
259                         }
260
261                         for (vector<string>::const_iterator docit = names.begin();
262                              docit != names.end() ; ++docit) {
263                                 int action =
264                                         lyxaction.getPseudoAction(LFUN_SWITCHBUFFER, *docit);
265                                 string label = MakeDisplayPath(*docit, 30);
266                                 tomenu.add(MenuItem(MenuItem::Command,
267                                                     label, action));
268                         }
269                 }
270                 break;
271
272                 case MenuItem::ImportFormats:
273                 case MenuItem::ViewFormats:
274                 case MenuItem::UpdateFormats:
275                 case MenuItem::ExportFormats: {
276                         vector<Format const *> formats;
277                         kb_action action;
278                         switch ((*cit).kind()) {
279                         case MenuItem::ImportFormats:
280                                 formats = Importer::GetImportableFormats();
281                                 action = LFUN_IMPORT;
282                                 break;
283                         case MenuItem::ViewFormats:
284                                 formats = Exporter::GetExportableFormats(buf, true); 
285                                 action = LFUN_PREVIEW;
286                                 break;
287                         case MenuItem::UpdateFormats:
288                                 formats = Exporter::GetExportableFormats(buf, true); 
289                                 action = LFUN_UPDATE;
290                                 break;
291                         default:
292                                 formats = Exporter::GetExportableFormats(buf, false); 
293                                 action = LFUN_EXPORT;
294                         }
295                         sort(formats.begin(), formats.end());
296
297                         for (vector<Format const *>::const_iterator fit = formats.begin();
298                              fit != formats.end() ; ++fit) {
299                                 if ((*fit)->dummy())
300                                         continue;
301                                 string label = (*fit)->prettyname();
302                                 if ((*cit).kind() == MenuItem::ImportFormats)
303                                         if ((*fit)->name() == "text")
304                                                 label = _("Ascii text as lines");
305                                         else if ((*fit)->name() == "textparagraph")
306                                                 label = _("Ascii text as paragraphs");
307                                 if (!(*fit)->shortcut().empty())
308                                         label += "|" + (*fit)->shortcut();
309                                 int action2 = lyxaction.
310                                         getPseudoAction(action, (*fit)->name());
311                                 tomenu.add(MenuItem(MenuItem::Command,
312                                                     label, action2));
313                         }
314                 }
315                 break;
316                         
317                 default:
318                         tomenu.add(*cit);
319                 }
320         }
321
322         // Check whether the shortcuts are unique
323         if (lyxerr.debugging(Debug::GUI))
324                 checkShortcuts();
325 }
326
327 bool Menu::hasSubmenu(string const & name) const
328 {
329         return find_if(begin(), end(),
330                        compare_memfun(&MenuItem::submenu, name)) != end();
331 }
332
333
334 void MenuBackend::read(LyXLex & lex)
335 {
336         enum Menutags {
337                 md_menu = 1,
338                 md_menubar,
339                 md_endmenuset,
340                 md_last
341         };
342
343         struct keyword_item menutags[md_last - 1] = {
344                 { "end", md_endmenuset },
345                 { "menu", md_menu },
346                 { "menubar", md_menubar }
347         };
348
349         //consistency check
350         if (compare_no_case(lex.GetString(), "menuset"))
351                 lyxerr << "Menubackend::read: ERROR wrong token:`"
352                        << lex.GetString() << '\'' << endl;
353
354         lex.pushTable(menutags, md_last - 1);
355         if (lyxerr.debugging(Debug::PARSER))
356                 lex.printTable(lyxerr);
357
358         bool quit = false;
359         bool menubar = false;
360
361         while (lex.IsOK() && !quit) {
362                 switch (lex.lex()) {
363                 case md_menubar: 
364                         menubar = true;
365                         // fallback to md_menu
366                 case md_menu: {
367                         lex.next();
368                         string name = lex.GetString();
369                         if (hasMenu(name)) {
370                                 if (getMenu(name).menubar() == menubar) {
371                                         getMenu(name).read(lex);
372                                 } else {
373                                         lex.printError("Cannot append to menu `$$Token' unless it is of the same type");
374                                         return;
375                                 }
376                         } else {                                
377                                 Menu menu(name, menubar);
378                                 menu.read(lex);
379                                 add(menu);
380                         }
381                         menubar = false;
382                         break;
383                 }
384                 case md_endmenuset:
385                         quit = true;
386                         break;
387                 default:
388                         lex.printError("menubackend::read: "
389                                        "Unknown menu tag: `$$Token'");
390                         break;
391                 }
392         }
393         lex.popTable();
394 }
395
396
397 void MenuBackend::defaults()
398 {
399         menulist_.clear();
400
401         lyxerr[Debug::GUI] << "MenuBackend::defaults: using default values" 
402                            << endl;
403
404         Menu file("file");
405         file
406                 .add(MenuItem(MenuItem::Command, _("New...|N"), "buffer-new"))
407                 .add(MenuItem(MenuItem::Command, _("Open...|O"), "buffer-open"))
408                 .add(MenuItem(MenuItem::Submenu, _("Import|I"), "import"))
409                 .add(MenuItem(MenuItem::Command, _("Quit|Q"), "lyx-quit"))
410                 .add(MenuItem(MenuItem::Separator))
411                 .add(MenuItem(MenuItem::Lastfiles));
412         add(file);
413
414         Menu import("import");
415         import
416                 .add(MenuItem(MenuItem::Command,
417                               _("LaTeX...|L"), "buffer-import latex"))
418                 .add(MenuItem(MenuItem::Command,
419                               _("LinuxDoc...|L"), "buffer-import linuxdoc"));
420         add(import);
421  
422         Menu edit("edit");
423         edit
424                 .add(MenuItem(MenuItem::Command, _("Cut"), "cut"))
425                 .add(MenuItem(MenuItem::Command, _("Copy"), "copy"))
426                 .add(MenuItem(MenuItem::Command, _("Paste"), "paste"))
427                 .add(MenuItem(MenuItem::Command, _("Emphasize"), "font-emph"));
428         add(edit);
429
430         Menu documents("documents");
431         documents.add(MenuItem(MenuItem::Documents));
432         add(documents);
433
434         Menu main("main", true);
435         main
436                 .add(MenuItem(MenuItem::Submenu, _("File|F"), "file"))
437                 .add(MenuItem(MenuItem::Submenu, _("Edit|E"), "edit"))
438                 .add(MenuItem(MenuItem::Submenu,
439                               _("Documents|D"), "documents"));
440         add(main);
441
442         Menu main_nobuffer("main_nobuffer", true);
443         main_nobuffer.add(MenuItem(MenuItem::Submenu, _("File|F"), "file"));
444         add(main_nobuffer);
445
446         if (lyxerr.debugging(Debug::GUI)) {
447                 for (const_iterator cit = begin();
448                     cit != end() ; ++cit)
449                         lyxerr << "Menu name: " << cit->name() 
450                                << ", Menubar: " << cit->menubar() 
451                                << endl;
452         }
453 }
454
455
456 void MenuBackend::add(Menu const & menu)
457 {
458         menulist_.push_back(menu);
459 }
460
461
462 bool MenuBackend::hasMenu(string const & name) const
463 {
464         return find_if(begin(), end(),
465                        compare_memfun(&Menu::name, name)) != end();
466 }
467
468
469 Menu const & MenuBackend::getMenu(string const & name) const
470 {
471         const_iterator cit = find_if(begin(), end(),
472                                      compare_memfun(&Menu::name, name));
473         Assert(cit != end());
474         return (*cit);
475 }
476
477
478 Menu & MenuBackend::getMenu(string const & name)
479 {
480         MenuList::iterator it = find_if(menulist_.begin(), menulist_.end(),
481                                         compare_memfun(&Menu::name, name));
482         Assert(it != menulist_.end());
483         return (*it);
484 }