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