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