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