]> git.lyx.org Git - features.git/blob - src/MenuBackend.C
Dekel's import/export patch
[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 "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                                 bool same_before = 
266                                         fit != names.begin() &&
267                                         (*fit).format == (*(fit-1)).format;
268                                 bool same_after = 
269                                         fit+1 != names.end() &&
270                                         (*fit).format == (*(fit+1)).format;
271                                 if ((*fit).from &&
272                                     (same_before || same_after)) {
273                                         fmt += ":" + (*fit).from->name;
274                                         string head;
275                                         split((*fit).command, head, ' ');
276                                         label += _(" (using ") + head + ")";
277                                         if (!(*fit).format->shortcut.empty() &&
278                                             !same_before)
279                                                 label += "|" + (*fit).format->shortcut;
280                                 } else if (!(*fit).format->shortcut.empty())
281                                         label += "|" + (*fit).format->shortcut;
282                                 int action2 = lyxaction.getPseudoAction(action, fmt);
283                                 tomenu.add(MenuItem(MenuItem::Command,
284                                                     label, action2));
285                         }
286                 }
287                 break;
288
289                         
290                 default:
291                         tomenu.add(*cit);
292                 }
293         }
294 }
295
296
297 void MenuBackend::read(LyXLex & lex)
298 {
299         enum Menutags {
300                 md_menu = 1,
301                 md_menubar,
302                 md_endmenuset,
303                 md_last
304         };
305
306         struct keyword_item menutags[md_last - 1] = {
307                 { "end", md_endmenuset },
308                 { "menu", md_menu },
309                 { "menubar", md_menubar }
310         };
311
312         //consistency check
313         if (compare_no_case(lex.GetString(), "menuset"))
314                 lyxerr << "Menubackend::read: ERROR wrong token:`"
315                        << lex.GetString() << '\'' << endl;
316
317         lex.pushTable(menutags, md_last - 1);
318         if (lyxerr.debugging(Debug::PARSER))
319                 lex.printTable(lyxerr);
320
321         bool quit = false;
322         bool menubar = false;
323
324         while (lex.IsOK() && !quit) {
325                 switch(lex.lex()) {
326                 case md_menubar: 
327                         menubar = true;
328                         // fallback to md_menu
329                 case md_menu: {
330                         lex.next();
331                         string name = lex.GetString();
332                         if (hasMenu(name)) {
333                                 if (getMenu(name).menubar() == menubar) {
334                                         getMenu(name).read(lex);
335                                 } else {
336                                         lex.printError("Cannot append to menu `$$Token' unless it is of the same type");
337                                         return;
338                                 }
339                         } else {                                
340                                 Menu menu(name, menubar);
341                                 menu.read(lex);
342                                 add(menu);
343                         }
344                         menubar = false;
345                         break;
346                 }
347                 case md_endmenuset:
348                         quit = true;
349                         break;
350                 default:
351                         lex.printError("menubackend::read: "
352                                        "Unknown menu tag: `$$Token'");
353                         break;
354                 }
355         }
356         lex.popTable();
357 }
358
359
360 void MenuBackend::defaults()
361 {
362         menulist_.clear();
363
364         lyxerr[Debug::GUI] << "MenuBackend::defaults: using default values" 
365                            << endl;
366
367         Menu file("file");
368         file
369                 .add(MenuItem(MenuItem::Command, _("New...|N"), "buffer-new"))
370                 .add(MenuItem(MenuItem::Command, _("Open...|O"), "buffer-open"))
371                 .add(MenuItem(MenuItem::Submenu, _("Import|I"), "import"))
372                 .add(MenuItem(MenuItem::Command, _("Quit|Q"), "lyx-quit"))
373                 .add(MenuItem(MenuItem::Separator))
374                 .add(MenuItem(MenuItem::Lastfiles));
375         add(file);
376
377         Menu import("import");
378         import
379                 .add(MenuItem(MenuItem::Command,
380                               _("LaTeX...|L"), "buffer-import latex"))
381                 .add(MenuItem(MenuItem::Command,
382                               _("LinuxDoc...|L"), "buffer-import linuxdoc"));
383         add(import);
384  
385         Menu edit("edit");
386         edit
387                 .add(MenuItem(MenuItem::Command, _("Cut"), "cut"))
388                 .add(MenuItem(MenuItem::Command, _("Copy"), "copy"))
389                 .add(MenuItem(MenuItem::Command, _("Paste"), "paste"))
390                 .add(MenuItem(MenuItem::Command, _("Emphasize"), "font-emph"));
391         add(edit);
392
393         Menu documents("documents");
394         documents.add(MenuItem(MenuItem::Documents));
395         add(documents);
396
397         Menu main("main", true);
398         main
399                 .add(MenuItem(MenuItem::Submenu, _("File|F"), "file"))
400                 .add(MenuItem(MenuItem::Submenu, _("Edit|E"), "edit"))
401                 .add(MenuItem(MenuItem::Submenu,
402                               _("Documents|D"), "documents"));
403         add(main);
404
405         Menu main_nobuffer("main_nobuffer", true);
406         main_nobuffer.add(MenuItem(MenuItem::Submenu, _("File|F"), "file"));
407         add(main_nobuffer);
408
409         if (lyxerr.debugging(Debug::GUI)) {
410                 for(const_iterator cit = begin();
411                     cit != end() ; ++cit)
412                         lyxerr << "Menu name: " << cit->name() 
413                                << ", Menubar: " << cit->menubar() 
414                                << endl;
415         }
416 }
417
418
419 void MenuBackend::add(Menu const & menu)
420 {
421         menulist_.push_back(menu);
422 }
423
424
425 bool MenuBackend::hasMenu(string const & name) const
426 {
427         return find_if(begin(), end(),
428                        compare_memfun(&Menu::name, name)) != end();
429 }
430
431
432 Menu const & MenuBackend::getMenu(string const & name) const
433 {
434         const_iterator cit = find_if(begin(), end(),
435                                      compare_memfun(&Menu::name, name));
436         Assert(cit != end());
437         return (*cit);
438 }
439
440
441 Menu & MenuBackend::getMenu(string const & name)
442 {
443         MenuList::iterator it = find_if(menulist_.begin(), menulist_.end(),
444                                         compare_memfun(&Menu::name, name));
445         Assert(it != menulist_.end());
446         return (*it);
447 }