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