]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiDocument.cpp
Add support for document-local layout information. GUI is to follow.
[lyx.git] / src / frontends / qt4 / GuiDocument.cpp
1 /**
2  * \file GuiDocument.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Edwin Leuven
7  * \author Richard Heck (modules)
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "GuiDocument.h"
15
16 #include "LayoutFile.h"
17 #include "BranchList.h"
18 #include "buffer_funcs.h"
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "BufferView.h"
22 #include "Color.h"
23 #include "Encoding.h"
24 #include "FloatPlacement.h"
25 #include "FuncRequest.h"
26 #include "support/gettext.h"
27 #include "GuiBranches.h"
28 #include "Language.h"
29 #include "LaTeXFeatures.h"
30 #include "LaTeXHighlighter.h"
31 #include "Layout.h"
32 #include "LengthCombo.h"
33 #include "LyXRC.h" // defaultUnit
34 #include "ModuleList.h"
35 #include "OutputParams.h"
36 #include "PanelStack.h"
37 #include "PDFOptions.h"
38 #include "qt_helpers.h"
39 #include "Spacing.h"
40 #include "Validator.h"
41
42 #include "insets/InsetListingsParams.h"
43
44 #include "support/debug.h"
45 #include "support/FileName.h"
46 #include "support/FileFilterList.h"
47 #include "support/filetools.h"
48 #include "support/lstrings.h"
49
50 #include "frontends/alert.h"
51
52 #include <QCloseEvent>
53 #include <QScrollBar>
54 #include <QTextCursor>
55
56 #include <sstream>
57
58 using namespace std;
59 using namespace lyx::support;
60
61
62 namespace {
63
64 char const * const tex_graphics[] =
65 {
66         "default", "dvips", "dvitops", "emtex",
67         "ln", "oztex", "textures", "none", ""
68 };
69
70
71 char const * const tex_graphics_gui[] =
72 {
73         N_("Default"), "Dvips", "DVItoPS", "EmTeX",
74         "LN", "OzTeX", "Textures", N_("None"), ""
75 };
76
77
78 char const * const tex_fonts_roman[] =
79 {
80         "default", "cmr", "lmodern", "ae", "times", "palatino",
81         "charter", "newcent", "bookman", "utopia", "beraserif",
82         "ccfonts", "chancery", ""
83 };
84
85
86 char const * tex_fonts_roman_gui[] =
87 {
88         N_("Default"), N_("Computer Modern Roman"), N_("Latin Modern Roman"),
89         N_("AE (Almost European)"), N_("Times Roman"), N_("Palatino"),
90         N_("Bitstream Charter"), N_("New Century Schoolbook"), N_("Bookman"),
91         N_("Utopia"),  N_("Bera Serif"), N_("Concrete Roman"), N_("Zapf Chancery"),
92         ""
93 };
94
95
96 char const * const tex_fonts_sans[] =
97 {
98         "default", "cmss", "lmss", "helvet", "avant", "berasans", "cmbr", ""
99 };
100
101
102 char const * tex_fonts_sans_gui[] =
103 {
104         N_("Default"), N_("Computer Modern Sans"), N_("Latin Modern Sans"),
105         N_("Helvetica"), N_("Avant Garde"), N_("Bera Sans"), N_("CM Bright"), ""
106 };
107
108
109 char const * const tex_fonts_monospaced[] =
110 {
111         "default", "cmtt", "lmtt", "courier", "beramono", "luximono", "cmtl", ""
112 };
113
114
115 char const * tex_fonts_monospaced_gui[] =
116 {
117         N_("Default"), N_("Computer Modern Typewriter"),
118         N_("Latin Modern Typewriter"), N_("Courier"), N_("Bera Mono"),
119         N_("LuxiMono"), N_("CM Typewriter Light"), ""
120 };
121
122
123 vector<pair<string, lyx::docstring> > pagestyles;
124
125
126 } // anonymous namespace
127
128 namespace lyx {
129
130 namespace {
131 // used when sorting the textclass list.
132 class less_textclass_avail_desc
133         : public binary_function<string, string, int>
134 {
135 public:
136         int operator()(string const & lhs, string const & rhs) const
137         {
138                 // Ordering criteria:
139                 //   1. Availability of text class
140                 //   2. Description (lexicographic)
141                 LayoutFile const & tc1 = LayoutFileList::get()[lhs];
142                 LayoutFile const & tc2 = LayoutFileList::get()[rhs];
143                 return (tc1.isTeXClassAvailable() && !tc2.isTeXClassAvailable()) ||
144                         (tc1.isTeXClassAvailable() == tc2.isTeXClassAvailable() &&
145                          _(tc1.description()) < _(tc2.description()));
146         }
147 };
148
149 }
150
151 namespace frontend {
152
153
154 /// 
155 QModelIndex getSelectedIndex(QListView * lv)
156 {
157         QModelIndex retval = QModelIndex();
158         QModelIndexList selIdx = 
159                         lv->selectionModel()->selectedIndexes();
160         if (!selIdx.empty())
161                 retval = selIdx.first();
162         return retval;
163 }
164
165
166 namespace {
167         vector<string> getRequiredList(string const & modName) 
168         {
169                 LyXModule const * const mod = moduleList[modName];
170                 if (!mod)
171                         return vector<string>(); //empty such thing
172                 return mod->getRequiredModules();
173         }
174
175
176         vector<string> getExcludedList(string const & modName)
177         {
178                 LyXModule const * const mod = moduleList[modName];
179                 if (!mod)
180                         return vector<string>(); //empty such thing
181                 return mod->getExcludedModules();
182         }
183
184
185         docstring getModuleDescription(string const & modName)
186         {
187                 LyXModule const * const mod = moduleList[modName];
188                 if (!mod)
189                         return _("Module not found!");
190                 return _(mod->getDescription());
191         }
192
193
194         vector<string> getPackageList(string const & modName)
195         {
196                 LyXModule const * const mod = moduleList[modName];
197                 if (!mod)
198                         return vector<string>(); //empty such thing
199                 return mod->getPackageList();
200         }
201
202
203         bool isModuleAvailable(string const & modName)
204         {
205                 LyXModule * mod = moduleList[modName];
206                 if (!mod)
207                         return false;
208                 return mod->isAvailable();
209         }
210 } //anonymous namespace
211
212
213 ModuleSelMan::ModuleSelMan(
214         QListView * availableLV, 
215         QListView * selectedLV,
216         QPushButton * addPB, 
217         QPushButton * delPB, 
218         QPushButton * upPB, 
219         QPushButton * downPB,
220         GuiIdListModel * availableModel,
221         GuiIdListModel * selectedModel) :
222 GuiSelectionManager(availableLV, selectedLV, addPB, delPB,
223                     upPB, downPB, availableModel, selectedModel) 
224 {}
225         
226
227 void ModuleSelMan::updateAddPB() 
228 {
229         int const arows = availableModel->rowCount();
230         QModelIndexList const availSels = 
231                         availableLV->selectionModel()->selectedIndexes();
232         if (arows == 0 || availSels.isEmpty()  || isSelected(availSels.first())) {
233                 addPB->setEnabled(false);
234                 return;
235         }
236         
237         QModelIndex const & idx = availableLV->selectionModel()->currentIndex();
238         string const modName = getAvailableModel()->getIDString(idx.row());
239         vector<string> reqs = getRequiredList(modName);
240         vector<string> excl = getExcludedList(modName);
241         
242         if (reqs.empty() && excl.empty()) {
243                 addPB->setEnabled(true);
244                 return;
245         }
246
247         int const srows = selectedModel->rowCount();
248         vector<string> selModList;
249         for (int i = 0; i < srows; ++i)
250                 selModList.push_back(getSelectedModel()->getIDString(i));
251
252         vector<string>::const_iterator selModStart = selModList.begin();
253         vector<string>::const_iterator selModEnd   = selModList.end();
254         
255         //Check whether some required module is available
256         if (!reqs.empty()) {
257                 bool foundOne = false;
258                 vector<string>::const_iterator it  = reqs.begin();
259                 vector<string>::const_iterator end = reqs.end();
260                 for (; it != end; ++it) {
261                         if (find(selModStart, selModEnd, *it) != selModEnd) {
262                                 foundOne = true;
263                                 break;
264                         }
265                 }
266                 if (!foundOne) {
267                         addPB->setEnabled(false);
268                         return;
269                 }
270         }
271         
272         //Check whether any excluded module is being used
273         if (!excl.empty()) {
274                 vector<string>::const_iterator it  = excl.begin();
275                 vector<string>::const_iterator end = excl.end();
276                 for (; it != end; ++it) {
277                         if (find(selModStart, selModEnd, *it) != selModEnd) {
278                                 addPB->setEnabled(false);
279                                 return;
280                         }
281                 }
282         }
283
284         addPB->setEnabled(true);
285 }
286
287
288 void ModuleSelMan::updateDownPB()
289 {
290         int const srows = selectedModel->rowCount();
291         if (srows == 0) {
292                 downPB->setEnabled(false);
293                 return;
294         }
295         QModelIndexList const selSels = 
296                         selectedLV->selectionModel()->selectedIndexes();
297         //disable if empty or last item is selected
298         if (selSels.empty() || selSels.first().row() == srows - 1) {
299                 downPB->setEnabled(false);
300                 return;
301         }
302         //determine whether immediately succeding element requires this one
303         QModelIndex const & curIdx = selectedLV->selectionModel()->currentIndex();
304         int curRow = curIdx.row();
305         if (curRow < 0 || curRow >= srows - 1) { //this shouldn't happen...
306                 downPB->setEnabled(false);
307                 return;
308         }
309         string const curModName = getSelectedModel()->getIDString(curRow);
310         string const nextModName = getSelectedModel()->getIDString(curRow + 1);
311
312         vector<string> reqs = getRequiredList(nextModName);
313
314         //if it doesn't require anything....
315         if (reqs.empty()) {
316                 downPB->setEnabled(true);
317                 return;
318         }
319
320         //FIXME This should perhaps be more flexible and check whether, even 
321         //if this one is required, there is also an earlier one that is required.
322         //enable it if this module isn't required
323         downPB->setEnabled(
324                         find(reqs.begin(), reqs.end(), curModName) == reqs.end());
325 }
326
327 void ModuleSelMan::updateUpPB() 
328 {
329         int const srows = selectedModel->rowCount();
330         if (srows == 0) {
331                 upPB->setEnabled(false);
332                 return;
333         }
334         QModelIndexList const selSels = 
335                         selectedLV->selectionModel()->selectedIndexes();
336         //disable if empty or first item is selected
337         if (selSels.empty() || selSels.first().row() == 0) {
338                 upPB->setEnabled(false);
339                 return;
340         }
341
342         //determine whether immediately preceding element is required by this one
343         QModelIndex const & curIdx = selectedLV->selectionModel()->currentIndex();
344         int curRow = curIdx.row();
345         if (curRow <= -1 || curRow > srows - 1) { //sanity check
346                 downPB->setEnabled(false);
347                 return;
348         }
349         string const curModName = getSelectedModel()->getIDString(curRow);
350         vector<string> reqs = getRequiredList(curModName);
351         
352         //if this one doesn't require anything....
353         if (reqs.empty()) {
354                 upPB->setEnabled(true);
355                 return;
356         }
357
358         string preModName = getSelectedModel()->getIDString(curRow - 1);
359
360         //NOTE This is less flexible than it might be. You could check whether, even 
361         //if this one is required, there is also an earlier one that is required.
362         //enable it if the preceding module isn't required
363         upPB->setEnabled(find(reqs.begin(), reqs.end(), preModName) == reqs.end());
364 }
365
366 void ModuleSelMan::updateDelPB() 
367 {
368         int const srows = selectedModel->rowCount();
369         if (srows == 0) {
370                 deletePB->setEnabled(false);
371                 return;
372         }
373         QModelIndexList const selSels = 
374                         selectedLV->selectionModel()->selectedIndexes();
375         if (selSels.empty() || selSels.first().row() < 0) {
376                 deletePB->setEnabled(false);
377                 return;
378         }
379         
380         //determine whether some LATER module requires this one
381         //NOTE Things are arranged so that this is the only way there
382         //can be a problem. At least, we hope so.
383         QModelIndex const & curIdx = 
384                 selectedLV->selectionModel()->currentIndex();
385         int const curRow = curIdx.row();
386         if (curRow < 0 || curRow >= srows) { //this shouldn't happen
387                 deletePB->setEnabled(false);
388                 return;
389         }
390                 
391         QString const curModName = curIdx.data().toString();
392         
393         //We're looking here for a reason NOT to enable the button. If we
394         //find one, we disable it and return. If we don't, we'll end up at
395         //the end of the function, and then we enable it.
396         for (int i = curRow + 1; i < srows; ++i) {
397                 string const thisMod = getSelectedModel()->getIDString(i);
398                 vector<string> reqs = getRequiredList(thisMod);
399                 //does this one require us?
400                 if (find(reqs.begin(), reqs.end(), fromqstr(curModName)) == reqs.end())
401                         //no...
402                         continue;
403
404                 //OK, so this module requires us
405                 //is there an EARLIER module that also satisfies the require?
406                 //NOTE We demand that it be earlier to keep the list of modules
407                 //consistent with the rule that a module must be proceeded by a
408                 //required module. There would be more flexible ways to proceed,
409                 //but that would be a lot more complicated, and the logic here is
410                 //already complicated. (That's why I've left the debugging code.)
411                 //lyxerr << "Testing " << thisMod << std::endl;
412                 bool foundOne = false;
413                 for (int j = 0; j < curRow; ++j) {
414                         string const mod = getSelectedModel()->getIDString(j);
415                         //lyxerr << "In loop: Testing " << mod << std::endl;
416                         //do we satisfy the require? 
417                         if (find(reqs.begin(), reqs.end(), mod) != reqs.end()) {
418                                 //lyxerr << mod << " does the trick." << std::endl;
419                                 foundOne = true;
420                                 break;
421                         }
422                 }
423                 //did we find a module to satisfy the require?
424                 if (!foundOne) {
425                         //lyxerr << "No matching module found." << std::endl;
426                         deletePB->setEnabled(false);
427                         return;
428                 }
429         }
430         //lyxerr << "All's well that ends well." << std::endl;  
431         deletePB->setEnabled(true);
432 }
433
434
435 /////////////////////////////////////////////////////////////////////
436 //
437 // PreambleModule
438 //
439 /////////////////////////////////////////////////////////////////////
440
441 PreambleModule::PreambleModule(): current_id_(0)
442 {
443         // This is not a memory leak. The object will be destroyed
444         // with this.
445         (void) new LaTeXHighlighter(preambleTE->document());
446         setFocusProxy(preambleTE);
447         connect(preambleTE, SIGNAL(textChanged()), this, SIGNAL(changed()));
448 }
449
450
451 void PreambleModule::update(BufferParams const & params, BufferId id)
452 {
453         QString preamble = toqstr(params.preamble);
454         // Nothing to do if the params and preamble are unchanged.
455         if (id == current_id_
456                 && preamble == preambleTE->document()->toPlainText())
457                 return;
458
459         QTextCursor cur = preambleTE->textCursor();
460         // Save the coords before switching to the new one.
461         preamble_coords_[current_id_] =
462                 make_pair(cur.position(), preambleTE->verticalScrollBar()->value());
463
464         // Save the params address for further use.
465         current_id_ = id;
466         preambleTE->document()->setPlainText(preamble);
467         Coords::const_iterator it = preamble_coords_.find(current_id_);
468         if (it == preamble_coords_.end())
469                 // First time we open this one.
470                 preamble_coords_[current_id_] = make_pair(0,0);
471         else {
472                 // Restore saved coords.
473                 QTextCursor cur = preambleTE->textCursor();
474                 cur.setPosition(it->second.first);
475                 preambleTE->setTextCursor(cur);
476                 preambleTE->verticalScrollBar()->setValue(it->second.second);
477         }
478 }
479
480
481 void PreambleModule::apply(BufferParams & params)
482 {
483         params.preamble = fromqstr(preambleTE->document()->toPlainText());
484 }
485
486
487 void PreambleModule::closeEvent(QCloseEvent * e)
488 {
489         // Save the coords before closing.
490         QTextCursor cur = preambleTE->textCursor();
491         preamble_coords_[current_id_] =
492                 make_pair(cur.position(), preambleTE->verticalScrollBar()->value());
493         e->accept();
494 }
495
496
497 /////////////////////////////////////////////////////////////////////
498 //
499 // DocumentDialog
500 //
501 /////////////////////////////////////////////////////////////////////
502
503
504 GuiDocument::GuiDocument(GuiView & lv)
505         : GuiDialog(lv, "document", qt_("Document Settings")), current_id_(0)
506 {
507         setupUi(this);
508
509         QList<LanguagePair> langs = languageData(false);        
510         for (int i = 0; i != langs.size(); ++i)
511                 lang_.append(langs[i].second);
512
513         connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
514         connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
515         connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
516         connect(restorePB, SIGNAL(clicked()), this, SLOT(slotRestore()));
517
518         connect(savePB, SIGNAL(clicked()), this, SLOT(saveDefaultClicked()));
519         connect(defaultPB, SIGNAL(clicked()), this, SLOT(useDefaultsClicked()));
520
521         // Manage the restore, ok, apply, restore and cancel/close buttons
522         bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
523         bc().setOK(okPB);
524         bc().setApply(applyPB);
525         bc().setCancel(closePB);
526         bc().setRestore(restorePB);
527
528         textLayoutModule = new UiWidget<Ui::TextLayoutUi>;
529         // text layout
530         connect(textLayoutModule->lspacingCO, SIGNAL(activated(int)),
531                 this, SLOT(change_adaptor()));
532         connect(textLayoutModule->lspacingCO, SIGNAL(activated(int)),
533                 this, SLOT(setLSpacing(int)));
534         connect(textLayoutModule->lspacingLE, SIGNAL(textChanged(const QString &)),
535                 this, SLOT(change_adaptor()));
536         connect(textLayoutModule->skipRB, SIGNAL(clicked()),
537                 this, SLOT(change_adaptor()));
538         connect(textLayoutModule->indentRB, SIGNAL(clicked()),
539                 this, SLOT(change_adaptor()));
540         connect(textLayoutModule->skipCO, SIGNAL(activated(int)),
541                 this, SLOT(change_adaptor()));
542         connect(textLayoutModule->skipLE, SIGNAL(textChanged(const QString &)),
543                 this, SLOT(change_adaptor()));
544         connect(textLayoutModule->skipLengthCO, SIGNAL(activated(int)),
545                 this, SLOT(change_adaptor()));
546         connect(textLayoutModule->skipCO, SIGNAL(activated(int)),
547                 this, SLOT(setSkip(int)));
548         connect(textLayoutModule->skipRB, SIGNAL(toggled(bool)),
549                 this, SLOT(enableSkip(bool)));
550         connect(textLayoutModule->twoColumnCB, SIGNAL(clicked()),
551                 this, SLOT(change_adaptor()));
552         connect(textLayoutModule->twoColumnCB, SIGNAL(clicked()),
553                 this, SLOT(setColSep()));
554         connect(textLayoutModule->listingsED, SIGNAL(textChanged()),
555                 this, SLOT(change_adaptor()));
556         connect(textLayoutModule->bypassCB, SIGNAL(clicked()), 
557                 this, SLOT(change_adaptor()));
558         connect(textLayoutModule->bypassCB, SIGNAL(clicked()), 
559                 this, SLOT(set_listings_msg()));
560         connect(textLayoutModule->listingsED, SIGNAL(textChanged()),
561                 this, SLOT(set_listings_msg()));
562         textLayoutModule->listingsTB->setPlainText(
563                 qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
564         textLayoutModule->lspacingLE->setValidator(new QDoubleValidator(
565                 textLayoutModule->lspacingLE));
566         textLayoutModule->skipLE->setValidator(unsignedLengthValidator(
567                 textLayoutModule->skipLE));
568
569         textLayoutModule->skipCO->addItem(qt_("SmallSkip"));
570         textLayoutModule->skipCO->addItem(qt_("MedSkip"));
571         textLayoutModule->skipCO->addItem(qt_("BigSkip"));
572         textLayoutModule->skipCO->addItem(qt_("Length"));
573         // remove the %-items from the unit choice
574         textLayoutModule->skipLengthCO->noPercents();
575         textLayoutModule->lspacingCO->insertItem(
576                 Spacing::Single, qt_("Single"));
577         textLayoutModule->lspacingCO->insertItem(
578                 Spacing::Onehalf, qt_("OneHalf"));
579         textLayoutModule->lspacingCO->insertItem(
580                 Spacing::Double, qt_("Double"));
581         textLayoutModule->lspacingCO->insertItem(
582                 Spacing::Other, qt_("Custom"));
583
584         // initialize the length validator
585         bc().addCheckedLineEdit(textLayoutModule->skipLE);
586
587         fontModule = new UiWidget<Ui::FontUi>;
588         // fonts
589         connect(fontModule->fontsRomanCO, SIGNAL(activated(int)),
590                 this, SLOT(change_adaptor()));
591         connect(fontModule->fontsRomanCO, SIGNAL(activated(int)),
592                 this, SLOT(romanChanged(int)));
593         connect(fontModule->fontsSansCO, SIGNAL(activated(int)),
594                 this, SLOT(change_adaptor()));
595         connect(fontModule->fontsSansCO, SIGNAL(activated(int)),
596                 this, SLOT(sansChanged(int)));
597         connect(fontModule->fontsTypewriterCO, SIGNAL(activated(int)),
598                 this, SLOT(change_adaptor()));
599         connect(fontModule->fontsTypewriterCO, SIGNAL(activated(int)),
600                 this, SLOT(ttChanged(int)));
601         connect(fontModule->fontsDefaultCO, SIGNAL(activated(int)),
602                 this, SLOT(change_adaptor()));
603         connect(fontModule->fontsizeCO, SIGNAL(activated(int)),
604                 this, SLOT(change_adaptor()));
605         connect(fontModule->scaleSansSB, SIGNAL(valueChanged(int)),
606                 this, SLOT(change_adaptor()));
607         connect(fontModule->scaleTypewriterSB, SIGNAL(valueChanged(int)),
608                 this, SLOT(change_adaptor()));
609         connect(fontModule->fontScCB, SIGNAL(clicked()),
610                 this, SLOT(change_adaptor()));
611         connect(fontModule->fontOsfCB, SIGNAL(clicked()),
612                 this, SLOT(change_adaptor()));
613
614         for (int n = 0; tex_fonts_roman[n][0]; ++n) {
615                 QString font = qt_(tex_fonts_roman_gui[n]);
616                 if (!isFontAvailable(tex_fonts_roman[n]))
617                         font += qt_(" (not installed)");
618                 fontModule->fontsRomanCO->addItem(font);
619         }
620         for (int n = 0; tex_fonts_sans[n][0]; ++n) {
621                 QString font = qt_(tex_fonts_sans_gui[n]);
622                 if (!isFontAvailable(tex_fonts_sans[n]))
623                         font += qt_(" (not installed)");
624                 fontModule->fontsSansCO->addItem(font);
625         }
626         for (int n = 0; tex_fonts_monospaced[n][0]; ++n) {
627                 QString font = qt_(tex_fonts_monospaced_gui[n]);
628                 if (!isFontAvailable(tex_fonts_monospaced[n]))
629                         font += qt_(" (not installed)");
630                 fontModule->fontsTypewriterCO->addItem(font);
631         }
632
633         fontModule->fontsizeCO->addItem(qt_("Default"));
634         fontModule->fontsizeCO->addItem(qt_("10"));
635         fontModule->fontsizeCO->addItem(qt_("11"));
636         fontModule->fontsizeCO->addItem(qt_("12"));
637
638         for (int n = 0; GuiDocument::fontfamilies_gui[n][0]; ++n)
639                 fontModule->fontsDefaultCO->addItem(
640                         qt_(GuiDocument::fontfamilies_gui[n]));
641
642
643         pageLayoutModule = new UiWidget<Ui::PageLayoutUi>;
644         // page layout
645         connect(pageLayoutModule->papersizeCO, SIGNAL(activated(int)),
646                 this, SLOT(setCustomPapersize(int)));
647         connect(pageLayoutModule->papersizeCO, SIGNAL(activated(int)),
648                 this, SLOT(setCustomPapersize(int)));
649         connect(pageLayoutModule->portraitRB, SIGNAL(clicked()),
650                 this, SLOT(portraitChanged()));
651         connect(pageLayoutModule->papersizeCO, SIGNAL(activated(int)),
652                 this, SLOT(change_adaptor()));
653         connect(pageLayoutModule->paperheightLE, SIGNAL(textChanged(const QString &)),
654                 this, SLOT(change_adaptor()));
655         connect(pageLayoutModule->paperwidthLE, SIGNAL(textChanged(const QString &)),
656                 this, SLOT(change_adaptor()));
657         connect(pageLayoutModule->paperwidthUnitCO, SIGNAL(activated(int)),
658                 this, SLOT(change_adaptor()));
659         connect(pageLayoutModule->paperheightUnitCO, SIGNAL(activated(int)),
660                 this, SLOT(change_adaptor()));
661         connect(pageLayoutModule->portraitRB, SIGNAL(clicked()),
662                 this, SLOT(change_adaptor()));
663         connect(pageLayoutModule->landscapeRB, SIGNAL(clicked()),
664                 this, SLOT(change_adaptor()));
665         connect(pageLayoutModule->facingPagesCB, SIGNAL(clicked()),
666                 this, SLOT(change_adaptor()));
667         connect(pageLayoutModule->pagestyleCO, SIGNAL(activated(int)),
668                 this, SLOT(change_adaptor()));
669
670         pageLayoutModule->pagestyleCO->addItem(qt_("Default"));
671         pageLayoutModule->pagestyleCO->addItem(qt_("empty"));
672         pageLayoutModule->pagestyleCO->addItem(qt_("plain"));
673         pageLayoutModule->pagestyleCO->addItem(qt_("headings"));
674         pageLayoutModule->pagestyleCO->addItem(qt_("fancy"));
675         bc().addCheckedLineEdit(pageLayoutModule->paperheightLE,
676                 pageLayoutModule->paperheightL);
677         bc().addCheckedLineEdit(pageLayoutModule->paperwidthLE,
678                 pageLayoutModule->paperwidthL);
679
680         // paper
681         QComboBox * cb = pageLayoutModule->papersizeCO;
682         cb->addItem(qt_("Default"));
683         cb->addItem(qt_("Custom"));
684         cb->addItem(qt_("US letter"));
685         cb->addItem(qt_("US legal"));
686         cb->addItem(qt_("US executive"));
687         cb->addItem(qt_("A3"));
688         cb->addItem(qt_("A4"));
689         cb->addItem(qt_("A5"));
690         cb->addItem(qt_("B3"));
691         cb->addItem(qt_("B4"));
692         cb->addItem(qt_("B5"));
693         // remove the %-items from the unit choice
694         pageLayoutModule->paperwidthUnitCO->noPercents();
695         pageLayoutModule->paperheightUnitCO->noPercents();
696         pageLayoutModule->paperheightLE->setValidator(unsignedLengthValidator(
697                 pageLayoutModule->paperheightLE));
698         pageLayoutModule->paperwidthLE->setValidator(unsignedLengthValidator(
699                 pageLayoutModule->paperwidthLE));
700
701
702         marginsModule = new UiWidget<Ui::MarginsUi>;
703         // margins
704         connect(marginsModule->marginCB, SIGNAL(toggled(bool)),
705                 this, SLOT(setCustomMargins(bool)));
706         connect(marginsModule->marginCB, SIGNAL(clicked()),
707                 this, SLOT(change_adaptor()));
708         connect(marginsModule->topLE, SIGNAL(textChanged(const QString &)),
709                 this, SLOT(change_adaptor()));
710         connect(marginsModule->topUnit, SIGNAL(activated(int)),
711                 this, SLOT(change_adaptor()));
712         connect(marginsModule->bottomLE, SIGNAL(textChanged(const QString &)),
713                 this, SLOT(change_adaptor()));
714         connect(marginsModule->bottomUnit, SIGNAL(activated(int)),
715                 this, SLOT(change_adaptor()));
716         connect(marginsModule->innerLE, SIGNAL(textChanged(const QString &)),
717                 this, SLOT(change_adaptor()));
718         connect(marginsModule->innerUnit, SIGNAL(activated(int)),
719                 this, SLOT(change_adaptor()));
720         connect(marginsModule->outerLE, SIGNAL(textChanged(const QString &)),
721                 this, SLOT(change_adaptor()));
722         connect(marginsModule->outerUnit, SIGNAL(activated(int)),
723                 this, SLOT(change_adaptor()));
724         connect(marginsModule->headheightLE, SIGNAL(textChanged(const QString &)),
725                 this, SLOT(change_adaptor()));
726         connect(marginsModule->headheightUnit, SIGNAL(activated(int)),
727                 this, SLOT(change_adaptor()));
728         connect(marginsModule->headsepLE, SIGNAL(textChanged(const QString &)),
729                 this, SLOT(change_adaptor()));
730         connect(marginsModule->headsepUnit, SIGNAL(activated(int)),
731                 this, SLOT(change_adaptor()));
732         connect(marginsModule->footskipLE, SIGNAL(textChanged(const QString&)),
733                 this, SLOT(change_adaptor()));
734         connect(marginsModule->footskipUnit, SIGNAL(activated(int)),
735                 this, SLOT(change_adaptor()));
736         connect(marginsModule->columnsepLE, SIGNAL(textChanged(const QString&)),
737                 this, SLOT(change_adaptor()));
738         connect(marginsModule->columnsepUnit, SIGNAL(activated(int)),
739                 this, SLOT(change_adaptor()));
740         marginsModule->topLE->setValidator(unsignedLengthValidator(
741                 marginsModule->topLE));
742         marginsModule->bottomLE->setValidator(unsignedLengthValidator(
743                 marginsModule->bottomLE));
744         marginsModule->innerLE->setValidator(unsignedLengthValidator(
745                 marginsModule->innerLE));
746         marginsModule->outerLE->setValidator(unsignedLengthValidator(
747                 marginsModule->outerLE));
748         marginsModule->headsepLE->setValidator(unsignedLengthValidator(
749                 marginsModule->headsepLE));
750         marginsModule->headheightLE->setValidator(unsignedLengthValidator(
751                 marginsModule->headheightLE));
752         marginsModule->footskipLE->setValidator(unsignedLengthValidator(
753                 marginsModule->footskipLE));
754         marginsModule->columnsepLE->setValidator(unsignedLengthValidator(
755                 marginsModule->columnsepLE));
756
757         bc().addCheckedLineEdit(marginsModule->topLE,
758                 marginsModule->topL);
759         bc().addCheckedLineEdit(marginsModule->bottomLE,
760                 marginsModule->bottomL);
761         bc().addCheckedLineEdit(marginsModule->innerLE,
762                 marginsModule->innerL);
763         bc().addCheckedLineEdit(marginsModule->outerLE,
764                 marginsModule->outerL);
765         bc().addCheckedLineEdit(marginsModule->headsepLE,
766                 marginsModule->headsepL);
767         bc().addCheckedLineEdit(marginsModule->headheightLE,
768                 marginsModule->headheightL);
769         bc().addCheckedLineEdit(marginsModule->footskipLE,
770                 marginsModule->footskipL);
771         bc().addCheckedLineEdit(marginsModule->columnsepLE,
772                 marginsModule->columnsepL);
773
774
775         langModule = new UiWidget<Ui::LanguageUi>;
776         // language & quote
777         connect(langModule->languageCO, SIGNAL(activated(int)),
778                 this, SLOT(change_adaptor()));
779         connect(langModule->defaultencodingRB, SIGNAL(clicked()),
780                 this, SLOT(change_adaptor()));
781         connect(langModule->otherencodingRB, SIGNAL(clicked()),
782                 this, SLOT(change_adaptor()));
783         connect(langModule->encodingCO, SIGNAL(activated(int)),
784                 this, SLOT(change_adaptor()));
785         connect(langModule->quoteStyleCO, SIGNAL(activated(int)),
786                 this, SLOT(change_adaptor()));
787         // language & quotes
788
789         QList<LanguagePair>::const_iterator lit  = langs.begin();
790         QList<LanguagePair>::const_iterator lend = langs.end();
791         for (; lit != lend; ++lit)
792                 langModule->languageCO->addItem(lit->first);
793
794         // Always put the default encoding in the first position.
795         // It is special because the displayed text is translated.
796         langModule->encodingCO->addItem(qt_("LaTeX default"));
797         Encodings::const_iterator it = encodings.begin();
798         Encodings::const_iterator const end = encodings.end();
799         for (; it != end; ++it)
800                 langModule->encodingCO->addItem(toqstr(it->latexName()));
801
802         langModule->quoteStyleCO->addItem(qt_("``text''"));
803         langModule->quoteStyleCO->addItem(qt_("''text''"));
804         langModule->quoteStyleCO->addItem(qt_(",,text``"));
805         langModule->quoteStyleCO->addItem(qt_(",,text''"));
806         langModule->quoteStyleCO->addItem(qt_("<<text>>"));
807         langModule->quoteStyleCO->addItem(qt_(">>text<<"));
808
809
810         numberingModule = new UiWidget<Ui::NumberingUi>;
811         // numbering
812         connect(numberingModule->depthSL, SIGNAL(valueChanged(int)),
813                 this, SLOT(change_adaptor()));
814         connect(numberingModule->tocSL, SIGNAL(valueChanged(int)),
815                 this, SLOT(change_adaptor()));
816         connect(numberingModule->depthSL, SIGNAL(valueChanged(int)),
817                 this, SLOT(updateNumbering()));
818         connect(numberingModule->tocSL, SIGNAL(valueChanged(int)),
819                 this, SLOT(updateNumbering()));
820         numberingModule->tocTW->setColumnCount(3);
821         numberingModule->tocTW->headerItem()->setText(0, qt_("Example"));
822         numberingModule->tocTW->headerItem()->setText(1, qt_("Numbered"));
823         numberingModule->tocTW->headerItem()->setText(2, qt_("Appears in TOC"));
824
825
826         biblioModule = new UiWidget<Ui::BiblioUi>;
827         connect(biblioModule->citeNatbibRB, SIGNAL(toggled(bool)),
828                 biblioModule->citationStyleL, SLOT(setEnabled(bool)));
829         connect(biblioModule->citeNatbibRB, SIGNAL(toggled(bool)),
830                 biblioModule->citeStyleCO, SLOT(setEnabled(bool)));
831         // biblio
832         connect(biblioModule->citeDefaultRB, SIGNAL(clicked()),
833                 this, SLOT(change_adaptor()));
834         connect(biblioModule->citeNatbibRB, SIGNAL(clicked()),
835                 this, SLOT(change_adaptor()));
836         connect(biblioModule->citeStyleCO, SIGNAL(activated(int)),
837                 this, SLOT(change_adaptor()));
838         connect(biblioModule->citeJurabibRB, SIGNAL(clicked()),
839                 this, SLOT(change_adaptor()));
840         connect(biblioModule->bibtopicCB, SIGNAL(clicked()),
841                 this, SLOT(change_adaptor()));
842         // biblio
843         biblioModule->citeStyleCO->addItem(qt_("Author-year"));
844         biblioModule->citeStyleCO->addItem(qt_("Numerical"));
845         biblioModule->citeStyleCO->setCurrentIndex(0);
846
847
848         mathsModule = new UiWidget<Ui::MathsUi>;
849         connect(mathsModule->amsautoCB, SIGNAL(toggled(bool)),
850                 mathsModule->amsCB, SLOT(setDisabled(bool)));
851         connect(mathsModule->esintautoCB, SIGNAL(toggled(bool)),
852                 mathsModule->esintCB, SLOT(setDisabled(bool)));
853         // maths
854         connect(mathsModule->amsCB, SIGNAL(clicked()),
855                 this, SLOT(change_adaptor()));
856         connect(mathsModule->amsautoCB, SIGNAL(clicked()),
857                 this, SLOT(change_adaptor()));
858         connect(mathsModule->esintCB, SIGNAL(clicked()),
859                 this, SLOT(change_adaptor()));
860         connect(mathsModule->esintautoCB, SIGNAL(clicked()),
861                 this, SLOT(change_adaptor()));
862
863         latexModule = new UiWidget<Ui::LaTeXUi>;
864         // latex class
865         connect(latexModule->optionsLE, SIGNAL(textChanged(const QString &)),
866                 this, SLOT(change_adaptor()));
867         connect(latexModule->psdriverCO, SIGNAL(activated(int)),
868                 this, SLOT(change_adaptor()));
869         connect(latexModule->classCO, SIGNAL(activated(int)),
870                 this, SLOT(classChanged()));
871         connect(latexModule->classCO, SIGNAL(activated(int)),
872                 this, SLOT(change_adaptor()));
873         connect(latexModule->layoutPB, SIGNAL(clicked()),
874                 this, SLOT(browseLayout()));
875         
876         selectionManager = 
877                 new ModuleSelMan(latexModule->availableLV, latexModule->selectedLV, 
878                         latexModule->addPB, latexModule->deletePB, 
879                         latexModule->upPB, latexModule->downPB, 
880                         availableModel(), selectedModel());
881         connect(selectionManager, SIGNAL(updateHook()),
882                 this, SLOT(updateModuleInfo()));
883         connect(selectionManager, SIGNAL(updateHook()),
884                 this, SLOT(change_adaptor()));
885         
886         // postscript drivers
887         for (int n = 0; tex_graphics[n][0]; ++n) {
888                 QString enc = qt_(tex_graphics_gui[n]);
889                 latexModule->psdriverCO->addItem(enc);
890         }
891         // latex classes
892         latexModule->classCO->setModel(&classes_model_);
893         LayoutFileList const & bcl = LayoutFileList::get();
894         vector<LayoutFileIndex> classList = bcl.classList();
895         sort(classList.begin(), classList.end(), less_textclass_avail_desc());
896
897         vector<LayoutFileIndex>::const_iterator cit  = classList.begin();
898         vector<LayoutFileIndex>::const_iterator cen = classList.end();
899         for (int i = 0; cit != cen; ++cit, ++i) {
900                 LayoutFile const & tc = bcl[*cit];
901                 docstring item = (tc.isTeXClassAvailable()) ?
902                         from_utf8(tc.description()) :
903                         bformat(_("Unavailable: %1$s"), from_utf8(tc.description()));
904                 classes_model_.insertRow(i, toqstr(item), *cit);
905         }
906
907         // branches
908         branchesModule = new GuiBranches;
909         connect(branchesModule, SIGNAL(changed()),
910                 this, SLOT(change_adaptor()));
911
912         // preamble
913         preambleModule = new PreambleModule;
914         connect(preambleModule, SIGNAL(changed()),
915                 this, SLOT(change_adaptor()));
916
917         // bullets
918         bulletsModule = new BulletsModule;
919         connect(bulletsModule, SIGNAL(changed()),
920                 this, SLOT(change_adaptor()));
921
922         // embedded files
923         embeddedFilesModule = new UiWidget<Ui::EmbeddedFilesUi>;
924         connect(embeddedFilesModule->addPB, SIGNAL(clicked()),
925                 this, SLOT(addExtraEmbeddedFile()));
926         connect(embeddedFilesModule->removePB, SIGNAL(clicked()),
927                 this, SLOT(removeExtraEmbeddedFile()));
928
929         // PDF support
930         pdfSupportModule = new UiWidget<Ui::PDFSupportUi>;
931
932         connect(pdfSupportModule->use_hyperrefGB, SIGNAL(toggled(bool)),
933                 this, SLOT(change_adaptor()));
934         connect(pdfSupportModule->titleLE, SIGNAL(textChanged(const QString &)),
935                 this, SLOT(change_adaptor()));
936         connect(pdfSupportModule->authorLE, SIGNAL(textChanged(const QString &)),
937                 this, SLOT(change_adaptor()));
938         connect(pdfSupportModule->subjectLE, SIGNAL(textChanged(const QString &)),
939                 this, SLOT(change_adaptor()));
940         connect(pdfSupportModule->keywordsLE, SIGNAL(textChanged(const QString &)),
941                 this, SLOT(change_adaptor()));
942         connect(pdfSupportModule->bookmarksGB, SIGNAL(toggled(bool)),
943                 this, SLOT(change_adaptor()));
944         connect(pdfSupportModule->bookmarksnumberedCB, SIGNAL(toggled(bool)),
945                 this, SLOT(change_adaptor()));
946         connect(pdfSupportModule->bookmarksopenGB, SIGNAL(toggled(bool)),
947                 this, SLOT(change_adaptor()));
948         connect(pdfSupportModule->bookmarksopenlevelSB, SIGNAL(valueChanged(int)),
949                 this, SLOT(change_adaptor()));
950         connect(pdfSupportModule->breaklinksCB, SIGNAL(toggled(bool)),
951                 this, SLOT(change_adaptor()));
952         connect(pdfSupportModule->pdfborderCB, SIGNAL(toggled(bool)),
953                 this, SLOT(change_adaptor()));
954         connect(pdfSupportModule->colorlinksCB, SIGNAL(toggled(bool)),
955                 this, SLOT(change_adaptor()));
956         connect(pdfSupportModule->backrefCB, SIGNAL(toggled(bool)),
957                 this, SLOT(change_adaptor()));
958         connect(pdfSupportModule->pdfusetitleCB, SIGNAL(toggled(bool)),
959                 this, SLOT(change_adaptor()));
960         connect(pdfSupportModule->pagebackrefCB, SIGNAL(toggled(bool)),
961                 this, SLOT(change_adaptor()));
962         connect(pdfSupportModule->fullscreenCB, SIGNAL(toggled(bool)),
963                 this, SLOT(change_adaptor()));
964         connect(pdfSupportModule->optionsLE, SIGNAL(textChanged(const QString &)),
965                 this, SLOT(change_adaptor()));
966
967         // float
968         floatModule = new FloatPlacement;
969         connect(floatModule, SIGNAL(changed()),
970                 this, SLOT(change_adaptor()));
971
972         docPS->addPanel(latexModule, qt_("Document Class"));
973         docPS->addPanel(fontModule, qt_("Fonts"));
974         docPS->addPanel(textLayoutModule, qt_("Text Layout"));
975         docPS->addPanel(pageLayoutModule, qt_("Page Layout"));
976         docPS->addPanel(marginsModule, qt_("Page Margins"));
977         docPS->addPanel(langModule, qt_("Language"));
978         docPS->addPanel(numberingModule, qt_("Numbering & TOC"));
979         docPS->addPanel(biblioModule, qt_("Bibliography"));
980         docPS->addPanel(pdfSupportModule, qt_("PDF Properties"));
981         docPS->addPanel(mathsModule, qt_("Math Options"));
982         docPS->addPanel(floatModule, qt_("Float Placement"));
983         docPS->addPanel(bulletsModule, qt_("Bullets"));
984         docPS->addPanel(branchesModule, qt_("Branches"));
985         docPS->addPanel(embeddedFilesModule, qt_("Embedded Files"));
986         docPS->addPanel(preambleModule, qt_("LaTeX Preamble"));
987         docPS->setCurrentPanel(qt_("Document Class"));
988 // FIXME: hack to work around resizing bug in Qt >= 4.2
989 // bug verified with Qt 4.2.{0-3} (JSpitzm)
990 #if QT_VERSION >= 0x040200
991         docPS->updateGeometry();
992 #endif
993 }
994
995
996 void GuiDocument::showPreamble()
997 {
998         docPS->setCurrentPanel(qt_("LaTeX Preamble"));
999 }
1000
1001
1002 void GuiDocument::saveDefaultClicked()
1003 {
1004         saveDocDefault();
1005 }
1006
1007
1008 void GuiDocument::useDefaultsClicked()
1009 {
1010         useClassDefaults();
1011 }
1012
1013
1014 void GuiDocument::change_adaptor()
1015 {
1016         changed();
1017 }
1018
1019
1020 docstring GuiDocument::validate_listings_params()
1021 {
1022         // use a cache here to avoid repeated validation
1023         // of the same parameters
1024         static string param_cache = string();
1025         static docstring msg_cache = docstring();
1026         
1027         if (textLayoutModule->bypassCB->isChecked())
1028                 return docstring();
1029
1030         string params = fromqstr(textLayoutModule->listingsED->toPlainText());
1031         if (params != param_cache) {
1032                 param_cache = params;
1033                 msg_cache = InsetListingsParams(params).validate();
1034         }
1035         return msg_cache;
1036 }
1037
1038
1039 void GuiDocument::set_listings_msg()
1040 {
1041         static bool isOK = true;
1042         docstring msg = validate_listings_params();
1043         if (msg.empty()) {
1044                 if (isOK)
1045                         return;
1046                 isOK = true;
1047                 // listingsTB->setTextColor("black");
1048                 textLayoutModule->listingsTB->setPlainText(
1049                         qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
1050         } else {
1051                 isOK = false;
1052                 // listingsTB->setTextColor("red");
1053                 textLayoutModule->listingsTB->setPlainText(toqstr(msg));
1054         }
1055 }
1056
1057
1058 void GuiDocument::setLSpacing(int item)
1059 {
1060         textLayoutModule->lspacingLE->setEnabled(item == 3);
1061 }
1062
1063
1064 void GuiDocument::setSkip(int item)
1065 {
1066         bool const enable = (item == 3);
1067         textLayoutModule->skipLE->setEnabled(enable);
1068         textLayoutModule->skipLengthCO->setEnabled(enable);
1069 }
1070
1071
1072 void GuiDocument::enableSkip(bool skip)
1073 {
1074         textLayoutModule->skipCO->setEnabled(skip);
1075         textLayoutModule->skipLE->setEnabled(skip);
1076         textLayoutModule->skipLengthCO->setEnabled(skip);
1077         if (skip)
1078                 setSkip(textLayoutModule->skipCO->currentIndex());
1079 }
1080
1081 void GuiDocument::portraitChanged()
1082 {
1083         setMargins(pageLayoutModule->papersizeCO->currentIndex());
1084 }
1085
1086 void GuiDocument::setMargins(bool custom)
1087 {
1088         marginsModule->marginCB->setChecked(custom);
1089         setCustomMargins(custom);
1090 }
1091
1092
1093 void GuiDocument::setCustomPapersize(int papersize)
1094 {
1095         bool const custom = (papersize == 1);
1096
1097         pageLayoutModule->paperwidthL->setEnabled(custom);
1098         pageLayoutModule->paperwidthLE->setEnabled(custom);
1099         pageLayoutModule->paperwidthUnitCO->setEnabled(custom);
1100         pageLayoutModule->paperheightL->setEnabled(custom);
1101         pageLayoutModule->paperheightLE->setEnabled(custom);
1102         pageLayoutModule->paperheightLE->setFocus();
1103         pageLayoutModule->paperheightUnitCO->setEnabled(custom);
1104 }
1105
1106
1107 void GuiDocument::setColSep()
1108 {
1109         setCustomMargins(marginsModule->marginCB->checkState() == Qt::Checked);
1110 }
1111
1112
1113 void GuiDocument::setCustomMargins(bool custom)
1114 {
1115         marginsModule->topL->setEnabled(!custom);
1116         marginsModule->topLE->setEnabled(!custom);
1117         marginsModule->topUnit->setEnabled(!custom);
1118
1119         marginsModule->bottomL->setEnabled(!custom);
1120         marginsModule->bottomLE->setEnabled(!custom);
1121         marginsModule->bottomUnit->setEnabled(!custom);
1122
1123         marginsModule->innerL->setEnabled(!custom);
1124         marginsModule->innerLE->setEnabled(!custom);
1125         marginsModule->innerUnit->setEnabled(!custom);
1126
1127         marginsModule->outerL->setEnabled(!custom);
1128         marginsModule->outerLE->setEnabled(!custom);
1129         marginsModule->outerUnit->setEnabled(!custom);
1130
1131         marginsModule->headheightL->setEnabled(!custom);
1132         marginsModule->headheightLE->setEnabled(!custom);
1133         marginsModule->headheightUnit->setEnabled(!custom);
1134
1135         marginsModule->headsepL->setEnabled(!custom);
1136         marginsModule->headsepLE->setEnabled(!custom);
1137         marginsModule->headsepUnit->setEnabled(!custom);
1138
1139         marginsModule->footskipL->setEnabled(!custom);
1140         marginsModule->footskipLE->setEnabled(!custom);
1141         marginsModule->footskipUnit->setEnabled(!custom);
1142
1143         bool const enableColSep = !custom && 
1144                         textLayoutModule->twoColumnCB->checkState() == Qt::Checked;
1145         marginsModule->columnsepL->setEnabled(enableColSep);
1146         marginsModule->columnsepLE->setEnabled(enableColSep);
1147         marginsModule->columnsepUnit->setEnabled(enableColSep);
1148 }
1149
1150
1151 void GuiDocument::updateFontsize(string const & items, string const & sel)
1152 {
1153         fontModule->fontsizeCO->clear();
1154         fontModule->fontsizeCO->addItem(qt_("Default"));
1155
1156         for (int n = 0; !token(items,'|',n).empty(); ++n)
1157                 fontModule->fontsizeCO->
1158                         addItem(toqstr(token(items,'|',n)));
1159
1160         for (int n = 0; n < fontModule->fontsizeCO->count(); ++n) {
1161                 if (fromqstr(fontModule->fontsizeCO->itemText(n)) == sel) {
1162                         fontModule->fontsizeCO->setCurrentIndex(n);
1163                         break;
1164                 }
1165         }
1166 }
1167
1168
1169 void GuiDocument::romanChanged(int item)
1170 {
1171         string const font = tex_fonts_roman[item];
1172         fontModule->fontScCB->setEnabled(providesSC(font));
1173         fontModule->fontOsfCB->setEnabled(providesOSF(font));
1174 }
1175
1176
1177 void GuiDocument::sansChanged(int item)
1178 {
1179         string const font = tex_fonts_sans[item];
1180         bool scaleable = providesScale(font);
1181         fontModule->scaleSansSB->setEnabled(scaleable);
1182         fontModule->scaleSansLA->setEnabled(scaleable);
1183 }
1184
1185
1186 void GuiDocument::ttChanged(int item)
1187 {
1188         string const font = tex_fonts_monospaced[item];
1189         bool scaleable = providesScale(font);
1190         fontModule->scaleTypewriterSB->setEnabled(scaleable);
1191         fontModule->scaleTypewriterLA->setEnabled(scaleable);
1192 }
1193
1194
1195 void GuiDocument::updatePagestyle(string const & items, string const & sel)
1196 {
1197         pagestyles.clear();
1198         pageLayoutModule->pagestyleCO->clear();
1199         pageLayoutModule->pagestyleCO->addItem(qt_("Default"));
1200
1201         for (int n = 0; !token(items,'|',n).empty(); ++n) {
1202                 string style = token(items, '|', n);
1203                 docstring style_gui = _(style);
1204                 pagestyles.push_back(pair<string, docstring>(style, style_gui));
1205                 pageLayoutModule->pagestyleCO->addItem(toqstr(style_gui));
1206         }
1207
1208         if (sel == "default") {
1209                 pageLayoutModule->pagestyleCO->setCurrentIndex(0);
1210                 return;
1211         }
1212
1213         int nn = 0;
1214
1215         for (size_t i = 0; i < pagestyles.size(); ++i)
1216                 if (pagestyles[i].first == sel)
1217                         nn = pageLayoutModule->pagestyleCO->findText(
1218                                         toqstr(pagestyles[i].second));
1219
1220         if (nn > 0)
1221                 pageLayoutModule->pagestyleCO->setCurrentIndex(nn);
1222 }
1223
1224
1225 void GuiDocument::browseLayout()
1226 {
1227         QString const label1 = qt_("Layouts|#o#O");
1228         QString const dir1 = toqstr(lyxrc.document_path);
1229         FileFilterList const filter(_("LyX Layout (*.layout)"));
1230         QString file = browseRelFile(QString(), bufferFilepath(),
1231                 qt_("Local layout file"), filter, false,
1232                 label1, dir1);
1233
1234         if (!suffixIs(fromqstr(file), ".layout"))
1235                 return;
1236
1237         FileName layoutFile = makeAbsPath(fromqstr(file),
1238                 fromqstr(bufferFilepath()));
1239         
1240         // load the layout file
1241         LayoutFileList & bcl = LayoutFileList::get();
1242         string classname = layoutFile.onlyFileName();
1243         LayoutFileIndex name = bcl.addLayoutFile(
1244                 classname.substr(0, classname.size() - 7),
1245                 layoutFile.onlyPath().absFilename(),
1246                 LayoutFileList::Local);
1247
1248         if (name.empty()) {
1249                 Alert::error(_("Error"),
1250                         _("Unable to read local layout file."));                
1251                 return;
1252         }
1253
1254         // do not trigger classChanged if there is no change.
1255         if (latexModule->classCO->currentText() == toqstr(name))
1256                 return;
1257                 
1258         // add to combo box
1259         int idx = latexModule->classCO->findText(toqstr(name));
1260         if (idx == -1) {
1261                 classes_model_.insertRow(0, toqstr(name), name);
1262                 latexModule->classCO->setCurrentIndex(0);
1263         } else
1264                 latexModule->classCO->setCurrentIndex(idx);
1265         classChanged();
1266 }
1267
1268
1269 void GuiDocument::classChanged()
1270 {
1271         int idx = latexModule->classCO->currentIndex();
1272         if (idx < 0) 
1273                 return;
1274         string const classname = classes_model_.getIDString(idx);
1275         // check if this is a local layout file
1276         if (prefixIs(classname, LayoutFileList::localPrefix)) {
1277                 int const ret = Alert::prompt(_("Local layout file"),
1278                                 _("The layout file you have selected is a local layout\n"
1279                                   "file, not one in the system or user directory. Your\n"
1280                                   "document may not work with this layout if you do not\n"
1281                                   "keep the layout file in the same directory."),
1282                                   1, 1, _("&Set Layout"), _("&Cancel"));
1283                 if (ret == 1) {
1284                         // try to reset the layout combo
1285                         setLayoutComboByIDString(bp_.baseClassID());
1286                         return;
1287                 }
1288         } else if (prefixIs(classname, LayoutFileList::embeddedPrefix)) {
1289                 int const ret = Alert::prompt(_("Embedded layout"),
1290                                 _("The layout file you have selected is an embedded layout that\n"
1291                                   "is embedded to a buffer. You cannot make use of it unless\n"
1292                                   "it is already embedded to this buffer.\n"),
1293                                   1, 1, _("&Set Layout"), _("&Cancel"));
1294                 if (ret == 1) {
1295                         setLayoutComboByIDString(bp_.baseClassID());
1296                         return;
1297                 }
1298         }
1299         // FIXME Note that by doing things this way, we load the TextClass
1300         // as soon as it is selected. So, if you use the scroll wheel when
1301         // sitting on the combo box, we'll load a lot of TextClass objects
1302         // very quickly. This could be changed.
1303         if (!bp_.setBaseClass(classname)) {
1304                 Alert::error(_("Error"), _("Unable to set document class."));
1305                 return;
1306         }
1307         if (lyxrc.auto_reset_options) {
1308                 if (applyPB->isEnabled()) {
1309                         int const ret = Alert::prompt(_("Unapplied changes"),
1310                                         _("Some changes in the dialog were not yet applied.\n"
1311                                         "If you do not apply now, they will be lost after this action."),
1312                                         1, 1, _("&Apply"), _("&Dismiss"));
1313                         if (ret == 0)
1314                                 applyView();
1315                 }
1316                 bp_.useClassDefaults();
1317                 forceUpdate();
1318         }
1319 }
1320
1321
1322 namespace {
1323         // This is an insanely complicated attempt to make this sort of thing
1324         // work with RTL languages.
1325         docstring formatStrVec(vector<string> const & v, docstring const & s) 
1326         {
1327                 //this mess formats the list as "v[0], v[1], ..., [s] v[n]"
1328                 int const vSize = v.size();
1329                 if (v.size() == 0)
1330                         return docstring();
1331                 else if (v.size() == 1) 
1332                         return from_ascii(v[0]);
1333                 else if (v.size() == 2) {
1334                         docstring retval = _("%1$s and %2$s");
1335                         retval = subst(retval, _("and"), s);
1336                         return bformat(retval, from_ascii(v[0]), from_ascii(v[1]));
1337                 }
1338                 //The idea here is to format all but the last two items...
1339                 docstring t2 = _("%1$s, %2$s");
1340                 docstring retval = from_ascii(v[0]);
1341                 for (int i = 1; i < vSize - 2; ++i)
1342                         retval = bformat(t2, retval, from_ascii(v[i])); 
1343                 //...and then to  plug them, and the last two, into this schema
1344                 docstring t = _("%1$s, %2$s, and %3$s");
1345                 t = subst(t, _("and"), s);
1346                 return bformat(t, retval, from_ascii(v[vSize - 2]), from_ascii(v[vSize - 1]));
1347         }
1348         
1349         vector<string> idsToNames(vector<string> const & idList)
1350         {
1351                 vector<string> retval;
1352                 vector<string>::const_iterator it  = idList.begin();
1353                 vector<string>::const_iterator end = idList.end();
1354                 for (; it != end; ++it) {
1355                         LyXModule const * const mod = moduleList[*it];
1356                         if (!mod)
1357                                 retval.push_back(*it + " (Unavailable)");
1358                         else
1359                                 retval.push_back(mod->getName());
1360                 }
1361                 return retval;
1362         }
1363 }
1364
1365
1366 void GuiDocument::updateModuleInfo()
1367 {
1368         selectionManager->update();
1369         
1370         //Module description
1371         bool const focusOnSelected = selectionManager->selectedFocused();
1372         QListView const * const lv = 
1373                         focusOnSelected ? latexModule->selectedLV : latexModule->availableLV;
1374         if (lv->selectionModel()->selectedIndexes().isEmpty()) {
1375                 latexModule->infoML->document()->clear();
1376                 return;
1377         }
1378         QModelIndex const & idx = lv->selectionModel()->currentIndex();
1379         GuiIdListModel const & idModel = 
1380                         focusOnSelected  ? modules_sel_model_ : modules_av_model_;
1381         string const modName = idModel.getIDString(idx.row());
1382         docstring desc = getModuleDescription(modName);
1383
1384         vector<string> pkgList = getPackageList(modName);
1385         docstring pkgdesc = formatStrVec(pkgList, _("and"));
1386         if (!pkgdesc.empty()) {
1387                 if (!desc.empty())
1388                         desc += "\n";
1389                 desc += bformat(_("Package(s) required: %1$s."), pkgdesc);
1390         }
1391
1392         pkgList = getRequiredList(modName);
1393         if (!pkgList.empty()) {
1394                 vector<string> const reqDescs = idsToNames(pkgList);
1395                 pkgdesc = formatStrVec(reqDescs, _("or"));
1396                 if (!desc.empty())
1397                         desc += "\n";
1398                 desc += bformat(_("Module required: %1$s."), pkgdesc);
1399         }
1400
1401         pkgList = getExcludedList(modName);
1402         if (!pkgList.empty()) {
1403                 vector<string> const reqDescs = idsToNames(pkgList);
1404                 pkgdesc = formatStrVec(reqDescs, _( "and"));
1405                 if (!desc.empty())
1406                         desc += "\n";
1407                 desc += bformat(_("Modules excluded: %1$s."), pkgdesc);
1408         }
1409
1410         if (!isModuleAvailable(modName)) {
1411                 if (!desc.empty())
1412                         desc += "\n";
1413                 desc += _("WARNING: Some packages are unavailable!");
1414         }
1415
1416         latexModule->infoML->document()->setPlainText(toqstr(desc));
1417 }
1418
1419
1420 void GuiDocument::setExtraEmbeddedFileList()
1421 {
1422         embeddedFilesModule->extraLW->clear();
1423         // add current embedded files
1424         vector<string> const & files = buffer().params().extraEmbeddedFiles();
1425         vector<string>::const_iterator fit = files.begin();
1426         vector<string>::const_iterator fit_end = files.end();
1427         for (; fit != fit_end; ++fit)
1428                 embeddedFilesModule->extraLW->addItem(toqstr(*fit));
1429 }
1430
1431
1432 void GuiDocument::addExtraEmbeddedFile()
1433 {
1434         QString const label1 = qt_("Documents|#o#O");
1435         QString const dir1 = toqstr(lyxrc.document_path);
1436         FileFilterList const filter(_("LyX Layout (*.layout);;LaTeX Classes (*.{cls,sty});;BibTeX Databases (*.{bib,bst})"));
1437         QString file = browseRelFile(QString(), bufferFilepath(),
1438                 qt_("Extra embedded file"), filter, true, label1, dir1);
1439
1440         if (file.isEmpty())
1441                 return;
1442
1443         if (embeddedFilesModule->extraLW->findItems(file, Qt::MatchExactly).empty())
1444                 embeddedFilesModule->extraLW->addItem(file);
1445 }
1446
1447
1448 void GuiDocument::removeExtraEmbeddedFile()
1449 {
1450         int index = embeddedFilesModule->extraLW->currentRow();
1451         delete embeddedFilesModule->extraLW->takeItem(index);
1452 }
1453
1454
1455 void GuiDocument::updateNumbering()
1456 {
1457         DocumentClass const & tclass = bp_.documentClass();
1458
1459         numberingModule->tocTW->setUpdatesEnabled(false);
1460         numberingModule->tocTW->clear();
1461
1462         int const depth = numberingModule->depthSL->value();
1463         int const toc = numberingModule->tocSL->value();
1464         QString const no = qt_("No");
1465         QString const yes = qt_("Yes");
1466         QTreeWidgetItem * item = 0;
1467
1468         DocumentClass::const_iterator lit = tclass.begin();
1469         DocumentClass::const_iterator len = tclass.end();
1470         for (; lit != len; ++lit) {
1471                 int const toclevel = lit->toclevel;
1472                 if (toclevel != Layout::NOT_IN_TOC && lit->labeltype == LABEL_COUNTER) {
1473                         item = new QTreeWidgetItem(numberingModule->tocTW);
1474                         item->setText(0, toqstr(translateIfPossible(lit->name())));
1475                         item->setText(1, (toclevel <= depth) ? yes : no);
1476                         item->setText(2, (toclevel <= toc) ? yes : no);
1477                 }
1478         }
1479
1480         numberingModule->tocTW->setUpdatesEnabled(true);
1481         numberingModule->tocTW->update();
1482 }
1483
1484
1485 void GuiDocument::apply(BufferParams & params)
1486 {
1487         // preamble
1488         preambleModule->apply(params);
1489
1490         // biblio
1491         params.setCiteEngine(biblio::ENGINE_BASIC);
1492
1493         if (biblioModule->citeNatbibRB->isChecked()) {
1494                 bool const use_numerical_citations =
1495                         biblioModule->citeStyleCO->currentIndex();
1496                 if (use_numerical_citations)
1497                         params.setCiteEngine(biblio::ENGINE_NATBIB_NUMERICAL);
1498                 else
1499                         params.setCiteEngine(biblio::ENGINE_NATBIB_AUTHORYEAR);
1500
1501         } else if (biblioModule->citeJurabibRB->isChecked())
1502                 params.setCiteEngine(biblio::ENGINE_JURABIB);
1503
1504         params.use_bibtopic =
1505                 biblioModule->bibtopicCB->isChecked();
1506
1507         // language & quotes
1508         if (langModule->defaultencodingRB->isChecked()) {
1509                 params.inputenc = "auto";
1510         } else {
1511                 int i = langModule->encodingCO->currentIndex();
1512                 if (i == 0)
1513                         params.inputenc = "default";
1514                 else
1515                         params.inputenc =
1516                                 fromqstr(langModule->encodingCO->currentText());
1517         }
1518
1519         InsetQuotes::QuoteLanguage lga = InsetQuotes::EnglishQuotes;
1520         switch (langModule->quoteStyleCO->currentIndex()) {
1521         case 0:
1522                 lga = InsetQuotes::EnglishQuotes;
1523                 break;
1524         case 1:
1525                 lga = InsetQuotes::SwedishQuotes;
1526                 break;
1527         case 2:
1528                 lga = InsetQuotes::GermanQuotes;
1529                 break;
1530         case 3:
1531                 lga = InsetQuotes::PolishQuotes;
1532                 break;
1533         case 4:
1534                 lga = InsetQuotes::FrenchQuotes;
1535                 break;
1536         case 5:
1537                 lga = InsetQuotes::DanishQuotes;
1538                 break;
1539         }
1540         params.quotes_language = lga;
1541
1542         int const pos = langModule->languageCO->currentIndex();
1543         params.language = lyx::languages.getLanguage(fromqstr(lang_[pos]));
1544
1545         // numbering
1546         if (params.documentClass().hasTocLevels()) {
1547                 params.tocdepth = numberingModule->tocSL->value();
1548                 params.secnumdepth = numberingModule->depthSL->value();
1549         }
1550
1551         // bullets
1552         params.user_defined_bullet(0) = bulletsModule->getBullet(0);
1553         params.user_defined_bullet(1) = bulletsModule->getBullet(1);
1554         params.user_defined_bullet(2) = bulletsModule->getBullet(2);
1555         params.user_defined_bullet(3) = bulletsModule->getBullet(3);
1556
1557         // packages
1558         params.graphicsDriver =
1559                 tex_graphics[latexModule->psdriverCO->currentIndex()];
1560         
1561         // text layout
1562         int idx = latexModule->classCO->currentIndex();
1563         if (idx >= 0) {
1564                 string const classname = classes_model_.getIDString(idx);
1565                 params.setBaseClass(classname);
1566         }
1567
1568         // Modules
1569         params.clearLayoutModules();
1570         int const srows = modules_sel_model_.rowCount();
1571         vector<string> selModList;
1572         for (int i = 0; i < srows; ++i)
1573                 params.addLayoutModule(modules_sel_model_.getIDString(i));
1574
1575         if (mathsModule->amsautoCB->isChecked()) {
1576                 params.use_amsmath = BufferParams::package_auto;
1577         } else {
1578                 if (mathsModule->amsCB->isChecked())
1579                         params.use_amsmath = BufferParams::package_on;
1580                 else
1581                         params.use_amsmath = BufferParams::package_off;
1582         }
1583
1584         if (mathsModule->esintautoCB->isChecked())
1585                 params.use_esint = BufferParams::package_auto;
1586         else {
1587                 if (mathsModule->esintCB->isChecked())
1588                         params.use_esint = BufferParams::package_on;
1589                 else
1590                         params.use_esint = BufferParams::package_off;
1591         }
1592
1593         if (pageLayoutModule->pagestyleCO->currentIndex() == 0)
1594                 params.pagestyle = "default";
1595         else {
1596                 docstring style_gui =
1597                         qstring_to_ucs4(pageLayoutModule->pagestyleCO->currentText());
1598                 for (size_t i = 0; i < pagestyles.size(); ++i)
1599                         if (pagestyles[i].second == style_gui)
1600                                 params.pagestyle = pagestyles[i].first;
1601         }
1602
1603         switch (textLayoutModule->lspacingCO->currentIndex()) {
1604         case 0:
1605                 params.spacing().set(Spacing::Single);
1606                 break;
1607         case 1:
1608                 params.spacing().set(Spacing::Onehalf);
1609                 break;
1610         case 2:
1611                 params.spacing().set(Spacing::Double);
1612                 break;
1613         case 3:
1614                 params.spacing().set(Spacing::Other,
1615                         fromqstr(textLayoutModule->lspacingLE->text()));
1616                 break;
1617         }
1618
1619         if (textLayoutModule->twoColumnCB->isChecked())
1620                 params.columns = 2;
1621         else
1622                 params.columns = 1;
1623
1624         // text should have passed validation
1625         params.listings_params =
1626                 InsetListingsParams(fromqstr(textLayoutModule->listingsED->toPlainText())).params();
1627
1628         if (textLayoutModule->indentRB->isChecked())
1629                 params.paragraph_separation = BufferParams::ParagraphIndentSeparation;
1630         else
1631                 params.paragraph_separation = BufferParams::ParagraphSkipSeparation;
1632
1633         switch (textLayoutModule->skipCO->currentIndex()) {
1634         case 0:
1635                 params.setDefSkip(VSpace(VSpace::SMALLSKIP));
1636                 break;
1637         case 1:
1638                 params.setDefSkip(VSpace(VSpace::MEDSKIP));
1639                 break;
1640         case 2:
1641                 params.setDefSkip(VSpace(VSpace::BIGSKIP));
1642                 break;
1643         case 3:
1644         {
1645                 VSpace vs = VSpace(
1646                         widgetsToLength(textLayoutModule->skipLE,
1647                                 textLayoutModule->skipLengthCO)
1648                         );
1649                 params.setDefSkip(vs);
1650                 break;
1651         }
1652         default:
1653                 // DocumentDefskipCB assures that this never happens
1654                 // so Assert then !!!  - jbl
1655                 params.setDefSkip(VSpace(VSpace::MEDSKIP));
1656                 break;
1657         }
1658
1659         params.options =
1660                 fromqstr(latexModule->optionsLE->text());
1661
1662         params.float_placement = floatModule->get();
1663
1664         // fonts
1665         params.fontsRoman =
1666                 tex_fonts_roman[fontModule->fontsRomanCO->currentIndex()];
1667
1668         params.fontsSans =
1669                 tex_fonts_sans[fontModule->fontsSansCO->currentIndex()];
1670
1671         params.fontsTypewriter =
1672                 tex_fonts_monospaced[fontModule->fontsTypewriterCO->currentIndex()];
1673
1674         params.fontsSansScale = fontModule->scaleSansSB->value();
1675
1676         params.fontsTypewriterScale = fontModule->scaleTypewriterSB->value();
1677
1678         params.fontsSC = fontModule->fontScCB->isChecked();
1679
1680         params.fontsOSF = fontModule->fontOsfCB->isChecked();
1681
1682         params.fontsDefaultFamily = GuiDocument::fontfamilies[
1683                 fontModule->fontsDefaultCO->currentIndex()];
1684
1685         if (fontModule->fontsizeCO->currentIndex() == 0)
1686                 params.fontsize = "default";
1687         else
1688                 params.fontsize =
1689                         fromqstr(fontModule->fontsizeCO->currentText());
1690
1691         // paper
1692         params.papersize = PAPER_SIZE(
1693                 pageLayoutModule->papersizeCO->currentIndex());
1694
1695         // custom, A3, B3 and B4 paper sizes need geometry
1696         int psize = pageLayoutModule->papersizeCO->currentIndex();
1697         bool geom_papersize = (psize == 1 || psize == 5 || psize == 8 || psize == 9);
1698
1699         params.paperwidth = widgetsToLength(pageLayoutModule->paperwidthLE,
1700                 pageLayoutModule->paperwidthUnitCO);
1701
1702         params.paperheight = widgetsToLength(pageLayoutModule->paperheightLE,
1703                 pageLayoutModule->paperheightUnitCO);
1704
1705         if (pageLayoutModule->facingPagesCB->isChecked())
1706                 params.sides = TwoSides;
1707         else
1708                 params.sides = OneSide;
1709
1710         if (pageLayoutModule->landscapeRB->isChecked())
1711                 params.orientation = ORIENTATION_LANDSCAPE;
1712         else
1713                 params.orientation = ORIENTATION_PORTRAIT;
1714
1715         // margins
1716         params.use_geometry = !marginsModule->marginCB->isChecked()
1717                 || geom_papersize;
1718
1719         Ui::MarginsUi const * m = marginsModule;
1720
1721         params.leftmargin = widgetsToLength(m->innerLE, m->innerUnit);
1722         params.topmargin = widgetsToLength(m->topLE, m->topUnit);
1723         params.rightmargin = widgetsToLength(m->outerLE, m->outerUnit);
1724         params.bottommargin = widgetsToLength(m->bottomLE, m->bottomUnit);
1725         params.headheight = widgetsToLength(m->headheightLE, m->headheightUnit);
1726         params.headsep = widgetsToLength(m->headsepLE, m->headsepUnit);
1727         params.footskip = widgetsToLength(m->footskipLE, m->footskipUnit);
1728         params.columnsep = widgetsToLength(m->columnsepLE, m->columnsepUnit);
1729
1730         branchesModule->apply(params);
1731
1732         // PDF support
1733         PDFOptions & pdf = params.pdfoptions();
1734         pdf.use_hyperref = pdfSupportModule->use_hyperrefGB->isChecked();
1735         pdf.title = fromqstr(pdfSupportModule->titleLE->text());
1736         pdf.author = fromqstr(pdfSupportModule->authorLE->text());
1737         pdf.subject = fromqstr(pdfSupportModule->subjectLE->text());
1738         pdf.keywords = fromqstr(pdfSupportModule->keywordsLE->text());
1739
1740         pdf.bookmarks = pdfSupportModule->bookmarksGB->isChecked();
1741         pdf.bookmarksnumbered = pdfSupportModule->bookmarksnumberedCB->isChecked();
1742         pdf.bookmarksopen = pdfSupportModule->bookmarksopenGB->isChecked();
1743         pdf.bookmarksopenlevel = pdfSupportModule->bookmarksopenlevelSB->value();
1744
1745         pdf.breaklinks = pdfSupportModule->breaklinksCB->isChecked();
1746         pdf.pdfborder = pdfSupportModule->pdfborderCB->isChecked();
1747         pdf.pdfusetitle = pdfSupportModule->pdfusetitleCB->isChecked();
1748         pdf.colorlinks = pdfSupportModule->colorlinksCB->isChecked();
1749         pdf.backref = pdfSupportModule->backrefCB->isChecked();
1750         pdf.pagebackref = pdfSupportModule->pagebackrefCB->isChecked();
1751         if (pdfSupportModule->fullscreenCB->isChecked())
1752                 pdf.pagemode = pdf.pagemode_fullscreen;
1753         else
1754                 pdf.pagemode.clear();
1755         pdf.quoted_options = pdf.quoted_options_check(
1756                                 fromqstr(pdfSupportModule->optionsLE->text()));
1757
1758         // Embedded files
1759         vector<string> & files = params.extraEmbeddedFiles();
1760         files.clear();
1761         for (int i = 0; i < embeddedFilesModule->extraLW->count(); ++i) {
1762                 QListWidgetItem * item = embeddedFilesModule->extraLW->item(i);
1763                 files.push_back(fromqstr(item->text()));
1764         }
1765 }
1766
1767
1768 static int findPos(QStringList const & vec, QString const & val)
1769 {
1770         for (int i = 0; i != vec.size(); ++i)
1771                 if (vec[i] == val)
1772                         return i;
1773         return 0;
1774 }
1775
1776
1777 void GuiDocument::updateParams()
1778 {
1779         updateParams(bp_);
1780 }
1781
1782
1783 void GuiDocument::updateParams(BufferParams const & params)
1784 {
1785         // set the default unit
1786         Length::UNIT defaultUnit = Length::CM;
1787         switch (lyxrc.default_papersize) {
1788                 case PAPER_DEFAULT: break;
1789
1790                 case PAPER_USLETTER:
1791                 case PAPER_USLEGAL:
1792                 case PAPER_USEXECUTIVE:
1793                         defaultUnit = Length::IN;
1794                         break;
1795
1796                 case PAPER_A3:
1797                 case PAPER_A4:
1798                 case PAPER_A5:
1799                 case PAPER_B3:
1800                 case PAPER_B4:
1801                 case PAPER_B5:
1802                         defaultUnit = Length::CM;
1803                         break;
1804                 case PAPER_CUSTOM:
1805                         break;
1806         }
1807
1808         // preamble
1809         preambleModule->update(params, id());
1810
1811         // biblio
1812         biblioModule->citeDefaultRB->setChecked(
1813                 params.citeEngine() == biblio::ENGINE_BASIC);
1814
1815         biblioModule->citeNatbibRB->setChecked(
1816                 params.citeEngine() == biblio::ENGINE_NATBIB_NUMERICAL ||
1817                 params.citeEngine() == biblio::ENGINE_NATBIB_AUTHORYEAR);
1818
1819         biblioModule->citeStyleCO->setCurrentIndex(
1820                 params.citeEngine() == biblio::ENGINE_NATBIB_NUMERICAL);
1821
1822         biblioModule->citeJurabibRB->setChecked(
1823                 params.citeEngine() == biblio::ENGINE_JURABIB);
1824
1825         biblioModule->bibtopicCB->setChecked(
1826                 params.use_bibtopic);
1827
1828         // language & quotes
1829         int const pos = findPos(lang_, toqstr(params.language->lang()));
1830         langModule->languageCO->setCurrentIndex(pos);
1831
1832         langModule->quoteStyleCO->setCurrentIndex(
1833                 params.quotes_language);
1834
1835         bool default_enc = true;
1836         if (params.inputenc != "auto") {
1837                 default_enc = false;
1838                 if (params.inputenc == "default") {
1839                         langModule->encodingCO->setCurrentIndex(0);
1840                 } else {
1841                         int const i = langModule->encodingCO->findText(
1842                                         toqstr(params.inputenc));
1843                         if (i >= 0)
1844                                 langModule->encodingCO->setCurrentIndex(i);
1845                         else
1846                                 // unknown encoding. Set to default.
1847                                 default_enc = true;
1848                 }
1849         }
1850         langModule->defaultencodingRB->setChecked(default_enc);
1851         langModule->otherencodingRB->setChecked(!default_enc);
1852
1853         // numbering
1854         int const min_toclevel = documentClass().min_toclevel();
1855         int const max_toclevel = documentClass().max_toclevel();
1856         if (documentClass().hasTocLevels()) {
1857                 numberingModule->setEnabled(true);
1858                 numberingModule->depthSL->setMinimum(min_toclevel - 1);
1859                 numberingModule->depthSL->setMaximum(max_toclevel);
1860                 numberingModule->depthSL->setValue(params.secnumdepth);
1861                 numberingModule->tocSL->setMaximum(min_toclevel - 1);
1862                 numberingModule->tocSL->setMaximum(max_toclevel);
1863                 numberingModule->tocSL->setValue(params.tocdepth);
1864                 updateNumbering();
1865         } else {
1866                 numberingModule->setEnabled(false);
1867                 numberingModule->tocTW->clear();
1868         }
1869
1870         // bullets
1871         bulletsModule->setBullet(0, params.user_defined_bullet(0));
1872         bulletsModule->setBullet(1, params.user_defined_bullet(1));
1873         bulletsModule->setBullet(2, params.user_defined_bullet(2));
1874         bulletsModule->setBullet(3, params.user_defined_bullet(3));
1875         bulletsModule->init();
1876
1877         // packages
1878         int nitem = findToken(tex_graphics, params.graphicsDriver);
1879         if (nitem >= 0)
1880                 latexModule->psdriverCO->setCurrentIndex(nitem);
1881         updateModuleInfo();
1882         
1883         mathsModule->amsCB->setChecked(
1884                 params.use_amsmath == BufferParams::package_on);
1885         mathsModule->amsautoCB->setChecked(
1886                 params.use_amsmath == BufferParams::package_auto);
1887
1888         mathsModule->esintCB->setChecked(
1889                 params.use_esint == BufferParams::package_on);
1890         mathsModule->esintautoCB->setChecked(
1891                 params.use_esint == BufferParams::package_auto);
1892
1893         switch (params.spacing().getSpace()) {
1894                 case Spacing::Other: nitem = 3; break;
1895                 case Spacing::Double: nitem = 2; break;
1896                 case Spacing::Onehalf: nitem = 1; break;
1897                 case Spacing::Default: case Spacing::Single: nitem = 0; break;
1898         }
1899
1900         // text layout
1901         string const & layoutID = params.baseClassID();
1902         setLayoutComboByIDString(layoutID);
1903
1904         updatePagestyle(documentClass().opt_pagestyle(),
1905                                  params.pagestyle);
1906
1907         textLayoutModule->lspacingCO->setCurrentIndex(nitem);
1908         if (params.spacing().getSpace() == Spacing::Other) {
1909                 textLayoutModule->lspacingLE->setText(
1910                         toqstr(params.spacing().getValueAsString()));
1911         }
1912         setLSpacing(nitem);
1913
1914         if (params.paragraph_separation == BufferParams::ParagraphIndentSeparation)
1915                 textLayoutModule->indentRB->setChecked(true);
1916         else
1917                 textLayoutModule->skipRB->setChecked(true);
1918
1919         int skip = 0;
1920         switch (params.getDefSkip().kind()) {
1921         case VSpace::SMALLSKIP:
1922                 skip = 0;
1923                 break;
1924         case VSpace::MEDSKIP:
1925                 skip = 1;
1926                 break;
1927         case VSpace::BIGSKIP:
1928                 skip = 2;
1929                 break;
1930         case VSpace::LENGTH:
1931         {
1932                 skip = 3;
1933                 string const length = params.getDefSkip().asLyXCommand();
1934                 lengthToWidgets(textLayoutModule->skipLE,
1935                         textLayoutModule->skipLengthCO,
1936                         length, defaultUnit);
1937                 break;
1938         }
1939         default:
1940                 skip = 0;
1941                 break;
1942         }
1943         textLayoutModule->skipCO->setCurrentIndex(skip);
1944         setSkip(skip);
1945
1946         textLayoutModule->twoColumnCB->setChecked(
1947                 params.columns == 2);
1948
1949         // break listings_params to multiple lines
1950         string lstparams =
1951                 InsetListingsParams(params.listings_params).separatedParams();
1952         textLayoutModule->listingsED->setPlainText(toqstr(lstparams));
1953
1954         if (!params.options.empty()) {
1955                 latexModule->optionsLE->setText(
1956                         toqstr(params.options));
1957         } else {
1958                 latexModule->optionsLE->setText(QString());
1959         }
1960
1961         floatModule->set(params.float_placement);
1962
1963         // Fonts
1964         updateFontsize(documentClass().opt_fontsize(),
1965                         params.fontsize);
1966
1967         int n = findToken(tex_fonts_roman, params.fontsRoman);
1968         if (n >= 0) {
1969                 fontModule->fontsRomanCO->setCurrentIndex(n);
1970                 romanChanged(n);
1971         }
1972
1973         n = findToken(tex_fonts_sans, params.fontsSans);
1974         if (n >= 0)     {
1975                 fontModule->fontsSansCO->setCurrentIndex(n);
1976                 sansChanged(n);
1977         }
1978
1979         n = findToken(tex_fonts_monospaced, params.fontsTypewriter);
1980         if (n >= 0) {
1981                 fontModule->fontsTypewriterCO->setCurrentIndex(n);
1982                 ttChanged(n);
1983         }
1984
1985         fontModule->fontScCB->setChecked(params.fontsSC);
1986         fontModule->fontOsfCB->setChecked(params.fontsOSF);
1987         fontModule->scaleSansSB->setValue(params.fontsSansScale);
1988         fontModule->scaleTypewriterSB->setValue(params.fontsTypewriterScale);
1989         n = findToken(GuiDocument::fontfamilies, params.fontsDefaultFamily);
1990         if (n >= 0)
1991                 fontModule->fontsDefaultCO->setCurrentIndex(n);
1992
1993         // paper
1994         int const psize = params.papersize;
1995         pageLayoutModule->papersizeCO->setCurrentIndex(psize);
1996         setCustomPapersize(psize);
1997
1998         bool const landscape =
1999                 params.orientation == ORIENTATION_LANDSCAPE;
2000         pageLayoutModule->landscapeRB->setChecked(landscape);
2001         pageLayoutModule->portraitRB->setChecked(!landscape);
2002
2003         pageLayoutModule->facingPagesCB->setChecked(
2004                 params.sides == TwoSides);
2005
2006
2007         lengthToWidgets(pageLayoutModule->paperwidthLE,
2008                 pageLayoutModule->paperwidthUnitCO, params.paperwidth, defaultUnit);
2009
2010         lengthToWidgets(pageLayoutModule->paperheightLE,
2011                 pageLayoutModule->paperheightUnitCO, params.paperheight, defaultUnit);
2012
2013         // margins
2014         Ui::MarginsUi * m = marginsModule;
2015
2016         setMargins(!params.use_geometry);
2017
2018         lengthToWidgets(m->topLE, m->topUnit,
2019                 params.topmargin, defaultUnit);
2020
2021         lengthToWidgets(m->bottomLE, m->bottomUnit,
2022                 params.bottommargin, defaultUnit);
2023
2024         lengthToWidgets(m->innerLE, m->innerUnit,
2025                 params.leftmargin, defaultUnit);
2026
2027         lengthToWidgets(m->outerLE, m->outerUnit,
2028                 params.rightmargin, defaultUnit);
2029
2030         lengthToWidgets(m->headheightLE, m->headheightUnit,
2031                 params.headheight, defaultUnit);
2032
2033         lengthToWidgets(m->headsepLE, m->headsepUnit,
2034                 params.headsep, defaultUnit);
2035
2036         lengthToWidgets(m->footskipLE, m->footskipUnit,
2037                 params.footskip, defaultUnit);
2038
2039         lengthToWidgets(m->columnsepLE, m->columnsepUnit,
2040                 params.columnsep, defaultUnit);
2041
2042         branchesModule->update(params);
2043
2044         // PDF support
2045         PDFOptions const & pdf = params.pdfoptions();
2046         pdfSupportModule->use_hyperrefGB->setChecked(pdf.use_hyperref);
2047         pdfSupportModule->titleLE->setText(toqstr(pdf.title));
2048         pdfSupportModule->authorLE->setText(toqstr(pdf.author));
2049         pdfSupportModule->subjectLE->setText(toqstr(pdf.subject));
2050         pdfSupportModule->keywordsLE->setText(toqstr(pdf.keywords));
2051
2052         pdfSupportModule->bookmarksGB->setChecked(pdf.bookmarks);
2053         pdfSupportModule->bookmarksnumberedCB->setChecked(pdf.bookmarksnumbered);
2054         pdfSupportModule->bookmarksopenGB->setChecked(pdf.bookmarksopen);
2055
2056         pdfSupportModule->bookmarksopenlevelSB->setValue(pdf.bookmarksopenlevel);
2057
2058         pdfSupportModule->breaklinksCB->setChecked(pdf.breaklinks);
2059         pdfSupportModule->pdfborderCB->setChecked(pdf.pdfborder);
2060         pdfSupportModule->pdfusetitleCB->setChecked(pdf.pdfusetitle);
2061         pdfSupportModule->colorlinksCB->setChecked(pdf.colorlinks);
2062         pdfSupportModule->backrefCB->setChecked(pdf.backref);
2063         pdfSupportModule->pagebackrefCB->setChecked(pdf.pagebackref);
2064         pdfSupportModule->fullscreenCB->setChecked
2065                 (pdf.pagemode == pdf.pagemode_fullscreen);
2066
2067         pdfSupportModule->optionsLE->setText(
2068                 toqstr(pdf.quoted_options));
2069         
2070         setExtraEmbeddedFileList();
2071 }
2072
2073
2074 void GuiDocument::applyView()
2075 {
2076         apply(params());
2077 }
2078
2079
2080 void GuiDocument::saveDocDefault()
2081 {
2082         // we have to apply the params first
2083         applyView();
2084         saveAsDefault();
2085 }
2086
2087
2088 void GuiDocument::updateAvailableModules() 
2089 {
2090         modules_av_model_.clear();
2091         vector<modInfoStruct> const modInfoList = getModuleInfo();
2092         int const mSize = modInfoList.size();
2093         for (int i = 0; i != mSize; ++i) {
2094                 modInfoStruct const & modInfo = modInfoList[i];
2095                 modules_av_model_.insertRow(i, qt_(modInfo.name), modInfo.id);
2096         }
2097 }
2098
2099
2100 void GuiDocument::updateSelectedModules() 
2101 {
2102         // and selected ones, too
2103         modules_sel_model_.clear();
2104         vector<modInfoStruct> const selModList = getSelectedModules();
2105         int const sSize = selModList.size();
2106         for (int i = 0; i != sSize; ++i) {
2107                 modInfoStruct const & modInfo = selModList[i];
2108                 modules_sel_model_.insertRow(i, qt_(modInfo.name), modInfo.id);
2109         }
2110 }
2111
2112
2113 void GuiDocument::updateContents()
2114 {
2115         if (id() == current_id_)
2116                 return;
2117
2118         updateAvailableModules();
2119         updateSelectedModules();
2120         
2121         //FIXME It'd be nice to make sure here that the selected
2122         //modules are consistent: That required modules are actually
2123         //selected, and that we don't have conflicts. If so, we could
2124         //at least pop up a warning.
2125         updateParams(bp_);
2126         current_id_ = id();
2127 }
2128
2129
2130 void GuiDocument::forceUpdate()
2131 {
2132         // reset to force dialog update
2133         current_id_ = 0;
2134         updateContents();
2135 }
2136
2137
2138 void GuiDocument::useClassDefaults()
2139 {
2140         if (applyPB->isEnabled()) {
2141                 int const ret = Alert::prompt(_("Unapplied changes"),
2142                                 _("Some changes in the dialog were not yet applied.\n"
2143                                   "If you do not apply now, they will be lost after this action."),
2144                                 1, 1, _("&Apply"), _("&Dismiss"));
2145                 if (ret == 0)
2146                         applyView();
2147         }
2148
2149         int idx = latexModule->classCO->currentIndex();
2150         string const classname = classes_model_.getIDString(idx);
2151         if (!bp_.setBaseClass(classname)) {
2152                 Alert::error(_("Error"), _("Unable to set document class."));
2153                 return;
2154         }
2155         bp_.useClassDefaults();
2156         forceUpdate();
2157 }
2158
2159
2160 void GuiDocument::setLayoutComboByIDString(std::string const & idString)
2161 {
2162         int idx = classes_model_.findIDString(idString);
2163         if (idx < 0)
2164                 Alert::warning(_("Can't set layout!"), 
2165                         bformat(_("Unable to set layout for ID: %1$s"), from_utf8(idString)));
2166         else 
2167                 latexModule->classCO->setCurrentIndex(idx);
2168 }
2169
2170
2171 bool GuiDocument::isValid()
2172 {
2173         return validate_listings_params().empty()
2174                 && (textLayoutModule->skipCO->currentIndex() != 3
2175                         || !textLayoutModule->skipLE->text().isEmpty());
2176 }
2177
2178
2179 char const * const GuiDocument::fontfamilies[5] = {
2180         "default", "rmdefault", "sfdefault", "ttdefault", ""
2181 };
2182
2183
2184 char const * GuiDocument::fontfamilies_gui[5] = {
2185         N_("Default"), N_("Roman"), N_("Sans Serif"), N_("Typewriter"), ""
2186 };
2187
2188
2189 bool GuiDocument::initialiseParams(string const &)
2190 {
2191         bp_ = buffer().params();
2192         loadModuleInfo();
2193         return true;
2194 }
2195
2196
2197 void GuiDocument::clearParams()
2198 {
2199         bp_ = BufferParams();
2200 }
2201
2202
2203 BufferId GuiDocument::id() const
2204 {
2205         return &buffer();
2206 }
2207
2208
2209 vector<GuiDocument::modInfoStruct> const & GuiDocument::getModuleInfo()
2210 {
2211         return moduleNames_;
2212 }
2213
2214
2215 vector<GuiDocument::modInfoStruct> const GuiDocument::getSelectedModules()
2216 {
2217         vector<string> const & mods = params().getModules();
2218         vector<string>::const_iterator it =  mods.begin();
2219         vector<string>::const_iterator end = mods.end();
2220         vector<modInfoStruct> mInfo;
2221         for (; it != end; ++it) {
2222                 modInfoStruct m;
2223                 m.id = *it;
2224                 LyXModule * mod = moduleList[*it];
2225                 if (mod)
2226                         m.name = mod->getName();
2227                 else 
2228                         m.name = *it + " (Not Found)";
2229                 mInfo.push_back(m);
2230         }
2231         return mInfo;
2232 }
2233
2234
2235 DocumentClass const & GuiDocument::documentClass() const
2236 {
2237         return bp_.documentClass();
2238 }
2239
2240
2241 static void dispatch_bufferparams(Dialog const & dialog,
2242         BufferParams const & bp, FuncCode lfun)
2243 {
2244         ostringstream ss;
2245         ss << "\\begin_header\n";
2246         bp.writeFile(ss);
2247         ss << "\\end_header\n";
2248         dialog.dispatch(FuncRequest(lfun, ss.str()));
2249 }
2250
2251
2252 void GuiDocument::dispatchParams()
2253 {
2254         // This must come first so that a language change is correctly noticed
2255         setLanguage();
2256
2257         // Apply the BufferParams. Note that this will set the base class
2258         // and then update the buffer's layout.
2259         dispatch_bufferparams(*this, params(), LFUN_BUFFER_PARAMS_APPLY);
2260
2261         // Generate the colours requested by each new branch.
2262         BranchList & branchlist = params().branchlist();
2263         if (!branchlist.empty()) {
2264                 BranchList::const_iterator it = branchlist.begin();
2265                 BranchList::const_iterator const end = branchlist.end();
2266                 for (; it != end; ++it) {
2267                         docstring const & current_branch = it->getBranch();
2268                         Branch const * branch = branchlist.find(current_branch);
2269                         string const x11hexname = X11hexname(branch->getColor());
2270                         // display the new color
2271                         docstring const str = current_branch + ' ' + from_ascii(x11hexname);
2272                         dispatch(FuncRequest(LFUN_SET_COLOR, str));
2273                 }
2274
2275                 // Open insets of selected branches, close deselected ones
2276                 dispatch(FuncRequest(LFUN_ALL_INSETS_TOGGLE,
2277                         "assign branch"));
2278         }
2279         // FIXME: If we used an LFUN, we would not need those two lines:
2280         bufferview()->processUpdateFlags(Update::Force | Update::FitCursor);
2281 }
2282
2283
2284 void GuiDocument::setLanguage() const
2285 {
2286         Language const * const newL = bp_.language;
2287         if (buffer().params().language == newL)
2288                 return;
2289
2290         string const & lang_name = newL->lang();
2291         dispatch(FuncRequest(LFUN_BUFFER_LANGUAGE, lang_name));
2292 }
2293
2294
2295 void GuiDocument::saveAsDefault() const
2296 {
2297         dispatch_bufferparams(*this, params(), LFUN_BUFFER_SAVE_AS_DEFAULT);
2298 }
2299
2300
2301 bool GuiDocument::isFontAvailable(string const & font) const
2302 {
2303         if (font == "default" || font == "cmr"
2304             || font == "cmss" || font == "cmtt")
2305                 // these are standard
2306                 return true;
2307         if (font == "lmodern" || font == "lmss" || font == "lmtt")
2308                 return LaTeXFeatures::isAvailable("lmodern");
2309         if (font == "times" || font == "palatino"
2310                  || font == "helvet" || font == "courier")
2311                 return LaTeXFeatures::isAvailable("psnfss");
2312         if (font == "cmbr" || font == "cmtl")
2313                 return LaTeXFeatures::isAvailable("cmbright");
2314         if (font == "utopia")
2315                 return LaTeXFeatures::isAvailable("utopia")
2316                         || LaTeXFeatures::isAvailable("fourier");
2317         if (font == "beraserif" || font == "berasans"
2318                 || font == "beramono")
2319                 return LaTeXFeatures::isAvailable("bera");
2320         return LaTeXFeatures::isAvailable(font);
2321 }
2322
2323
2324 bool GuiDocument::providesOSF(string const & font) const
2325 {
2326         if (font == "cmr")
2327                 return isFontAvailable("eco");
2328         if (font == "palatino")
2329                 return isFontAvailable("mathpazo");
2330         return false;
2331 }
2332
2333
2334 bool GuiDocument::providesSC(string const & font) const
2335 {
2336         if (font == "palatino")
2337                 return isFontAvailable("mathpazo");
2338         if (font == "utopia")
2339                 return isFontAvailable("fourier");
2340         return false;
2341 }
2342
2343
2344 bool GuiDocument::providesScale(string const & font) const
2345 {
2346         return font == "helvet" || font == "luximono"
2347                 || font == "berasans"  || font == "beramono";
2348 }
2349
2350
2351 void GuiDocument::loadModuleInfo()
2352 {
2353         moduleNames_.clear();
2354         LyXModuleList::const_iterator it  = moduleList.begin();
2355         LyXModuleList::const_iterator end = moduleList.end();
2356         for (; it != end; ++it) {
2357                 modInfoStruct m;
2358                 m.id = it->getID();
2359                 m.name = it->getName();
2360                 moduleNames_.push_back(m);
2361         }
2362 }
2363
2364
2365 Dialog * createGuiDocument(GuiView & lv) { return new GuiDocument(lv); }
2366
2367
2368 } // namespace frontend
2369 } // namespace lyx
2370
2371 #include "GuiDocument_moc.cpp"