]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiTabular.cpp
91b68678a682101c8f44b729b7b4a475b35de334
[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  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiTabular.h"
16
17 #include "GuiSetBorder.h"
18 #include "GuiView.h"
19 #include "LengthCombo.h"
20 #include "qt_helpers.h"
21 #include "Validator.h"
22
23 #include "BufferView.h"
24 #include "Cursor.h"
25 #include "FuncRequest.h"
26 #include "FuncStatus.h"
27 #include "LyXFunc.h"
28
29 #include "insets/InsetTabular.h"
30
31 #include <QCheckBox>
32 #include <QPushButton>
33 #include <QRadioButton>
34 #include <QLineEdit>
35
36 using namespace std;
37
38 namespace lyx {
39 namespace frontend {
40
41 GuiTabular::GuiTabular(GuiView & lv)
42         : GuiDialog(lv, "tabular", qt_("Table Settings")),
43         // tabular_ is initialised at dialog construction in initialiseParams()
44         tabular_(*lv.buffer(), 0, 0)
45 {
46         active_cell_ = Tabular::npos;
47
48         setupUi(this);
49
50         widthED->setValidator(unsignedLengthValidator(widthED));
51         topspaceED->setValidator(new LengthValidator(topspaceED));
52         bottomspaceED->setValidator(new LengthValidator(bottomspaceED));
53         interlinespaceED->setValidator(new LengthValidator(interlinespaceED));
54
55         connect(topspaceED, SIGNAL(returnPressed()),
56                 this, SLOT(topspace_changed()));
57         connect(topspaceUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
58                 this, SLOT(topspace_changed()));
59         connect(topspaceCO, SIGNAL(activated(int)),
60                 this, SLOT(topspace_changed()));
61         connect(bottomspaceED, SIGNAL(returnPressed()),
62                 this, SLOT(bottomspace_changed()));
63         connect(bottomspaceUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
64                 this, SLOT(bottomspace_changed()));
65         connect(bottomspaceCO, SIGNAL(activated(int)),
66                 this, SLOT(bottomspace_changed()));
67         connect(interlinespaceED, SIGNAL(returnPressed()),
68                 this, SLOT(interlinespace_changed()));
69         connect(interlinespaceUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
70                 this, SLOT(interlinespace_changed()));
71         connect(interlinespaceCO, SIGNAL(activated(int)),
72                 this, SLOT(interlinespace_changed()));
73         connect(booktabsRB, SIGNAL(clicked(bool)),
74                 this, SLOT(booktabsChanged(bool)));
75         connect(borderDefaultRB, SIGNAL(clicked(bool)),
76                 this, SLOT(booktabsChanged(bool)));
77         connect(borderSetPB, SIGNAL(clicked()),
78                 this, SLOT(borderSet_clicked()));
79         connect(borderUnsetPB, SIGNAL(clicked()), 
80                 this, SLOT(borderUnset_clicked()));
81         connect(longTabularCB, SIGNAL(toggled(bool)),
82                 longtableGB, SLOT(setEnabled(bool)));
83         connect(longTabularCB, SIGNAL(toggled(bool)),
84                 newpageCB, SLOT(setEnabled(bool)));
85         connect(longTabularCB, SIGNAL(toggled(bool)),
86                 alignmentGB, SLOT(setEnabled(bool)));
87         // longtables cannot have a vertical alignment
88         connect(longTabularCB, SIGNAL(toggled(bool)),
89                 TableAlignCB, SLOT(setDisabled(bool)));
90         connect(hAlignCB, SIGNAL(activated(int)),
91                 this, SLOT(hAlign_changed(int)));
92         connect(vAlignCB, SIGNAL(activated(int)),
93                 this, SLOT(vAlign_changed(int)));
94         connect(multicolumnCB, SIGNAL(clicked()),
95                 this, SLOT(multicolumn_clicked()));
96         connect(newpageCB, SIGNAL(clicked()),
97                 this, SLOT(ltNewpage_clicked()));
98         connect(headerStatusCB, SIGNAL(clicked()),
99                 this, SLOT(ltHeaderStatus_clicked()));
100         connect(headerBorderAboveCB, SIGNAL(clicked()),
101                 this, SLOT(ltHeaderBorderAbove_clicked()));
102         connect(headerBorderBelowCB, SIGNAL(clicked()),
103                 this, SLOT(ltHeaderBorderBelow_clicked()));
104         connect(firstheaderStatusCB, SIGNAL(clicked()),
105                 this, SLOT(ltFirstHeaderStatus_clicked()));
106         connect(firstheaderBorderAboveCB, SIGNAL(clicked()),
107                 this, SLOT(ltFirstHeaderBorderAbove_clicked()));
108         connect(firstheaderBorderBelowCB, SIGNAL(clicked()),
109                 this, SLOT(ltFirstHeaderBorderBelow_clicked()));
110         connect(firstheaderNoContentsCB, SIGNAL(clicked()),
111                 this, SLOT(ltFirstHeaderEmpty_clicked()));
112         connect(footerStatusCB, SIGNAL(clicked()),
113                 this, SLOT(ltFooterStatus_clicked()));
114         connect(footerBorderAboveCB, SIGNAL(clicked()),
115                 this, SLOT(ltFooterBorderAbove_clicked()));
116         connect(footerBorderBelowCB, SIGNAL(clicked()),
117                 this, SLOT(ltFooterBorderBelow_clicked()));
118         connect(lastfooterStatusCB, SIGNAL(clicked()),
119                 this, SLOT(ltLastFooterStatus_clicked()));
120         connect(lastfooterBorderAboveCB, SIGNAL(clicked()),
121                 this, SLOT(ltLastFooterBorderAbove_clicked()));
122         connect(lastfooterBorderBelowCB, SIGNAL(clicked()),
123                 this, SLOT(ltLastFooterBorderBelow_clicked()));
124         connect(lastfooterNoContentsCB, SIGNAL(clicked()),
125                 this, SLOT(ltLastFooterEmpty_clicked()));
126         connect(specialAlignmentED, SIGNAL(returnPressed()),
127                 this, SLOT(specialAlignment_changed()));
128         connect(widthED, SIGNAL(editingFinished()),
129                 this, SLOT(width_changed()));
130         connect(widthUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
131                 this, SLOT(width_changed()));
132         connect(closePB, SIGNAL(clicked()),
133                 this, SLOT(close_clicked()));
134         connect(borders, SIGNAL(topSet(bool)),
135                 this, SLOT(topBorder_changed()));
136         connect(borders, SIGNAL(bottomSet(bool)),
137                 this, SLOT(bottomBorder_changed()));
138         connect(borders, SIGNAL(rightSet(bool)),
139                 this, SLOT(rightBorder_changed()));
140         connect(borders, SIGNAL(leftSet(bool)),
141                 this, SLOT(leftBorder_changed()));
142         connect(rotateTabularCB, SIGNAL(clicked()),
143                 this, SLOT(rotateTabular()));
144         connect(rotateCellCB, SIGNAL(clicked()),
145                 this, SLOT(rotateCell()));
146         connect(TableAlignCB, SIGNAL(activated(int)),
147                 this, SLOT(tableAlignment_changed(int)));
148         connect(longTabularCB, SIGNAL(clicked()),
149                 this, SLOT(longTabular()));
150         connect(leftRB, SIGNAL(clicked()),
151                 this, SLOT(ltAlignment_clicked()));
152         connect(centerRB, SIGNAL(clicked()),
153                 this, SLOT(ltAlignment_clicked()));
154         connect(rightRB, SIGNAL(clicked()),
155                 this, SLOT(ltAlignment_clicked()));
156                 
157         bc().setPolicy(ButtonPolicy::IgnorantPolicy);
158         
159         bc().addReadOnly(topspaceED);
160         bc().addReadOnly(topspaceUnit);
161         bc().addReadOnly(topspaceCO);
162         bc().addReadOnly(bottomspaceED);
163         bc().addReadOnly(bottomspaceUnit);
164         bc().addReadOnly(bottomspaceCO);
165         bc().addReadOnly(interlinespaceED);
166         bc().addReadOnly(interlinespaceUnit);
167         bc().addReadOnly(interlinespaceCO);
168         bc().addReadOnly(borderDefaultRB);
169         bc().addReadOnly(booktabsRB);
170
171         bc().addReadOnly(multicolumnCB);
172         bc().addReadOnly(rotateCellCB);
173         bc().addReadOnly(rotateTabularCB);
174         bc().addReadOnly(specialAlignmentED);
175         bc().addReadOnly(widthED);
176         bc().addReadOnly(widthUnit);
177         bc().addReadOnly(hAlignCB);
178         bc().addReadOnly(vAlignCB);
179         bc().addReadOnly(TableAlignCB);
180         bc().addReadOnly(borderSetPB);
181         bc().addReadOnly(borderUnsetPB);
182         bc().addReadOnly(borders);
183         bc().addReadOnly(longTabularCB);
184         bc().addReadOnly(headerStatusCB);
185         bc().addReadOnly(headerBorderAboveCB);
186         bc().addReadOnly(headerBorderBelowCB);
187         bc().addReadOnly(firstheaderStatusCB);
188         bc().addReadOnly(firstheaderBorderAboveCB);
189         bc().addReadOnly(firstheaderBorderBelowCB);
190         bc().addReadOnly(firstheaderNoContentsCB);
191         bc().addReadOnly(footerStatusCB);
192         bc().addReadOnly(footerBorderAboveCB);
193         bc().addReadOnly(footerBorderBelowCB);
194         bc().addReadOnly(lastfooterStatusCB);
195         bc().addReadOnly(lastfooterBorderAboveCB);
196         bc().addReadOnly(lastfooterBorderBelowCB);
197         bc().addReadOnly(lastfooterNoContentsCB);
198         bc().addReadOnly(newpageCB);
199         bc().addReadOnly(leftRB);
200         bc().addReadOnly(centerRB);
201         bc().addReadOnly(rightRB);
202         
203         // initialize the length validator
204         bc().addCheckedLineEdit(widthED, fixedWidthColLA);
205         bc().addCheckedLineEdit(topspaceED, topspaceLA);
206         bc().addCheckedLineEdit(bottomspaceED, bottomspaceLA);
207         bc().addCheckedLineEdit(interlinespaceED, interlinespaceLA);
208 }
209
210
211 GuiTabular::~GuiTabular()
212 {
213 }
214
215
216 void GuiTabular::change_adaptor()
217 {
218         changed();
219 }
220
221
222 void GuiTabular::booktabsChanged(bool)
223 {
224         changed();
225         booktabs(booktabsRB->isChecked());
226         update_borders();
227 }
228
229
230 void GuiTabular::topspace_changed()
231 {
232         switch (topspaceCO->currentIndex()) {
233                 case 0: {
234                         set(Tabular::SET_TOP_SPACE, "");
235                         topspaceED->setEnabled(false);
236                         topspaceUnit->setEnabled(false);
237                         break;
238                 }
239                 case 1: {
240                         set(Tabular::SET_TOP_SPACE, "default");
241                         topspaceED->setEnabled(false);
242                         topspaceUnit->setEnabled(false);
243                         break;
244                 }
245                 case 2: {
246                         if (!topspaceED->text().isEmpty())
247                                 set(Tabular::SET_TOP_SPACE,
248                                         widgetsToLength(topspaceED,
249                                                         topspaceUnit));
250                         if (!bc().policy().isReadOnly()) {
251                                 topspaceED->setEnabled(true);
252                                 topspaceUnit->setEnabled(true);
253                         }
254                         break;
255                 }
256         }
257         changed();
258 }
259
260
261 void GuiTabular::bottomspace_changed()
262 {
263         switch (bottomspaceCO->currentIndex()) {
264                 case 0: {
265                         set(Tabular::SET_BOTTOM_SPACE, "");
266                                 bottomspaceED->setEnabled(false);
267                                 bottomspaceUnit->setEnabled(false);
268                         break;
269                 }
270                 case 1: {
271                         set(Tabular::SET_BOTTOM_SPACE, "default");
272                         bottomspaceED->setEnabled(false);
273                         bottomspaceUnit->setEnabled(false);
274                         break;
275                 }
276                 case 2: {
277                         if (!bottomspaceED->text().isEmpty())
278                                 set(Tabular::SET_BOTTOM_SPACE,
279                                         widgetsToLength(bottomspaceED,
280                                                         bottomspaceUnit));
281                         if (!bc().policy().isReadOnly()) {
282                                 bottomspaceED->setEnabled(true);
283                                 bottomspaceUnit->setEnabled(true);
284                         }
285                         break;
286                 }
287         }
288         changed();
289 }
290
291
292 void GuiTabular::interlinespace_changed()
293 {
294         switch (interlinespaceCO->currentIndex()) {
295                 case 0: {
296                         set(Tabular::SET_INTERLINE_SPACE, "");
297                                 interlinespaceED->setEnabled(false);
298                                 interlinespaceUnit->setEnabled(false);
299                         break;
300                 }
301                 case 1: {
302                         set(Tabular::SET_INTERLINE_SPACE, "default");
303                         interlinespaceED->setEnabled(false);
304                         interlinespaceUnit->setEnabled(false);
305                         break;
306                 }
307                 case 2: {
308                         if (!interlinespaceED->text().isEmpty())
309                                 set(Tabular::SET_INTERLINE_SPACE,
310                                         widgetsToLength(interlinespaceED,
311                                                         interlinespaceUnit));
312                         if (!bc().policy().isReadOnly()) {
313                                 interlinespaceED->setEnabled(true);
314                                 interlinespaceUnit->setEnabled(true);
315                         }
316                         break;
317                 }
318         }
319         changed();
320 }
321
322
323 void GuiTabular::close_clicked()
324 {
325         closeGUI();
326         slotClose();
327 }
328
329
330 void GuiTabular::borderSet_clicked()
331 {
332         set(Tabular::SET_ALL_LINES);
333         update_borders();
334         changed();
335 }
336
337
338 void GuiTabular::borderUnset_clicked()
339 {
340         set(Tabular::UNSET_ALL_LINES);
341         update_borders();
342         changed();
343 }
344
345
346 void GuiTabular::leftBorder_changed()
347 {
348         set(Tabular::TOGGLE_LINE_LEFT);
349         changed();
350 }
351
352
353 void GuiTabular::rightBorder_changed()
354 {
355         set(Tabular::TOGGLE_LINE_RIGHT);
356         changed();
357 }
358
359
360 void GuiTabular::topBorder_changed()
361 {
362         set(Tabular::TOGGLE_LINE_TOP);
363         changed();
364 }
365
366
367 void GuiTabular::bottomBorder_changed()
368 {
369         set(Tabular::TOGGLE_LINE_BOTTOM);
370         changed();
371 }
372
373
374 void GuiTabular::specialAlignment_changed()
375 {
376         string special = fromqstr(specialAlignmentED->text());
377         setSpecial(special);
378         changed();
379 }
380
381
382 void GuiTabular::width_changed()
383 {
384         changed();
385         string const width = widgetsToLength(widthED, widthUnit);
386         setWidth(width);
387 }
388
389
390 void GuiTabular::multicolumn_clicked()
391 {
392         toggleMultiColumn();
393         changed();
394 }
395
396
397 void GuiTabular::rotateTabular()
398 {
399         rotateTabular(rotateTabularCB->isChecked());
400         changed();
401 }
402
403
404 void GuiTabular::rotateCell()
405 {
406         rotateCell(rotateCellCB->isChecked());
407         changed();
408 }
409
410
411 void GuiTabular::hAlign_changed(int align)
412 {
413         GuiTabular::HALIGN h = GuiTabular::LEFT;
414
415         switch (align) {
416                 case 0: h = GuiTabular::LEFT; break;
417                 case 1: h = GuiTabular::CENTER; break;
418                 case 2: h = GuiTabular::RIGHT; break;
419                 case 3: h = GuiTabular::BLOCK; break;
420         }
421
422         halign(h);
423 }
424
425
426 void GuiTabular::vAlign_changed(int align)
427 {
428         GuiTabular::VALIGN v = GuiTabular::TOP;
429
430         switch (align) {
431                 case 0: v = GuiTabular::TOP; break;
432                 case 1: v = GuiTabular::MIDDLE; break;
433                 case 2: v = GuiTabular::BOTTOM; break;
434         }
435
436         valign(v);
437 }
438
439
440 void GuiTabular::tableAlignment_changed(int align)
441 {
442         switch (align) {
443                 case 0: set(Tabular::TABULAR_VALIGN_TOP);
444                         break;
445                 case 1: set(Tabular::TABULAR_VALIGN_MIDDLE);
446                         break;
447                 case 2: set(Tabular::TABULAR_VALIGN_BOTTOM);
448                         break;
449         }
450 }
451
452
453 void GuiTabular::longTabular()
454 {
455         longTabular(longTabularCB->isChecked());
456         changed();
457 }
458
459
460 void GuiTabular::ltNewpage_clicked()
461 {
462         set(Tabular::SET_LTNEWPAGE);
463         changed();
464 }
465
466
467 void GuiTabular::on_captionStatusCB_toggled()
468 {
469         set(Tabular::TOGGLE_LTCAPTION);
470         changed();
471 }
472
473
474 void GuiTabular::ltHeaderStatus_clicked()
475 {
476         bool enable = headerStatusCB->isChecked();
477         if (enable)
478                 set(Tabular::SET_LTHEAD, "");
479         else
480                 set(Tabular::UNSET_LTHEAD, "");
481         changed();
482 }
483
484
485 void GuiTabular::ltHeaderBorderAbove_clicked()
486 {
487         if (headerBorderAboveCB->isChecked())
488                 set(Tabular::SET_LTHEAD, "dl_above");
489         else
490                 set(Tabular::UNSET_LTHEAD, "dl_above");
491         changed();
492 }
493
494
495 void GuiTabular::ltHeaderBorderBelow_clicked()
496 {
497         if (headerBorderBelowCB->isChecked())
498                 set(Tabular::SET_LTHEAD, "dl_below");
499         else
500                 set(Tabular::UNSET_LTHEAD, "dl_below");
501         changed();
502 }
503
504
505 void GuiTabular::ltFirstHeaderBorderAbove_clicked()
506 {
507         if (firstheaderBorderAboveCB->isChecked())
508                 set(Tabular::SET_LTFIRSTHEAD, "dl_above");
509         else
510                 set(Tabular::UNSET_LTFIRSTHEAD, "dl_above");
511         changed();
512 }
513
514
515 void GuiTabular::ltFirstHeaderBorderBelow_clicked()
516 {
517         if (firstheaderBorderBelowCB->isChecked())
518                 set(Tabular::SET_LTFIRSTHEAD, "dl_below");
519         else
520                 set(Tabular::UNSET_LTFIRSTHEAD, "dl_below");
521         changed();
522 }
523
524
525 void GuiTabular::ltFirstHeaderStatus_clicked()
526 {
527         bool enable = firstheaderStatusCB->isChecked();
528         if (enable)
529                 set(Tabular::SET_LTFIRSTHEAD, "");
530         else
531                 set(Tabular::UNSET_LTFIRSTHEAD, "");
532         changed();
533 }
534
535
536 void GuiTabular::ltFirstHeaderEmpty_clicked()
537 {
538         bool enable = firstheaderNoContentsCB->isChecked();
539         if (enable)
540                 set(Tabular::SET_LTFIRSTHEAD, "empty");
541         else
542                 set(Tabular::UNSET_LTFIRSTHEAD, "empty");
543         changed();
544 }
545
546
547 void GuiTabular::ltFooterStatus_clicked()
548 {
549         bool enable = footerStatusCB->isChecked();
550         if (enable)
551                 set(Tabular::SET_LTFOOT, "");
552         else
553                 set(Tabular::UNSET_LTFOOT, "");
554         changed();
555 }
556
557
558 void GuiTabular::ltFooterBorderAbove_clicked()
559 {
560         if (footerBorderAboveCB->isChecked())
561                 set(Tabular::SET_LTFOOT, "dl_above");
562         else
563                 set(Tabular::UNSET_LTFOOT, "dl_above");
564         changed();
565 }
566
567
568 void GuiTabular::ltFooterBorderBelow_clicked()
569 {
570         if (footerBorderBelowCB->isChecked())
571                 set(Tabular::SET_LTFOOT, "dl_below");
572         else
573                 set(Tabular::UNSET_LTFOOT, "dl_below");
574         changed();
575 }
576
577
578 void GuiTabular::ltLastFooterStatus_clicked()
579 {
580         bool enable = lastfooterStatusCB->isChecked();
581         if (enable)
582                 set(Tabular::SET_LTLASTFOOT, "");
583         else
584                 set(Tabular::UNSET_LTLASTFOOT, "");
585         changed();
586 }
587
588
589 void GuiTabular::ltLastFooterBorderAbove_clicked()
590 {
591         if (lastfooterBorderAboveCB->isChecked())
592                 set(Tabular::SET_LTLASTFOOT, "dl_above");
593         else
594                 set(Tabular::UNSET_LTLASTFOOT, "dl_above");
595         changed();
596 }
597
598
599 void GuiTabular::ltLastFooterBorderBelow_clicked()
600 {
601         if (lastfooterBorderBelowCB->isChecked())
602                 set(Tabular::SET_LTLASTFOOT, "dl_below");
603         else
604                 set(Tabular::UNSET_LTLASTFOOT, "dl_below");
605         changed();
606 }
607
608
609 void GuiTabular::ltLastFooterEmpty_clicked()
610 {
611         bool enable = lastfooterNoContentsCB->isChecked();
612         if (enable)
613                 set(Tabular::SET_LTLASTFOOT, "empty");
614         else
615                 set(Tabular::UNSET_LTLASTFOOT, "empty");
616         changed();
617 }
618
619
620 void GuiTabular::ltAlignment_clicked()
621 {
622         if (leftRB->isChecked())
623                 set(Tabular::LONGTABULAR_ALIGN_LEFT);
624         else if (centerRB->isChecked())
625                 set(Tabular::LONGTABULAR_ALIGN_CENTER);
626         else if (rightRB->isChecked())
627                 set(Tabular::LONGTABULAR_ALIGN_RIGHT);
628         changed();
629 }
630
631
632 void GuiTabular::update_borders()
633 {
634         Tabular::idx_type const cell = getActiveCell();
635         borders->setTop(tabular_.topLine(cell));
636         borders->setBottom(tabular_.bottomLine(cell));
637         borders->setLeft(tabular_.leftLine(cell));
638         borders->setRight(tabular_.rightLine(cell));
639         // repaint the setborder widget
640         borders->update();
641 }
642
643
644 namespace {
645
646 Length getColumnPWidth(Tabular const & t, size_t cell)
647 {
648         return t.column_info[t.cellColumn(cell)].p_width;
649 }
650
651
652 Length getMColumnPWidth(Tabular const & t, size_t cell)
653 {
654         if (t.isMultiColumn(cell))
655                 return t.cellInfo(cell).p_width;
656         return Length();
657 }
658
659
660 docstring getAlignSpecial(Tabular const & t, size_t cell, int what)
661 {
662         if (what == Tabular::SET_SPECIAL_MULTI)
663                 return t.cellInfo(cell).align_special;
664         return t.column_info[t.cellColumn(cell)].align_special;
665 }
666
667 }
668
669
670
671 void GuiTabular::updateContents()
672 {
673         initialiseParams(string());
674
675         size_t const cell = getActiveCell();
676
677         Tabular::row_type const row = tabular_.cellRow(cell);
678         Tabular::col_type const col = tabular_.cellColumn(cell);
679
680         tabularRowED->setText(QString::number(row + 1));
681         tabularColumnED->setText(QString::number(col + 1));
682
683         bool const multicol(tabular_.isMultiColumn(cell));
684
685         multicolumnCB->setChecked(multicol);
686
687         rotateCellCB->setChecked(tabular_.getRotateCell(cell));
688         rotateTabularCB->setChecked(tabular_.rotate);
689
690         longTabularCB->setChecked(tabular_.is_long_tabular);
691
692         update_borders();
693
694         Length pwidth;
695         docstring special;
696
697         if (multicol) {
698                 special = getAlignSpecial(tabular_, cell,
699                         Tabular::SET_SPECIAL_MULTI);
700                 pwidth = getMColumnPWidth(tabular_, cell);
701         } else {
702                 special = getAlignSpecial(tabular_, cell,
703                         Tabular::SET_SPECIAL_COLUMN);
704                 pwidth = getColumnPWidth(tabular_, cell);
705         }
706
707         specialAlignmentED->setText(toqstr(special));
708
709         bool const isReadonly = bc().policy().isReadOnly();
710         specialAlignmentED->setEnabled(!isReadonly);
711
712         Length::UNIT const default_unit = Length::defaultUnit();
713
714         borderDefaultRB->setChecked(!tabular_.use_booktabs);
715         booktabsRB->setChecked(tabular_.use_booktabs);
716
717         if (tabular_.row_info[row].top_space.empty()
718             && !tabular_.row_info[row].top_space_default) {
719                 topspaceCO->setCurrentIndex(0);
720         } else if (tabular_.row_info[row].top_space_default) {
721                 topspaceCO->setCurrentIndex(1);
722         } else {
723                 topspaceCO->setCurrentIndex(2);
724                 lengthToWidgets(topspaceED,
725                                 topspaceUnit,
726                                 tabular_.row_info[row].top_space.asString(),
727                                 default_unit);
728         }
729         topspaceED->setEnabled(!isReadonly
730                 && (topspaceCO->currentIndex() == 2));
731         topspaceUnit->setEnabled(!isReadonly
732                 && (topspaceCO->currentIndex() == 2));
733         topspaceCO->setEnabled(!isReadonly);
734
735         if (tabular_.row_info[row].bottom_space.empty()
736             && !tabular_.row_info[row].bottom_space_default) {
737                 bottomspaceCO->setCurrentIndex(0);
738         } else if (tabular_.row_info[row].bottom_space_default) {
739                 bottomspaceCO->setCurrentIndex(1);
740         } else {
741                 bottomspaceCO->setCurrentIndex(2);
742                 lengthToWidgets(bottomspaceED,
743                                 bottomspaceUnit,
744                                 tabular_.row_info[row].bottom_space.asString(),
745                                 default_unit);
746         }
747         bottomspaceED->setEnabled(!isReadonly
748                 && (bottomspaceCO->currentIndex() == 2));
749         bottomspaceUnit->setEnabled(!isReadonly
750                 && (bottomspaceCO->currentIndex() == 2));
751         bottomspaceCO->setEnabled(!isReadonly);
752
753         if (tabular_.row_info[row].interline_space.empty()
754             && !tabular_.row_info[row].interline_space_default) {
755                 interlinespaceCO->setCurrentIndex(0);
756         } else if (tabular_.row_info[row].interline_space_default) {
757                 interlinespaceCO->setCurrentIndex(1);
758         } else {
759                 interlinespaceCO->setCurrentIndex(2);
760                 lengthToWidgets(interlinespaceED,
761                                 interlinespaceUnit,
762                                 tabular_.row_info[row].interline_space.asString(),
763                                 default_unit);
764         }
765         interlinespaceED->setEnabled(!isReadonly
766                 && (interlinespaceCO->currentIndex() == 2));
767         interlinespaceUnit->setEnabled(!isReadonly
768                 && (interlinespaceCO->currentIndex() == 2));
769         interlinespaceCO->setEnabled(!isReadonly);
770
771         string colwidth;
772         if (!pwidth.zero())
773                 colwidth = pwidth.asString();
774         lengthToWidgets(widthED, widthUnit,
775                 colwidth, default_unit);
776
777         widthED->setEnabled(!isReadonly);
778         widthUnit->setEnabled(!isReadonly);
779
780         hAlignCB->clear();
781         hAlignCB->addItem(qt_("Left"));
782         hAlignCB->addItem(qt_("Center"));
783         hAlignCB->addItem(qt_("Right"));
784         if (!multicol && !pwidth.zero())
785                 hAlignCB->addItem(qt_("Justified"));
786
787         int align = 0;
788         switch (tabular_.getAlignment(cell)) {
789         case LYX_ALIGN_LEFT:
790                 align = 0;
791                 break;
792         case LYX_ALIGN_CENTER:
793                 align = 1;
794                 break;
795         case LYX_ALIGN_RIGHT:
796                 align = 2;
797                 break;
798         case LYX_ALIGN_BLOCK:
799         {
800                 if (!multicol && !pwidth.zero())
801                         align = 3;
802                 break;
803         }
804         default:
805                 align = 0;
806                 break;
807         }
808         hAlignCB->setCurrentIndex(align);
809
810         int valign = 0;
811         switch (tabular_.getVAlignment(cell)) {
812         case Tabular::LYX_VALIGN_TOP:
813                 valign = 0;
814                 break;
815         case Tabular::LYX_VALIGN_MIDDLE:
816                 valign = 1;
817                 break;
818         case Tabular::LYX_VALIGN_BOTTOM:
819                 valign = 2;
820                 break;
821         default:
822                 valign = 0;
823                 break;
824         }
825         if (pwidth.zero())
826                 valign = 0;
827         vAlignCB->setCurrentIndex(valign);
828
829         hAlignCB->setEnabled(true);
830         vAlignCB->setEnabled(!pwidth.zero());
831
832         int tableValign = 1;
833         switch (tabular_.tabular_valignment) {
834         case Tabular::LYX_VALIGN_TOP:
835                 tableValign = 0;
836                 break;
837         case Tabular::LYX_VALIGN_MIDDLE:
838                 tableValign = 1;
839                 break;
840         case Tabular::LYX_VALIGN_BOTTOM:
841                 tableValign = 2;
842                 break;
843         default:
844                 tableValign = 0;
845                 break;
846         }
847         TableAlignCB->setCurrentIndex(tableValign);
848
849         if (!tabular_.is_long_tabular) {
850                 headerStatusCB->setChecked(false);
851                 headerBorderAboveCB->setChecked(false);
852                 headerBorderBelowCB->setChecked(false);
853                 firstheaderStatusCB->setChecked(false);
854                 firstheaderBorderAboveCB->setChecked(false);
855                 firstheaderBorderBelowCB->setChecked(false);
856                 firstheaderNoContentsCB->setChecked(false);
857                 footerStatusCB->setChecked(false);
858                 footerBorderAboveCB->setChecked(false);
859                 footerBorderBelowCB->setChecked(false);
860                 lastfooterStatusCB->setChecked(false);
861                 lastfooterBorderAboveCB->setChecked(false);
862                 lastfooterBorderBelowCB->setChecked(false);
863                 lastfooterNoContentsCB->setChecked(false);
864                 newpageCB->setChecked(false);
865                 newpageCB->setEnabled(false);
866                 captionStatusCB->blockSignals(true);
867                 captionStatusCB->setChecked(false);
868                 captionStatusCB->blockSignals(false);
869                 return;
870         } else
871                 // longtables cannot have a vertical alignment
872                 TableAlignCB->setCurrentIndex(Tabular::LYX_VALIGN_MIDDLE);
873
874         switch (tabular_.longtabular_alignment) {
875         case Tabular::LYX_LONGTABULAR_ALIGN_LEFT:
876                 leftRB->setChecked(true);
877                 break;
878         case Tabular::LYX_LONGTABULAR_ALIGN_CENTER:
879                 centerRB->setChecked(true);
880                 break;
881         case Tabular::LYX_LONGTABULAR_ALIGN_RIGHT:
882                 rightRB->setChecked(true);
883                 break;
884         default:
885                 centerRB->setChecked(true);
886                 break;
887         }
888         captionStatusCB->blockSignals(true);
889         captionStatusCB->setChecked(tabular_.ltCaption(row));
890         captionStatusCB->blockSignals(false);
891
892         // FIXME: shouldn't this be handled by GuiDialog?
893         // FIXME: Some of them should be handled directly in TabularUI.ui
894         firstheaderBorderAboveCB->setEnabled(
895                 funcEnabled(Tabular::SET_LTFIRSTHEAD));
896         firstheaderBorderBelowCB->setEnabled(
897                 funcEnabled(Tabular::SET_LTFIRSTHEAD));
898         // first header can only be suppressed when there is a header
899         firstheaderNoContentsCB->setEnabled(tabular_.haveLTHead()
900                 && !tabular_.haveLTFirstHead());
901
902         //firstheaderStatusCB->setEnabled(
903         //      !firstheaderNoContentsCB->isChecked());
904         headerBorderAboveCB->setEnabled(funcEnabled(Tabular::SET_LTHEAD));
905         headerBorderBelowCB->setEnabled(funcEnabled(Tabular::SET_LTHEAD));
906         headerStatusCB->setEnabled(funcEnabled(Tabular::SET_LTHEAD));
907
908         footerBorderAboveCB->setEnabled(funcEnabled(Tabular::SET_LTFOOT));
909         footerBorderBelowCB->setEnabled(funcEnabled(Tabular::SET_LTFOOT));
910         footerStatusCB->setEnabled(funcEnabled(Tabular::SET_LTFOOT));
911
912         lastfooterBorderAboveCB->setEnabled(
913                 funcEnabled(Tabular::SET_LTLASTFOOT));
914         lastfooterBorderBelowCB->setEnabled(
915                 funcEnabled(Tabular::SET_LTLASTFOOT));
916         // last footer can only be suppressed when there is a footer
917         lastfooterNoContentsCB->setEnabled(tabular_.haveLTFoot()
918                 && !tabular_.haveLTLastFoot());
919
920         captionStatusCB->setEnabled(
921                 funcEnabled(Tabular::TOGGLE_LTCAPTION));
922         // When a row is set as longtable caption, it must not be allowed
923         // to unset that this row is a multicolumn.
924         multicolumnCB->setEnabled(funcEnabled(Tabular::MULTICOLUMN));
925
926         Tabular::ltType ltt;
927         bool use_empty;
928         bool row_set = tabular_.getRowOfLTHead(row, ltt);
929         headerStatusCB->setChecked(row_set);
930         if (ltt.set) {
931                 headerBorderAboveCB->setChecked(ltt.topDL);
932                 headerBorderBelowCB->setChecked(ltt.bottomDL);
933                 use_empty = true;
934         } else {
935                 headerBorderAboveCB->setChecked(false);
936                 headerBorderBelowCB->setChecked(false);
937                 headerBorderAboveCB->setEnabled(false);
938                 headerBorderBelowCB->setEnabled(false);
939                 firstheaderNoContentsCB->setChecked(false);
940                 firstheaderNoContentsCB->setEnabled(false);
941                 use_empty = false;
942         }
943
944         row_set = tabular_.getRowOfLTFirstHead(row, ltt);
945         // check if setting a first header is allowed
946         // additionally check firstheaderNoContentsCB because when this is
947         // the case a first header makes no sense
948         firstheaderStatusCB->setEnabled(
949                 funcEnabled(Tabular::SET_LTFIRSTHEAD)
950                 && !firstheaderNoContentsCB->isChecked());
951         firstheaderStatusCB->setChecked(row_set);
952         if (ltt.set && (!ltt.empty || !use_empty)) {
953                 firstheaderBorderAboveCB->setChecked(ltt.topDL);
954                 firstheaderBorderBelowCB->setChecked(ltt.bottomDL);
955         } else {
956                 firstheaderBorderAboveCB->setEnabled(false);
957                 firstheaderBorderBelowCB->setEnabled(false);
958                 firstheaderBorderAboveCB->setChecked(false);
959                 firstheaderBorderBelowCB->setChecked(false);
960                 if (use_empty) {
961                         if (ltt.empty)
962                                 firstheaderStatusCB->setEnabled(false);
963                 }
964         }
965
966         row_set = tabular_.getRowOfLTFoot(row, ltt);
967         footerStatusCB->setChecked(row_set);
968         if (ltt.set) {
969                 footerBorderAboveCB->setChecked(ltt.topDL);
970                 footerBorderBelowCB->setChecked(ltt.bottomDL);
971                 use_empty = true;
972         } else {
973                 footerBorderAboveCB->setChecked(false);
974                 footerBorderBelowCB->setChecked(false);
975                 footerBorderAboveCB->setEnabled(false);
976                 footerBorderBelowCB->setEnabled(false);
977                 lastfooterNoContentsCB->setChecked(false);
978                 lastfooterNoContentsCB->setEnabled(false);
979                 use_empty = false;
980         }
981
982         row_set = tabular_.getRowOfLTLastFoot(row, ltt);
983         // check if setting a last footer is allowed
984         // additionally check lastfooterNoContentsCB because when this is
985         // the case a last footer makes no sense
986         lastfooterStatusCB->setEnabled(
987                 funcEnabled(Tabular::SET_LTLASTFOOT)
988                 && !lastfooterNoContentsCB->isChecked());
989         lastfooterStatusCB->setChecked(row_set);
990         if (ltt.set && (!ltt.empty || !use_empty)) {
991                 lastfooterBorderAboveCB->setChecked(ltt.topDL);
992                 lastfooterBorderBelowCB->setChecked(ltt.bottomDL);
993         } else {
994                 lastfooterBorderAboveCB->setEnabled(false);
995                 lastfooterBorderBelowCB->setEnabled(false);
996                 lastfooterBorderAboveCB->setChecked(false);
997                 lastfooterBorderBelowCB->setChecked(false);
998                 if (use_empty) {
999                         if (ltt.empty)
1000                                 lastfooterStatusCB->setEnabled(false);
1001                 }
1002         }
1003         newpageCB->setChecked(tabular_.getLTNewPage(row));
1004 }
1005
1006
1007 void GuiTabular::closeGUI()
1008 {
1009         // ugly hack to auto-apply the stuff that hasn't been
1010         // yet. don't let this continue to exist ...
1011
1012         // Subtle here, we must /not/ apply any changes and
1013         // then refer to tabular, as it will have been freed
1014         // since the changes update the actual tabular_
1015         //
1016         // apply the fixed width values
1017         size_t const cell = getActiveCell();
1018         bool const multicol = tabular_.isMultiColumn(cell);
1019         string width = widgetsToLength(widthED, widthUnit);
1020         string width2;
1021
1022         Length llen = getColumnPWidth(tabular_, cell);
1023         Length llenMulti = getMColumnPWidth(tabular_, cell);
1024
1025         if (multicol && !llenMulti.zero())
1026                 width2 = llenMulti.asString();
1027         else if (!multicol && !llen.zero())
1028                 width2 = llen.asString();
1029
1030         // apply the special alignment
1031         docstring const sa1 = qstring_to_ucs4(specialAlignmentED->text());
1032         docstring sa2;
1033
1034         if (multicol)
1035                 sa2 = getAlignSpecial(tabular_, cell,
1036                         Tabular::SET_SPECIAL_MULTI);
1037         else
1038                 sa2 = getAlignSpecial(tabular_, cell,
1039                         Tabular::SET_SPECIAL_COLUMN);
1040
1041         if (sa1 != sa2) {
1042                 if (multicol)
1043                         set(Tabular::SET_SPECIAL_MULTI, to_utf8(sa1));
1044                 else
1045                         set(Tabular::SET_SPECIAL_COLUMN, to_utf8(sa1));
1046         }
1047
1048         if (width != width2) {
1049                 if (multicol)
1050                         set(Tabular::SET_MPWIDTH, width);
1051                 else
1052                         set(Tabular::SET_PWIDTH, width);
1053         }
1054
1055         /* DO WE NEED THIS?
1056         switch (topspaceCO->currentIndex()) {
1057                 case 0:
1058                         set(Tabular::SET_TOP_SPACE, "");
1059                         break;
1060                 case 1:
1061                         set(Tabular::SET_TOP_SPACE, "default");
1062                         break;
1063                 case 2:
1064                         set(Tabular::SET_TOP_SPACE,
1065                                 widgetsToLength(topspaceED,
1066                                         topspaceUnit));
1067                         break;
1068         }
1069
1070         switch (bottomspaceCO->currentIndex()) {
1071                 case 0:
1072                         set(Tabular::SET_BOTTOM_SPACE, "");
1073                         break;
1074                 case 1:
1075                         set(Tabular::SET_BOTTOM_SPACE, "default");
1076                         break;
1077                 case 2:
1078                         set(Tabular::SET_BOTTOM_SPACE,
1079                                 widgetsToLength(bottomspaceED,
1080                                         bottomspaceUnit));
1081                         break;
1082         }
1083
1084         switch (interlinespaceCO->currentIndex()) {
1085                 case 0:
1086                         set(Tabular::SET_INTERLINE_SPACE, "");
1087                         break;
1088                 case 1:
1089                         set(Tabular::SET_INTERLINE_SPACE, "default");
1090                         break;
1091                 case 2:
1092                         set(Tabular::SET_INTERLINE_SPACE,
1093                                 widgetsToLength(interlinespaceED,
1094                                         interlinespaceUnit));
1095                         break;
1096         }
1097 */
1098 }
1099
1100
1101 bool GuiTabular::initialiseParams(string const & data)
1102 {
1103         // try to get the current cell
1104         BufferView const * const bv = bufferview();
1105         InsetTabular const * current_inset = 0;
1106         if (bv) {
1107                 Cursor const & cur = bv->cursor();
1108                 // get the innermost tabular inset;
1109                 // assume that it is "ours"
1110                 for (int i = cur.depth() - 1; i >= 0; --i)
1111                         if (cur[i].inset().lyxCode() == TABULAR_CODE) {
1112                                 current_inset =
1113                                         static_cast<InsetTabular const *>(&cur[i].inset());
1114                                 active_cell_ = cur[i].idx();
1115                                 break;
1116                         }
1117         }
1118
1119         if (current_inset && data.empty()) {
1120                 tabular_ = Tabular(current_inset->tabular);
1121                 return true;
1122         }
1123
1124         InsetTabular tmp(const_cast<Buffer &>(buffer()));
1125         InsetTabular::string2params(data, tmp);
1126         tabular_ = Tabular(tmp.tabular);
1127         return true;
1128 }
1129
1130
1131 void GuiTabular::clearParams()
1132 {
1133         // This function is also called when LyX is closing and the dialog
1134         // is still open. At that time, the buffer might not be available
1135         // anymore.
1136         if (isBufferAvailable()) {
1137                 InsetTabular tmp(const_cast<Buffer &>(buffer()));
1138                 tabular_ = tmp.tabular;
1139         }
1140         active_cell_ = Tabular::npos;
1141 }
1142
1143
1144 Tabular::idx_type GuiTabular::getActiveCell() const
1145 {
1146         return active_cell_;
1147 }
1148
1149
1150 void GuiTabular::set(Tabular::Feature f, string const & arg)
1151 {
1152         string const data = featureAsString(f) + ' ' + arg;
1153         dispatch(FuncRequest(getLfun(), data));
1154 }
1155
1156
1157 void GuiTabular::setSpecial(string const & special)
1158 {
1159         if (tabular_.isMultiColumn(getActiveCell()))
1160                 set(Tabular::SET_SPECIAL_MULTI, special);
1161         else
1162                 set(Tabular::SET_SPECIAL_COLUMN, special);
1163 }
1164
1165
1166 void GuiTabular::setWidth(string const & width)
1167 {
1168         if (tabular_.isMultiColumn(getActiveCell()))
1169                 set(Tabular::SET_MPWIDTH, width);
1170         else
1171                 set(Tabular::SET_PWIDTH, width);
1172
1173         updateView();
1174 }
1175
1176
1177 void GuiTabular::toggleMultiColumn()
1178 {
1179         set(Tabular::MULTICOLUMN);
1180         updateView();
1181 }
1182
1183
1184 void GuiTabular::rotateTabular(bool yes)
1185 {
1186         if (yes)
1187                 set(Tabular::SET_ROTATE_TABULAR);
1188         else
1189                 set(Tabular::UNSET_ROTATE_TABULAR);
1190 }
1191
1192
1193 void GuiTabular::rotateCell(bool yes)
1194 {
1195         if (yes)
1196                 set(Tabular::SET_ROTATE_CELL);
1197         else
1198                 set(Tabular::UNSET_ROTATE_CELL);
1199 }
1200
1201
1202 void GuiTabular::halign(GuiTabular::HALIGN h)
1203 {
1204         Tabular::Feature num = Tabular::ALIGN_LEFT;
1205         Tabular::Feature multi_num = Tabular::M_ALIGN_LEFT;
1206
1207         switch (h) {
1208                 case LEFT:
1209                         num = Tabular::ALIGN_LEFT;
1210                         multi_num = Tabular::M_ALIGN_LEFT;
1211                         break;
1212                 case CENTER:
1213                         num = Tabular::ALIGN_CENTER;
1214                         multi_num = Tabular::M_ALIGN_CENTER;
1215                         break;
1216                 case RIGHT:
1217                         num = Tabular::ALIGN_RIGHT;
1218                         multi_num = Tabular::M_ALIGN_RIGHT;
1219                         break;
1220                 case BLOCK:
1221                         num = Tabular::ALIGN_BLOCK;
1222                         //multi_num: no equivalent
1223                         break;
1224         }
1225
1226         if (tabular_.isMultiColumn(getActiveCell()))
1227                 set(multi_num);
1228         else
1229                 set(num);
1230 }
1231
1232
1233 void GuiTabular::valign(GuiTabular::VALIGN v)
1234 {
1235         Tabular::Feature num = Tabular::VALIGN_MIDDLE;
1236         Tabular::Feature multi_num = Tabular::M_VALIGN_MIDDLE;
1237
1238         switch (v) {
1239                 case TOP:
1240                         num = Tabular::VALIGN_TOP;
1241                         multi_num = Tabular::M_VALIGN_TOP;
1242                         break;
1243                 case MIDDLE:
1244                         num = Tabular::VALIGN_MIDDLE;
1245                         multi_num = Tabular::M_VALIGN_MIDDLE;
1246                         break;
1247                 case BOTTOM:
1248                         num = Tabular::VALIGN_BOTTOM;
1249                         multi_num = Tabular::M_VALIGN_BOTTOM;
1250                         break;
1251         }
1252
1253         if (tabular_.isMultiColumn(getActiveCell()))
1254                 set(multi_num);
1255         else
1256                 set(num);
1257 }
1258
1259
1260 void GuiTabular::booktabs(bool yes)
1261 {
1262         if (yes)
1263                 set(Tabular::SET_BOOKTABS);
1264         else
1265                 set(Tabular::UNSET_BOOKTABS);
1266 }
1267
1268
1269 void GuiTabular::longTabular(bool yes)
1270 {
1271         if (yes)
1272                 set(Tabular::SET_LONGTABULAR);
1273         else
1274                 set(Tabular::UNSET_LONGTABULAR);
1275 }
1276
1277
1278 // to get the status of the longtable row settings
1279 bool GuiTabular::funcEnabled(Tabular::Feature f) const
1280 {
1281         return getStatus(
1282                 FuncRequest(getLfun(), featureAsString(f))).enabled();
1283 }
1284
1285
1286 Dialog * createGuiTabular(GuiView & lv) { return new GuiTabular(lv); }
1287
1288
1289 } // namespace frontend
1290 } // namespace lyx
1291
1292 #include "moc_GuiTabular.cpp"