]> git.lyx.org Git - features.git/blob - src/frontends/qt4/GuiTabular.cpp
With xltabular, multi-page tables can have a fixed width
[features.git] / src / frontends / qt4 / GuiTabular.cpp
1 /**
2  * \file GuiTabular.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Jürgen Spitzmüller
8  * \author Herbert Voß
9  * \author Uwe Stöhr
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "GuiTabular.h"
17
18 #include "GuiApplication.h"
19 #include "GuiSetBorder.h"
20 #include "GuiView.h"
21 #include "LengthCombo.h"
22 #include "qt_helpers.h"
23 #include "Validator.h"
24
25 #include "BufferView.h"
26 #include "Cursor.h"
27 #include "FuncRequest.h"
28 #include "FuncStatus.h"
29 #include "LyX.h"
30 #include "LyXRC.h"
31
32 #include "insets/InsetTabular.h"
33
34 #include "support/convert.h"
35 #include "support/debug.h"
36
37 #include <QCheckBox>
38 #include <QPushButton>
39 #include <QRadioButton>
40 #include <QLineEdit>
41
42 using namespace std;
43
44 namespace lyx {
45 namespace frontend {
46
47 GuiTabular::GuiTabular(QWidget * parent)
48         : InsetParamsWidget(parent), firstheader_suppressable_(false),
49           lastfooter_suppressable_(false)
50
51 {
52         setupUi(this);
53
54         tabularWidthED->setValidator(unsignedLengthValidator(tabularWidthED));
55         columnWidthED->setValidator(unsignedLengthValidator(columnWidthED));
56         multirowOffsetED->setValidator(new LengthValidator(multirowOffsetED));
57         topspaceED->setValidator(new LengthValidator(topspaceED));
58         bottomspaceED->setValidator(new LengthValidator(bottomspaceED));
59         interlinespaceED->setValidator(new LengthValidator(interlinespaceED));
60
61         tabularWidthUnitLC->setCurrentItem(Length::defaultUnit());
62         columnWidthUnitLC->setCurrentItem(Length::defaultUnit());
63         multirowOffsetUnitLC->setCurrentItem(Length::defaultUnit());
64         topspaceUnitLC->setCurrentItem(Length::defaultUnit());
65         bottomspaceUnitLC->setCurrentItem(Length::defaultUnit());
66         interlinespaceUnitLC->setCurrentItem(Length::defaultUnit());
67
68         connect(topspaceED, SIGNAL(textEdited(const QString &)),
69                 this, SLOT(checkEnabled()));
70         connect(topspaceUnitLC, SIGNAL(selectionChanged(lyx::Length::UNIT)),
71                 this, SLOT(checkEnabled()));
72         connect(bottomspaceED, SIGNAL(textEdited(const QString &)),
73                 this, SLOT(checkEnabled()));
74         connect(bottomspaceUnitLC, SIGNAL(selectionChanged(lyx::Length::UNIT)),
75                 this, SLOT(checkEnabled()));
76         connect(interlinespaceED, SIGNAL(textEdited(const QString &)),
77                 this, SLOT(checkEnabled()));
78         connect(interlinespaceUnitLC, SIGNAL(selectionChanged(lyx::Length::UNIT)),
79                 this, SLOT(checkEnabled()));
80         connect(booktabsRB, SIGNAL(clicked(bool)),
81                 this, SLOT(checkEnabled()));
82         connect(borderDefaultRB, SIGNAL(clicked(bool)),
83                 this, SLOT(checkEnabled()));
84         connect(borderSetPB, SIGNAL(clicked()),
85                 this, SLOT(borderSet_clicked()));
86         connect(borderUnsetPB, SIGNAL(clicked()),
87                 this, SLOT(borderUnset_clicked()));
88         connect(hAlignCO, SIGNAL(activated(int)),
89                 this, SLOT(checkEnabled()));
90         connect(vAlignCO, SIGNAL(activated(int)),
91                 this, SLOT(checkEnabled()));
92         connect(multicolumnCB, SIGNAL(clicked()),
93                 this, SLOT(checkEnabled()));
94         connect(multirowCB, SIGNAL(clicked()),
95                 this, SLOT(checkEnabled()));
96         connect(multirowOffsetED, SIGNAL(textEdited(const QString &)),
97                 this, SLOT(checkEnabled()));
98         connect(multirowOffsetUnitLC, SIGNAL(selectionChanged(lyx::Length::UNIT)),
99                 this, SLOT(checkEnabled()));
100         connect(newpageCB, SIGNAL(clicked()),
101                 this, SLOT(checkEnabled()));
102         connect(headerStatusCB, SIGNAL(clicked()),
103                 this, SLOT(checkEnabled()));
104         connect(headerBorderAboveCB, SIGNAL(clicked()),
105                 this, SLOT(checkEnabled()));
106         connect(headerBorderBelowCB, SIGNAL(clicked()),
107                 this, SLOT(checkEnabled()));
108         connect(firstheaderStatusCB, SIGNAL(clicked()),
109                 this, SLOT(checkEnabled()));
110         connect(firstheaderBorderAboveCB, SIGNAL(clicked()),
111                 this, SLOT(checkEnabled()));
112         connect(firstheaderBorderBelowCB, SIGNAL(clicked()),
113                 this, SLOT(checkEnabled()));
114         connect(firstheaderNoContentsCB, SIGNAL(clicked()),
115                 this, SLOT(checkEnabled()));
116         connect(footerStatusCB, SIGNAL(clicked()),
117                 this, SLOT(checkEnabled()));
118         connect(footerBorderAboveCB, SIGNAL(clicked()),
119                 this, SLOT(checkEnabled()));
120         connect(footerBorderBelowCB, SIGNAL(clicked()),
121                 this, SLOT(checkEnabled()));
122         connect(lastfooterStatusCB, SIGNAL(clicked()),
123                 this, SLOT(checkEnabled()));
124         connect(lastfooterBorderAboveCB, SIGNAL(clicked()),
125                 this, SLOT(checkEnabled()));
126         connect(lastfooterBorderBelowCB, SIGNAL(clicked()),
127                 this, SLOT(checkEnabled()));
128         connect(lastfooterNoContentsCB, SIGNAL(clicked()),
129                 this, SLOT(checkEnabled()));
130         connect(captionStatusCB, SIGNAL(clicked()),
131                 this, SLOT(checkEnabled()));
132         connect(specialAlignmentED, SIGNAL(textEdited(const QString &)),
133                 this, SLOT(checkEnabled()));
134         connect(columnWidthED, SIGNAL(textEdited(const QString &)),
135                 this, SLOT(checkEnabled()));
136         connect(columnWidthUnitLC, SIGNAL(selectionChanged(lyx::Length::UNIT)),
137                 this, SLOT(checkEnabled()));
138         connect(borders, SIGNAL(topSet(bool)),
139                 this, SLOT(checkEnabled()));
140         connect(borders, SIGNAL(bottomSet(bool)),
141                 this, SLOT(checkEnabled()));
142         connect(borders, SIGNAL(rightSet(bool)),
143                 this, SLOT(checkEnabled()));
144         connect(borders, SIGNAL(leftSet(bool)),
145                 this, SLOT(checkEnabled()));
146         connect(rotateTabularCB, SIGNAL(clicked()),
147                 this, SLOT(checkEnabled()));
148         connect(rotateTabularAngleSB, SIGNAL(valueChanged(int)),
149                 this, SLOT(checkEnabled()));
150         connect(rotateCellCB, SIGNAL(clicked()),
151                 this, SLOT(checkEnabled()));
152         connect(rotateCellAngleSB, SIGNAL(valueChanged(int)),
153                 this, SLOT(checkEnabled()));
154         connect(TableAlignCO, SIGNAL(activated(int)),
155                 this, SLOT(checkEnabled()));
156         connect(longTabularCB, SIGNAL(clicked()),
157                 this, SLOT(checkEnabled()));
158         connect(leftRB, SIGNAL(clicked()),
159                 this, SLOT(checkEnabled()));
160         connect(centerRB, SIGNAL(clicked()),
161                 this, SLOT(checkEnabled()));
162         connect(rightRB, SIGNAL(clicked()),
163                 this, SLOT(checkEnabled()));
164         connect(tabularWidthED, SIGNAL(textEdited(const QString &)),
165                 this, SLOT(checkEnabled()));
166
167         decimalPointED->setInputMask("X; ");
168         decimalPointED->setMaxLength(1);
169
170         // initialize the length validator
171         addCheckedWidget(columnWidthED, columnWidthLA);
172         addCheckedWidget(multirowOffsetED, multirowOffsetLA);
173         addCheckedWidget(topspaceED, topspaceLA);
174         addCheckedWidget(bottomspaceED, bottomspaceLA);
175         addCheckedWidget(interlinespaceED, interlinespaceLA);
176         addCheckedWidget(tabularWidthED, tabularWidthLA);
177 }
178
179
180 void GuiTabular::on_topspaceCO_activated(int index)
181 {
182         bool const enable = (index == 2);
183         topspaceED->setEnabled(enable);
184         topspaceUnitLC->setEnabled(enable);
185 }
186
187
188 void GuiTabular::on_bottomspaceCO_activated(int index)
189 {
190         bool const enable = (index == 2);
191         bottomspaceED->setEnabled(enable);
192         bottomspaceUnitLC->setEnabled(enable);
193 }
194
195
196 void GuiTabular::on_interlinespaceCO_activated(int index)
197 {
198         bool const enable = (index == 2);
199         interlinespaceED->setEnabled(enable);
200         interlinespaceUnitLC->setEnabled(enable);
201 }
202
203
204 void GuiTabular::on_columnTypeCO_activated(int index)
205 {
206         checkEnabled();
207         if (index == 2)
208                 columnWidthED->setFocus();
209 }
210
211
212 void GuiTabular::enableWidgets() const
213 {
214         // if there is a LaTeX argument, the width and alignment will be overwritten
215         // therefore disable them in this case
216         bool const fixed = specialAlignmentED->text().isEmpty()
217                         && columnTypeCO->currentIndex() == 2;
218         columnWidthED->setEnabled(fixed);
219         columnWidthUnitLC->setEnabled(fixed);
220         // if the column has a width, multirows are always left-aligned
221         // therefore disable hAlignCB in this case
222         hAlignCO->setEnabled(!(multirowCB->isChecked()
223                 && !widgetsToLength(columnWidthED, columnWidthUnitLC).empty())
224                 && specialAlignmentED->text().isEmpty());
225         // decimal alignment is only possible for non-multicol and non-multirow cells
226         if ((multicolumnCB->isChecked() || multirowCB->isChecked() || columnTypeCO->currentIndex() == 1)
227                 && hAlignCO->findData(toqstr("decimal")))
228                 hAlignCO->removeItem(hAlignCO->findData(toqstr("decimal")));
229         else if (!multicolumnCB->isChecked() && !multirowCB->isChecked()
230                 && hAlignCO->findData(toqstr("decimal")) == -1)
231                 hAlignCO->addItem(qt_("At Decimal Separator"), toqstr("decimal"));
232         bool const dalign =
233                 hAlignCO->itemData(hAlignCO->currentIndex()).toString() == QString("decimal");
234         decimalPointED->setEnabled(dalign);
235         decimalLA->setEnabled(dalign);
236
237         bool const setwidth = TableAlignCO->currentText() == qt_("Middle");
238         tabularWidthLA->setEnabled(setwidth);
239         tabularWidthED->setEnabled(setwidth);
240         tabularWidthUnitLC->setEnabled(setwidth);
241
242         rotateTabularAngleSB->setEnabled(rotateTabularCB->isChecked()
243                                          && !longTabularCB->isChecked());
244         rotateCellAngleSB->setEnabled(rotateCellCB->isChecked());
245
246         bool const enable_valign =
247                 !multirowCB->isChecked()
248                 && !widgetsToLength(columnWidthED, columnWidthUnitLC).empty()
249                 && specialAlignmentED->text().isEmpty();
250         vAlignCO->setEnabled(enable_valign);
251         vAlignLA->setEnabled(enable_valign);
252
253         topspaceED->setEnabled(topspaceCO->currentIndex() == 2);
254         topspaceED->setEnabled(topspaceCO->currentIndex() == 2);
255         topspaceUnitLC->setEnabled(topspaceCO->currentIndex() == 2);
256         bottomspaceED->setEnabled(bottomspaceCO->currentIndex() == 2);
257         bottomspaceUnitLC->setEnabled(bottomspaceCO->currentIndex() == 2);
258         interlinespaceED->setEnabled(interlinespaceCO->currentIndex() == 2);
259         interlinespaceUnitLC->setEnabled(interlinespaceCO->currentIndex() == 2);
260
261         // setting as longtable is not allowed when table is inside a float
262         bool const is_tabular_star = !tabularWidthED->text().isEmpty();
263         longTabularCB->setEnabled(funcEnabled(Tabular::SET_LONGTABULAR));
264         bool const longtabular = longTabularCB->isChecked();
265         longtableGB->setEnabled(true);
266         newpageCB->setEnabled(longtabular);
267         alignmentGB->setEnabled(longtabular);
268         // longtables and tabular* cannot have a vertical alignment
269         TableAlignLA->setDisabled(is_tabular_star || longtabular);
270         TableAlignCO->setDisabled(is_tabular_star || longtabular);
271         // longtable cannot be rotated with rotating package, only
272         // with [pdf]lscape, which only supports 90 deg.
273         rotateTabularAngleSB->setDisabled(longtabular);
274
275         // FIXME: This Dialog is really horrible, disabling/enabling a checkbox
276         // depending on the cursor position is very very unintuitive...
277         // We need some edit boxes to show which rows are header/footer/etc
278         // without having to move the cursor first.
279         headerStatusCB->setEnabled(longtabular
280                 && (headerStatusCB->isChecked() ?
281                     funcEnabled(Tabular::UNSET_LTHEAD) :
282                     funcEnabled(Tabular::SET_LTHEAD)));
283         headerBorderAboveCB->setEnabled(longtabular
284                 && headerStatusCB->isChecked());
285         headerBorderBelowCB->setEnabled(longtabular
286                 && headerStatusCB->isChecked());
287
288         // first header can only be suppressed when there is a header
289         // firstheader_suppressable_ is set in paramsToDialog
290         firstheaderNoContentsCB->setEnabled(longtabular && firstheader_suppressable_);
291         // check if setting a first header is allowed
292         // additionally check firstheaderNoContentsCB because when this is
293         // the case a first header makes no sense
294         firstheaderStatusCB->setEnabled((firstheaderStatusCB->isChecked() ?
295                    funcEnabled(Tabular::UNSET_LTFIRSTHEAD) :
296                    funcEnabled(Tabular::SET_LTFIRSTHEAD))
297                 && longtabular && !firstheaderNoContentsCB->isChecked());
298         firstheaderBorderAboveCB->setEnabled(longtabular
299                 && firstheaderStatusCB->isChecked());
300         firstheaderBorderBelowCB->setEnabled(longtabular
301                 && firstheaderStatusCB->isChecked());
302
303         footerStatusCB->setEnabled(longtabular
304                 && (footerStatusCB->isChecked() ?
305                     funcEnabled(Tabular::UNSET_LTFOOT) :
306                     funcEnabled(Tabular::SET_LTFOOT)));
307         footerBorderAboveCB->setEnabled(longtabular
308                 && footerBorderAboveCB->isChecked());
309         footerBorderBelowCB->setEnabled(longtabular
310                 && footerBorderAboveCB->isChecked());
311
312         // last footer can only be suppressed when there is a footer
313         // lastfooter_suppressable_ is set in paramsToDialog
314         lastfooterNoContentsCB->setEnabled(longtabular && lastfooter_suppressable_);
315         // check if setting a last footer is allowed
316         // additionally check lastfooterNoContentsCB because when this is
317         // the case a last footer makes no sense
318         lastfooterStatusCB->setEnabled((lastfooterStatusCB->isChecked() ?
319                    funcEnabled(Tabular::UNSET_LTLASTFOOT) :
320                    funcEnabled(Tabular::SET_LTLASTFOOT))
321                 && longtabular && !lastfooterNoContentsCB->isChecked());
322         lastfooterBorderAboveCB->setEnabled(longtabular
323                 && lastfooterBorderAboveCB->isChecked());
324         lastfooterBorderBelowCB->setEnabled(longtabular
325                 && lastfooterBorderAboveCB->isChecked());
326
327         captionStatusCB->setEnabled(funcEnabled(Tabular::TOGGLE_LTCAPTION)
328                 && longtabular);
329
330         multicolumnCB->setEnabled(funcEnabled(Tabular::MULTICOLUMN)
331                 && !dalign && !multirowCB->isChecked());
332         multirowCB->setEnabled(funcEnabled(Tabular::MULTIROW)
333                 && !dalign && !multicolumnCB->isChecked());
334         bool const enable_mr = multirowCB->isChecked();
335         multirowOffsetLA->setEnabled(enable_mr);
336         multirowOffsetED->setEnabled(enable_mr);
337         multirowOffsetUnitLC->setEnabled(enable_mr);
338
339         // Vertical lines cannot be set in formal tables
340         borders->setLeftEnabled(!booktabsRB->isChecked());
341         borders->setRightEnabled(!booktabsRB->isChecked());
342 }
343
344
345 void GuiTabular::checkEnabled()
346 {
347         enableWidgets();
348         changed();
349 }
350
351
352 void GuiTabular::borderSet_clicked()
353 {
354         borders->setTop(true);
355         borders->setBottom(true);
356         borders->setLeft(true);
357         borders->setRight(true);
358         // repaint the setborder widget
359         borders->update();
360         checkEnabled();
361 }
362
363
364 void GuiTabular::borderUnset_clicked()
365 {
366         borders->setTop(false);
367         borders->setBottom(false);
368         borders->setLeft(false);
369         borders->setRight(false);
370         // repaint the setborder widget
371         borders->update();
372         checkEnabled();
373 }
374
375
376 static void setParam(string & param_str, Tabular::Feature f, string const & arg = string())
377 {
378         param_str += ' ';
379         param_str += featureAsString(f) + ' ' + arg;
380 }
381
382
383 void GuiTabular::setHAlign(string & param_str) const
384 {
385         Tabular::Feature num = Tabular::ALIGN_LEFT;
386         Tabular::Feature multi_num = Tabular::M_ALIGN_LEFT;
387         string const align =
388                 fromqstr(hAlignCO->itemData(hAlignCO->currentIndex()).toString());
389         if (align == "left") {
390                 num = Tabular::ALIGN_LEFT;
391                 multi_num = Tabular::M_ALIGN_LEFT;
392         } else if (align == "center") {
393                 num = Tabular::ALIGN_CENTER;
394                 multi_num = Tabular::M_ALIGN_CENTER;
395         } else if (align == "right") {
396                 num = Tabular::ALIGN_RIGHT;
397                 multi_num = Tabular::M_ALIGN_RIGHT;
398         } else if (align == "justified") {
399                 num = Tabular::ALIGN_BLOCK;
400                 //multi_num: no equivalent
401         } else if (align == "decimal") {
402                 num = Tabular::ALIGN_DECIMAL;
403                 //multi_num: no equivalent
404         }
405
406         if (multicolumnCB->isChecked())
407                 setParam(param_str, multi_num);
408         else
409                 setParam(param_str, num);
410 }
411
412
413 void GuiTabular::setVAlign(string & param_str) const
414 {
415         int const align = vAlignCO->currentIndex();
416         enum VALIGN { TOP, MIDDLE, BOTTOM };
417         VALIGN v = TOP;
418
419         switch (align) {
420                 case 0: v = TOP; break;
421                 case 1: v = MIDDLE; break;
422                 case 2: v = BOTTOM; break;
423         }
424
425         Tabular::Feature num = Tabular::VALIGN_MIDDLE;
426         Tabular::Feature multi_num = Tabular::M_VALIGN_MIDDLE;
427
428         switch (v) {
429                 case TOP:
430                         num = Tabular::VALIGN_TOP;
431                         multi_num = Tabular::M_VALIGN_TOP;
432                         break;
433                 case MIDDLE:
434                         num = Tabular::VALIGN_MIDDLE;
435                         multi_num = Tabular::M_VALIGN_MIDDLE;
436                         break;
437                 case BOTTOM:
438                         num = Tabular::VALIGN_BOTTOM;
439                         multi_num = Tabular::M_VALIGN_BOTTOM;
440                         break;
441         }
442         if (multicolumnCB->isChecked() || multirowCB->isChecked())
443                 setParam(param_str, multi_num);
444         else
445                 setParam(param_str, num);
446 }
447
448
449 void GuiTabular::setTableAlignment(string & param_str) const
450 {
451         int const align = TableAlignCO->currentIndex();
452         switch (align) {
453                 case 0: setParam(param_str, Tabular::TABULAR_VALIGN_TOP);
454                         break;
455                 case 1: setParam(param_str, Tabular::TABULAR_VALIGN_MIDDLE);
456                         break;
457                 case 2: setParam(param_str, Tabular::TABULAR_VALIGN_BOTTOM);
458                         break;
459         }
460 }
461
462
463 docstring GuiTabular::dialogToParams() const
464 {
465         string param_str = "tabular";
466
467         // table width
468         string tabwidth = widgetsToLength(tabularWidthED, tabularWidthUnitLC);
469         if (tabwidth.empty())
470                 tabwidth = "0pt";
471         setParam(param_str, Tabular::SET_TABULAR_WIDTH, tabwidth);
472
473         // apply the fixed width values
474         // this must be done before applying the column alignment
475         // because its value influences the alignment of multirow cells
476         string width = widgetsToLength(columnWidthED, columnWidthUnitLC);
477         if (width.empty() || columnTypeCO->currentIndex() != 2)
478                 width = "0pt";
479         if (multicolumnCB->isChecked())
480                 setParam(param_str, Tabular::SET_MPWIDTH, width);
481         else
482                 setParam(param_str, Tabular::SET_PWIDTH, width);
483
484         bool const varwidth = specialAlignmentED->text().isEmpty()
485                         && columnTypeCO->currentIndex() == 1;
486         if (varwidth)
487                 setParam(param_str, Tabular::TOGGLE_VARWIDTH_COLUMN, "on");
488         else
489                 setParam(param_str, Tabular::TOGGLE_VARWIDTH_COLUMN, "off");
490
491         // apply the column alignment
492         // multirows inherit the alignment from the column; if a column width
493         // is set, multirows are always left-aligned so that in this case
494         // its alignment must not be applied (see bug #8084)
495         if (!(multirowCB->isChecked() && width != "0pt"))
496                 setHAlign(param_str);
497
498         // SET_DECIMAL_POINT must come after setHAlign() (ALIGN_DECIMAL)
499         string decimal_point = fromqstr(decimalPointED->text());
500         if (decimal_point.empty())
501                 decimal_point = lyxrc.default_decimal_point;
502         setParam(param_str, Tabular::SET_DECIMAL_POINT, decimal_point);
503
504         setVAlign(param_str);
505         setTableAlignment(param_str);
506         //
507         if (booktabsRB->isChecked())
508                 setParam(param_str, Tabular::SET_BOOKTABS);
509         else
510                 setParam(param_str, Tabular::UNSET_BOOKTABS);
511
512         //
513         switch (topspaceCO->currentIndex()) {
514                 case 0:
515                         setParam(param_str, Tabular::SET_TOP_SPACE, "none");
516                         break;
517                 case 1:
518                         setParam(param_str, Tabular::SET_TOP_SPACE, "default");
519                         break;
520                 case 2:
521                         if (!topspaceED->text().isEmpty())
522                                 setParam(param_str, Tabular::SET_TOP_SPACE,
523                                          widgetsToLength(topspaceED, topspaceUnitLC));
524                         break;
525         }
526
527         //
528         switch (bottomspaceCO->currentIndex()) {
529                 case 0:
530                         setParam(param_str, Tabular::SET_BOTTOM_SPACE, "none");
531                         break;
532                 case 1:
533                         setParam(param_str, Tabular::SET_BOTTOM_SPACE, "default");
534                         break;
535                 case 2:
536                         if (!bottomspaceED->text().isEmpty())
537                                 setParam(param_str, Tabular::SET_BOTTOM_SPACE,
538                                         widgetsToLength(bottomspaceED,
539                                                         bottomspaceUnitLC));
540                         break;
541         }
542
543         //
544         switch (interlinespaceCO->currentIndex()) {
545                 case 0:
546                         setParam(param_str, Tabular::SET_INTERLINE_SPACE, "none");
547                         break;
548                 case 1:
549                         setParam(param_str, Tabular::SET_INTERLINE_SPACE, "default");
550                         break;
551                 case 2:
552                         if (!interlinespaceED->text().isEmpty())
553                                 setParam(param_str, Tabular::SET_INTERLINE_SPACE,
554                                         widgetsToLength(interlinespaceED,
555                                                         interlinespaceUnitLC));
556                         break;
557         }
558
559         //
560         if (borders->getTop() && borders->getBottom() && borders->getLeft()
561                 && borders->getRight())
562                 setParam(param_str, Tabular::SET_ALL_LINES);
563         else if (!borders->getTop() && !borders->getBottom() && !borders->getLeft()
564                 && !borders->getRight())
565                 setParam(param_str, Tabular::UNSET_ALL_LINES);
566         else {
567                 setParam(param_str, Tabular::SET_LINE_LEFT,
568                          borders->getLeft() ? "true" : "false");
569                 setParam(param_str, Tabular::SET_LINE_RIGHT,
570                          borders->getRight() ? "true" : "false");
571                 setParam(param_str, Tabular::SET_LINE_TOP,
572                          borders->getTop() ? "true" : "false");
573                 setParam(param_str, Tabular::SET_LINE_BOTTOM,
574                          borders->getBottom() ? "true" : "false");
575         }
576
577         // apply the special alignment
578         string special = fromqstr(specialAlignmentED->text());
579         if (special.empty())
580                 special = "none";
581         if (multicolumnCB->isChecked())
582                 setParam(param_str, Tabular::SET_SPECIAL_MULTICOLUMN, special);
583         else
584                 setParam(param_str, Tabular::SET_SPECIAL_COLUMN, special);
585
586         //
587         if (multicolumnCB->isChecked())
588                 setParam(param_str, Tabular::SET_MULTICOLUMN);
589         else
590                 setParam(param_str, Tabular::UNSET_MULTICOLUMN);
591
592         // apply the multirow offset
593         string mroffset = widgetsToLength(multirowOffsetED, multirowOffsetUnitLC);
594         if (mroffset.empty())
595                 mroffset = "0pt";
596         if (multirowCB->isChecked())
597                 setParam(param_str, Tabular::SET_MROFFSET, mroffset);
598         //
599         if (multirowCB->isChecked())
600                 setParam(param_str, Tabular::SET_MULTIROW);
601         else
602                 setParam(param_str, Tabular::UNSET_MULTIROW);
603         // store the table rotation angle
604         string const tabular_angle = convert<string>(rotateTabularAngleSB->value());
605         if (rotateTabularCB->isChecked())
606                 setParam(param_str, Tabular::SET_ROTATE_TABULAR, tabular_angle);
607         else
608                 setParam(param_str, Tabular::UNSET_ROTATE_TABULAR, tabular_angle);
609         // store the cell rotation angle
610         string const cell_angle = convert<string>(rotateCellAngleSB->value());
611         if (rotateCellCB->isChecked())
612                 setParam(param_str, Tabular::SET_ROTATE_CELL, cell_angle);
613         else
614                 setParam(param_str, Tabular::UNSET_ROTATE_CELL, cell_angle);
615         //
616         if (longTabularCB->isChecked())
617                 setParam(param_str, Tabular::SET_LONGTABULAR);
618         else
619                 setParam(param_str, Tabular::UNSET_LONGTABULAR);
620         //
621         if (newpageCB->isChecked())
622                 setParam(param_str, Tabular::SET_LTNEWPAGE);
623         else
624                 setParam(param_str, Tabular::UNSET_LTNEWPAGE);
625         //
626         if (captionStatusCB->isChecked())
627                 setParam(param_str, Tabular::SET_LTCAPTION);
628         else
629                 setParam(param_str, Tabular::UNSET_LTCAPTION);
630         //
631         if (headerStatusCB->isChecked())
632                 setParam(param_str, Tabular::SET_LTHEAD, "none");
633         else
634                 setParam(param_str, Tabular::UNSET_LTHEAD, "none");
635         //
636         if (headerBorderAboveCB->isChecked())
637                 setParam(param_str, Tabular::SET_LTHEAD, "dl_above");
638         else
639                 setParam(param_str, Tabular::UNSET_LTHEAD, "dl_above");
640         //
641         if (headerBorderBelowCB->isChecked())
642                 setParam(param_str, Tabular::SET_LTHEAD, "dl_below");
643         else
644                 setParam(param_str, Tabular::UNSET_LTHEAD, "dl_below");
645         if (firstheaderBorderAboveCB->isChecked())
646                 setParam(param_str, Tabular::SET_LTFIRSTHEAD, "dl_above");
647         else
648                 setParam(param_str, Tabular::UNSET_LTFIRSTHEAD, "dl_above");
649         if (firstheaderBorderBelowCB->isChecked())
650                 setParam(param_str, Tabular::SET_LTFIRSTHEAD, "dl_below");
651         else
652                 setParam(param_str, Tabular::UNSET_LTFIRSTHEAD, "dl_below");
653         if (firstheaderStatusCB->isChecked())
654                 setParam(param_str, Tabular::SET_LTFIRSTHEAD, "none");
655         else
656                 setParam(param_str, Tabular::UNSET_LTFIRSTHEAD, "none");
657         if (firstheaderNoContentsCB->isChecked())
658                 setParam(param_str, Tabular::SET_LTFIRSTHEAD, "empty");
659         else
660                 setParam(param_str, Tabular::UNSET_LTFIRSTHEAD, "empty");
661         if (footerStatusCB->isChecked())
662                 setParam(param_str, Tabular::SET_LTFOOT, "none");
663         else
664                 setParam(param_str, Tabular::UNSET_LTFOOT, "none");
665         if (footerBorderAboveCB->isChecked())
666                 setParam(param_str, Tabular::SET_LTFOOT, "dl_above");
667         else
668                 setParam(param_str, Tabular::UNSET_LTFOOT, "dl_above");
669         if (footerBorderBelowCB->isChecked())
670                 setParam(param_str, Tabular::SET_LTFOOT, "dl_below");
671         else
672                 setParam(param_str, Tabular::UNSET_LTFOOT, "dl_below");
673         if (lastfooterStatusCB->isChecked())
674                 setParam(param_str, Tabular::SET_LTLASTFOOT, "none");
675         else
676                 setParam(param_str, Tabular::UNSET_LTLASTFOOT, "none");
677         if (lastfooterBorderAboveCB->isChecked())
678                 setParam(param_str, Tabular::SET_LTLASTFOOT, "dl_above");
679         else
680                 setParam(param_str, Tabular::UNSET_LTLASTFOOT, "dl_above");
681         if (lastfooterBorderBelowCB->isChecked())
682                 setParam(param_str, Tabular::SET_LTLASTFOOT, "dl_below");
683         else
684                 setParam(param_str, Tabular::UNSET_LTLASTFOOT, "dl_below");
685         if (lastfooterNoContentsCB->isChecked())
686                 setParam(param_str, Tabular::SET_LTLASTFOOT, "empty");
687         else
688                 setParam(param_str, Tabular::UNSET_LTLASTFOOT, "empty");
689
690         if (leftRB->isChecked())
691                 setParam(param_str, Tabular::LONGTABULAR_ALIGN_LEFT);
692         else if (centerRB->isChecked())
693                 setParam(param_str, Tabular::LONGTABULAR_ALIGN_CENTER);
694         else if (rightRB->isChecked())
695                 setParam(param_str, Tabular::LONGTABULAR_ALIGN_RIGHT);
696
697         return from_utf8(param_str);
698 }
699
700
701 static Length getColumnPWidth(Tabular const & t, size_t cell)
702 {
703         return t.column_info[t.cellColumn(cell)].p_width;
704 }
705
706
707 static Length getMColumnPWidth(Tabular const & t, size_t cell)
708 {
709         if (t.isMultiColumn(cell) || t.isMultiRow(cell))
710                 return t.cellInfo(cell).p_width;
711         return Length();
712 }
713
714
715 static Length getMROffset(Tabular const & t, size_t cell)
716 {
717         if (t.isMultiRow(cell))
718                 return t.cellInfo(cell).mroffset;
719         return Length();
720 }
721
722
723 static docstring getAlignSpecial(Tabular const & t, size_t cell, int what)
724 {
725         if (what == Tabular::SET_SPECIAL_MULTICOLUMN)
726                 return t.cellInfo(cell).align_special;
727         return t.column_info[t.cellColumn(cell)].align_special;
728 }
729
730
731 void GuiTabular::paramsToDialog(Inset const * inset)
732 {
733         InsetTabular const * itab = static_cast<InsetTabular const *>(inset);
734         // Copy Tabular of current inset.
735         Tabular const & tabular = itab->tabular;
736
737         BufferView const * bv = guiApp->currentView()->currentBufferView();
738         size_t const cell = bv->cursor().idx();
739
740         Tabular::row_type const row = tabular.cellRow(cell);
741         Tabular::col_type const col = tabular.cellColumn(cell);
742
743         tabularRowED->setText(QString::number(row + 1));
744         tabularColumnED->setText(QString::number(col + 1));
745
746         bool const multicol = tabular.isMultiColumn(cell);
747         multicolumnCB->setChecked(multicol);
748
749         bool const multirow = tabular.isMultiRow(cell);
750         multirowCB->setChecked(multirow);
751
752         rotateCellCB->setChecked(tabular.getRotateCell(cell) != 0);
753         if (rotateCellCB->isChecked()) {
754                 if (tabular.getRotateCell(cell) != 0)
755                         rotateCellAngleSB->setValue(tabular.getRotateCell(cell));
756                 else
757                         rotateCellAngleSB->setValue(90);
758         }
759
760         longTabularCB->setChecked(tabular.is_long_tabular);
761
762         rotateTabularCB->setChecked(tabular.rotate != 0);
763         if (rotateTabularCB->isChecked()) {
764                 if (longTabularCB->isChecked())
765                         rotateTabularAngleSB->setValue(90);
766                 else
767                         rotateTabularAngleSB->setValue(tabular.rotate != 0 ? tabular.rotate : 90);
768         }
769
770         borders->setTop(tabular.topLine(cell));
771         borders->setBottom(tabular.bottomLine(cell));
772         borders->setLeft(tabular.leftLine(cell));
773         borders->setRight(tabular.rightLine(cell));
774         // repaint the setborder widget
775         borders->update();
776
777         Length::UNIT const default_unit = Length::defaultUnit();
778
779         ///////////////////////////////////
780         // Set width and alignment
781
782         Length const tabwidth = tabular.tabularWidth();
783         if (tabwidth.zero()
784             && !(tabularWidthED->hasFocus() && tabularWidthED->text() == "0"))
785                 tabularWidthED->clear();
786         else
787                 lengthToWidgets(tabularWidthED, tabularWidthUnitLC,
788                         tabwidth.asString(), default_unit);
789
790         Length pwidth;
791         docstring special;
792         if (multicol) {
793                 special = getAlignSpecial(tabular, cell,
794                         Tabular::SET_SPECIAL_MULTICOLUMN);
795                 pwidth = getMColumnPWidth(tabular, cell);
796         } else {
797                 special = getAlignSpecial(tabular, cell,
798                         Tabular::SET_SPECIAL_COLUMN);
799                 pwidth = getColumnPWidth(tabular, cell);
800         }
801         bool const varwidth = tabular.column_info[tabular.cellColumn(cell)].varwidth;
802         if (varwidth)
803                 columnTypeCO->setCurrentIndex(1);
804         string colwidth;
805         if (pwidth.zero()
806             && !(columnWidthED->hasFocus() && columnWidthED->text() == "0")) {
807                 columnWidthED->clear();
808                 if (!varwidth)
809                         columnTypeCO->setCurrentIndex(0);
810         } else {
811                 colwidth = pwidth.asString();
812                 lengthToWidgets(columnWidthED, columnWidthUnitLC,
813                         colwidth, default_unit);
814                 columnTypeCO->setCurrentIndex(2);
815         }
816         Length mroffset;
817         if (multirow)
818                 mroffset = getMROffset(tabular, cell);
819         string offset;
820         if (mroffset.zero()
821             && !(multirowOffsetED->hasFocus() && multirowOffsetED->text() == "0"))
822                 multirowOffsetED->clear();
823         else {
824                 offset = mroffset.asString();
825                 lengthToWidgets(multirowOffsetED, multirowOffsetUnitLC,
826                         offset, default_unit);
827         }
828         specialAlignmentED->setText(toqstr(special));
829         ///////////////////////////////////
830
831
832         borderDefaultRB->setChecked(!tabular.use_booktabs);
833         booktabsRB->setChecked(tabular.use_booktabs);
834
835         if (tabular.row_info[row].top_space.empty()
836             && !tabular.row_info[row].top_space_default) {
837                 topspaceCO->setCurrentIndex(0);
838         } else if (tabular.row_info[row].top_space_default) {
839                 topspaceCO->setCurrentIndex(1);
840         } else {
841                 topspaceCO->setCurrentIndex(2);
842                 lengthToWidgets(topspaceED,
843                                 topspaceUnitLC,
844                                 tabular.row_info[row].top_space.asString(),
845                                 default_unit);
846         }
847
848         if (tabular.row_info[row].bottom_space.empty()
849             && !tabular.row_info[row].bottom_space_default) {
850                 bottomspaceCO->setCurrentIndex(0);
851         } else if (tabular.row_info[row].bottom_space_default) {
852                 bottomspaceCO->setCurrentIndex(1);
853         } else {
854                 bottomspaceCO->setCurrentIndex(2);
855                 lengthToWidgets(bottomspaceED,
856                                 bottomspaceUnitLC,
857                                 tabular.row_info[row].bottom_space.asString(),
858                                 default_unit);
859         }
860
861         if (tabular.row_info[row].interline_space.empty()
862             && !tabular.row_info[row].interline_space_default) {
863                 interlinespaceCO->setCurrentIndex(0);
864         } else if (tabular.row_info[row].interline_space_default) {
865                 interlinespaceCO->setCurrentIndex(1);
866         } else {
867                 interlinespaceCO->setCurrentIndex(2);
868                 lengthToWidgets(interlinespaceED,
869                                 interlinespaceUnitLC,
870                                 tabular.row_info[row].interline_space.asString(),
871                                 default_unit);
872         }
873
874         hAlignCO->clear();
875         hAlignCO->addItem(qt_("Left"), toqstr("left"));
876         hAlignCO->addItem(qt_("Center"), toqstr("center"));
877         hAlignCO->addItem(qt_("Right"), toqstr("right"));
878         if (!multicol && !pwidth.zero())
879                 hAlignCO->addItem(qt_("Justified"), toqstr("justified"));
880         if (!multicol && !multirow)
881                 hAlignCO->addItem(qt_("At Decimal Separator"), toqstr("decimal"));
882
883         string align;
884         switch (tabular.getAlignment(cell)) {
885                 case LYX_ALIGN_LEFT:
886                         align = "left";
887                         break;
888                 case LYX_ALIGN_CENTER:
889                         align = "center";
890                         break;
891                 case LYX_ALIGN_RIGHT:
892                         align = "right";
893                         break;
894                 case LYX_ALIGN_BLOCK:
895                 {
896                         if (!multicol && !pwidth.zero())
897                                 align = "justified";
898                         break;
899                 }
900                 case LYX_ALIGN_DECIMAL:
901                 {
902                         if (!multicol && !multirow)
903                                 align = "decimal";
904                         break;
905                 }
906                 default:
907                         // we should never end up here
908                         break;
909         }
910         hAlignCO->setCurrentIndex(hAlignCO->findData(toqstr(align)));
911
912         //
913         QString decimal_point = toqstr(tabular.column_info[col].decimal_point);
914         if (decimal_point.isEmpty())
915                 decimal_point = toqstr(from_utf8(lyxrc.default_decimal_point));
916         decimalPointED->setText(decimal_point);
917
918         int valign = 0;
919         switch (tabular.getVAlignment(cell)) {
920         case Tabular::LYX_VALIGN_TOP:
921                 valign = 0;
922                 break;
923         case Tabular::LYX_VALIGN_MIDDLE:
924                 valign = 1;
925                 break;
926         case Tabular::LYX_VALIGN_BOTTOM:
927                 valign = 2;
928                 break;
929         default:
930                 valign = 0;
931                 break;
932         }
933         if (pwidth.zero())
934                 valign = 0;
935         vAlignCO->setCurrentIndex(valign);
936
937         int tableValign = 1;
938         switch (tabular.tabular_valignment) {
939         case Tabular::LYX_VALIGN_TOP:
940                 tableValign = 0;
941                 break;
942         case Tabular::LYX_VALIGN_MIDDLE:
943                 tableValign = 1;
944                 break;
945         case Tabular::LYX_VALIGN_BOTTOM:
946                 tableValign = 2;
947                 break;
948         default:
949                 tableValign = 0;
950                 break;
951         }
952         TableAlignCO->setCurrentIndex(tableValign);
953
954         if (!tabular.is_long_tabular) {
955                 headerStatusCB->setChecked(false);
956                 headerBorderAboveCB->setChecked(false);
957                 headerBorderBelowCB->setChecked(false);
958                 firstheaderStatusCB->setChecked(false);
959                 firstheaderBorderAboveCB->setChecked(false);
960                 firstheaderBorderBelowCB->setChecked(false);
961                 firstheaderNoContentsCB->setChecked(false);
962                 footerStatusCB->setChecked(false);
963                 footerBorderAboveCB->setChecked(false);
964                 footerBorderBelowCB->setChecked(false);
965                 lastfooterStatusCB->setChecked(false);
966                 lastfooterBorderAboveCB->setChecked(false);
967                 lastfooterBorderBelowCB->setChecked(false);
968                 lastfooterNoContentsCB->setChecked(false);
969                 newpageCB->setChecked(false);
970                 captionStatusCB->blockSignals(true);
971                 captionStatusCB->setChecked(false);
972                 captionStatusCB->blockSignals(false);
973                 checkEnabled();
974                 return;
975         } else {
976                 // longtables cannot have a vertical alignment
977                 TableAlignCO->setCurrentIndex(Tabular::LYX_VALIGN_MIDDLE);
978         }
979         switch (tabular.longtabular_alignment) {
980         case Tabular::LYX_LONGTABULAR_ALIGN_LEFT:
981                 leftRB->setChecked(true);
982                 break;
983         case Tabular::LYX_LONGTABULAR_ALIGN_CENTER:
984                 centerRB->setChecked(true);
985                 break;
986         case Tabular::LYX_LONGTABULAR_ALIGN_RIGHT:
987                 rightRB->setChecked(true);
988                 break;
989         default:
990                 centerRB->setChecked(true);
991                 break;
992         }
993         captionStatusCB->blockSignals(true);
994         captionStatusCB->setChecked(tabular.ltCaption(row));
995         captionStatusCB->blockSignals(false);
996
997         Tabular::ltType ltt;
998         bool use_empty;
999         bool row_set = tabular.getRowOfLTHead(row, ltt);
1000         headerStatusCB->setChecked(row_set);
1001         if (ltt.set) {
1002                 headerBorderAboveCB->setChecked(ltt.topDL);
1003                 headerBorderBelowCB->setChecked(ltt.bottomDL);
1004                 use_empty = true;
1005         } else {
1006                 headerBorderAboveCB->setChecked(false);
1007                 headerBorderBelowCB->setChecked(false);
1008                 firstheaderNoContentsCB->setChecked(false);
1009                 use_empty = false;
1010         }
1011
1012         row_set = tabular.getRowOfLTFirstHead(row, ltt);
1013         firstheaderStatusCB->setChecked(row_set);
1014         if (ltt.set && (!ltt.empty || !use_empty)) {
1015                 firstheaderBorderAboveCB->setChecked(ltt.topDL);
1016                 firstheaderBorderBelowCB->setChecked(ltt.bottomDL);
1017         } else {
1018                 firstheaderBorderAboveCB->setChecked(false);
1019                 firstheaderBorderBelowCB->setChecked(false);
1020         }
1021
1022         row_set = tabular.getRowOfLTFoot(row, ltt);
1023         footerStatusCB->setChecked(row_set);
1024         if (ltt.set) {
1025                 footerBorderAboveCB->setChecked(ltt.topDL);
1026                 footerBorderBelowCB->setChecked(ltt.bottomDL);
1027                 use_empty = true;
1028         } else {
1029                 footerBorderAboveCB->setChecked(false);
1030                 footerBorderBelowCB->setChecked(false);
1031                 lastfooterNoContentsCB->setChecked(false);
1032                 use_empty = false;
1033         }
1034
1035         row_set = tabular.getRowOfLTLastFoot(row, ltt);
1036         lastfooterStatusCB->setChecked(row_set);
1037         if (ltt.set && (!ltt.empty || !use_empty)) {
1038                 lastfooterBorderAboveCB->setChecked(ltt.topDL);
1039                 lastfooterBorderBelowCB->setChecked(ltt.bottomDL);
1040         } else {
1041                 lastfooterBorderAboveCB->setChecked(false);
1042                 lastfooterBorderBelowCB->setChecked(false);
1043         }
1044         newpageCB->setChecked(tabular.getLTNewPage(row));
1045
1046         // first header can only be suppressed when there is a header
1047         firstheader_suppressable_ = tabular.haveLTHead()
1048                         && !tabular.haveLTFirstHead();
1049         // last footer can only be suppressed when there is a footer
1050         lastfooter_suppressable_ = tabular.haveLTFoot()
1051                         && !tabular.haveLTLastFoot();
1052
1053         // after setting the features, check if they are enabled
1054         checkEnabled();
1055 }
1056
1057
1058 bool GuiTabular::checkWidgets(bool readonly) const
1059 {
1060         tabularRowED->setReadOnly(readonly);
1061         tabularColumnED->setReadOnly(readonly);
1062         tabularWidthED->setReadOnly(readonly);
1063         specialAlignmentED->setReadOnly(readonly);
1064         columnWidthED->setReadOnly(readonly);
1065         multirowOffsetED->setReadOnly(readonly);
1066         decimalPointED->setReadOnly(readonly);
1067
1068         if (readonly) {
1069                 multicolumnCB->setEnabled(false);
1070                 multirowCB->setEnabled(false);
1071                 rotateCellCB->setEnabled(false);
1072                 rotateCellAngleSB->setEnabled(false);
1073                 rotateTabularCB->setEnabled(false);
1074                 rotateTabularAngleSB->setEnabled(false);
1075                 longTabularCB->setEnabled(false);
1076                 borders->setEnabled(false);
1077                 tabularWidthUnitLC->setEnabled(false);
1078                 columnWidthUnitLC->setEnabled(false);
1079                 columnTypeCO->setEnabled(false);
1080                 multirowOffsetUnitLC->setEnabled(false);
1081                 setBordersGB->setEnabled(false);
1082                 allBordersGB->setEnabled(false);
1083                 borderStyleGB->setEnabled(false);
1084                 booktabsRB->setEnabled(false);
1085                 topspaceCO->setEnabled(false);
1086                 topspaceUnitLC->setEnabled(false);
1087                 bottomspaceCO->setEnabled(false);
1088                 bottomspaceUnitLC->setEnabled(false);
1089                 interlinespaceCO->setEnabled(false);
1090                 interlinespaceUnitLC->setEnabled(false);
1091                 hAlignCO->setEnabled(false);
1092                 vAlignCO->setEnabled(false);
1093                 TableAlignCO->setEnabled(false);
1094                 longtableGB->setEnabled(false);
1095                 alignmentGB->setEnabled(false);
1096         } else
1097                 enableWidgets();
1098
1099         return InsetParamsWidget::checkWidgets();
1100 }
1101
1102
1103 bool GuiTabular::funcEnabled(Tabular::Feature f) const
1104 {
1105         FuncRequest r(LFUN_INSET_MODIFY, "tabular for-dialog" + featureAsString(f));
1106         return getStatus(r).enabled();
1107 }
1108
1109
1110 } // namespace frontend
1111 } // namespace lyx
1112
1113 #include "moc_GuiTabular.cpp"