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