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