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