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