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