]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiTabular.cpp
7402a0539ce8f5427f2a3fb0ce513041e3d7fbbe
[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
826         //firstheaderStatusCB->setEnabled(
827         //      !firstheaderNoContentsCB->isChecked());
828         headerBorderAboveCB->setEnabled(funcEnabled(Tabular::SET_LTHEAD));
829         headerBorderBelowCB->setEnabled(funcEnabled(Tabular::SET_LTHEAD));
830         headerStatusCB->setEnabled(funcEnabled(Tabular::SET_LTHEAD));
831         footerBorderAboveCB->setEnabled(funcEnabled(Tabular::SET_LTFOOT));
832         footerBorderBelowCB->setEnabled(funcEnabled(Tabular::SET_LTFOOT));
833         footerStatusCB->setEnabled(funcEnabled(Tabular::SET_LTFOOT));
834         lastfooterBorderAboveCB->setEnabled(
835                 funcEnabled(Tabular::SET_LTLASTFOOT));
836         lastfooterBorderBelowCB->setEnabled(
837                 funcEnabled(Tabular::SET_LTLASTFOOT));
838         // last footer can only be suppressed when there is a footer
839         lastfooterNoContentsCB->setEnabled(tabular_.haveLTFoot()
840                 && !tabular_.haveLTLastFoot());
841
842         captionStatusCB->setEnabled(
843                 funcEnabled(Tabular::TOGGLE_LTCAPTION));
844         // When a row is set as longtable caption, it must not be allowed
845         // to unset that this row is a multicolumn.
846         multicolumnCB->setEnabled(funcEnabled(Tabular::MULTICOLUMN));
847
848         Tabular::ltType ltt;
849         bool use_empty;
850         bool row_set = tabular_.getRowOfLTHead(row, ltt);
851         headerStatusCB->setChecked(row_set);
852         if (ltt.set) {
853                 headerBorderAboveCB->setChecked(ltt.topDL);
854                 headerBorderBelowCB->setChecked(ltt.bottomDL);
855                 use_empty = true;
856         } else {
857                 headerBorderAboveCB->setChecked(false);
858                 headerBorderBelowCB->setChecked(false);
859                 headerBorderAboveCB->setEnabled(false);
860                 headerBorderBelowCB->setEnabled(false);
861                 firstheaderNoContentsCB->setChecked(false);
862                 firstheaderNoContentsCB->setEnabled(false);
863                 use_empty = false;
864         }
865
866         row_set = tabular_.getRowOfLTFirstHead(row, ltt);
867         // check if setting a first header is allowed
868         // additionally check firstheaderStatusCB because when this is the
869         // case a first header makes no sense
870         firstheaderStatusCB->setEnabled(
871                 funcEnabled(Tabular::SET_LTFIRSTHEAD)
872                 && !firstheaderNoContentsCB->isChecked());
873         firstheaderStatusCB->setChecked(row_set);
874         if (ltt.set && (!ltt.empty || !use_empty)) {
875                 firstheaderBorderAboveCB->setChecked(ltt.topDL);
876                 firstheaderBorderBelowCB->setChecked(ltt.bottomDL);
877         } else {
878                 firstheaderBorderAboveCB->setEnabled(false);
879                 firstheaderBorderBelowCB->setEnabled(false);
880                 firstheaderBorderAboveCB->setChecked(false);
881                 firstheaderBorderBelowCB->setChecked(false);
882                 if (use_empty) {
883                         if (ltt.empty)
884                                 firstheaderStatusCB->setEnabled(false);
885                 }
886         }
887
888         row_set = tabular_.getRowOfLTFoot(row, ltt);
889         footerStatusCB->setChecked(row_set);
890         if (ltt.set) {
891                 footerBorderAboveCB->setChecked(ltt.topDL);
892                 footerBorderBelowCB->setChecked(ltt.bottomDL);
893                 use_empty = true;
894         } else {
895                 footerBorderAboveCB->setChecked(false);
896                 footerBorderBelowCB->setChecked(false);
897                 footerBorderAboveCB->setEnabled(false);
898                 footerBorderBelowCB->setEnabled(false);
899                 lastfooterNoContentsCB->setChecked(false);
900                 lastfooterNoContentsCB->setEnabled(false);
901                 use_empty = false;
902         }
903
904         row_set = tabular_.getRowOfLTLastFoot(row, ltt);
905         // check if setting a last footer is allowed
906         // additionally check lastfooterNoContentsCB because when this is
907         // the case a last footer makes no sense
908         lastfooterStatusCB->setEnabled(
909                 funcEnabled(Tabular::SET_LTLASTFOOT)
910                 && !lastfooterNoContentsCB->isChecked());
911         lastfooterStatusCB->setChecked(row_set);
912         if (ltt.set && (!ltt.empty || !use_empty)) {
913                 lastfooterBorderAboveCB->setChecked(ltt.topDL);
914                 lastfooterBorderBelowCB->setChecked(ltt.bottomDL);
915         } else {
916                 lastfooterBorderAboveCB->setEnabled(false);
917                 lastfooterBorderBelowCB->setEnabled(false);
918                 lastfooterBorderAboveCB->setChecked(false);
919                 lastfooterBorderBelowCB->setChecked(false);
920                 if (use_empty) {
921                         if (ltt.empty)
922                                 lastfooterStatusCB->setEnabled(false);
923                 }
924         }
925         newpageCB->setChecked(tabular_.getLTNewPage(row));
926 }
927
928
929 void GuiTabular::closeGUI()
930 {
931         // ugly hack to auto-apply the stuff that hasn't been
932         // yet. don't let this continue to exist ...
933
934         // Subtle here, we must /not/ apply any changes and
935         // then refer to tabular, as it will have been freed
936         // since the changes update the actual tabular_
937         //
938         // apply the fixed width values
939         size_t const cell = getActiveCell();
940         bool const multicol = tabular_.isMultiColumn(cell);
941         string width = widgetsToLength(widthED, widthUnit);
942         string width2;
943
944         Length llen = getColumnPWidth(tabular_, cell);
945         Length llenMulti = getMColumnPWidth(tabular_, cell);
946
947         if (multicol && !llenMulti.zero())
948                 width2 = llenMulti.asString();
949         else if (!multicol && !llen.zero())
950                 width2 = llen.asString();
951
952         // apply the special alignment
953         docstring const sa1 = qstring_to_ucs4(specialAlignmentED->text());
954         docstring sa2;
955
956         if (multicol)
957                 sa2 = getAlignSpecial(tabular_, cell,
958                         Tabular::SET_SPECIAL_MULTI);
959         else
960                 sa2 = getAlignSpecial(tabular_, cell,
961                         Tabular::SET_SPECIAL_COLUMN);
962
963         if (sa1 != sa2) {
964                 if (multicol)
965                         set(Tabular::SET_SPECIAL_MULTI, to_utf8(sa1));
966                 else
967                         set(Tabular::SET_SPECIAL_COLUMN, to_utf8(sa1));
968         }
969
970         if (width != width2) {
971                 if (multicol)
972                         set(Tabular::SET_MPWIDTH, width);
973                 else
974                         set(Tabular::SET_PWIDTH, width);
975         }
976
977         /* DO WE NEED THIS?
978         switch (topspaceCO->currentIndex()) {
979                 case 0:
980                         set(Tabular::SET_TOP_SPACE, "");
981                         break;
982                 case 1:
983                         set(Tabular::SET_TOP_SPACE, "default");
984                         break;
985                 case 2:
986                         set(Tabular::SET_TOP_SPACE,
987                                 widgetsToLength(topspaceED,
988                                         topspaceUnit));
989                         break;
990         }
991
992         switch (bottomspaceCO->currentIndex()) {
993                 case 0:
994                         set(Tabular::SET_BOTTOM_SPACE, "");
995                         break;
996                 case 1:
997                         set(Tabular::SET_BOTTOM_SPACE, "default");
998                         break;
999                 case 2:
1000                         set(Tabular::SET_BOTTOM_SPACE,
1001                                 widgetsToLength(bottomspaceED,
1002                                         bottomspaceUnit));
1003                         break;
1004         }
1005
1006         switch (interlinespaceCO->currentIndex()) {
1007                 case 0:
1008                         set(Tabular::SET_INTERLINE_SPACE, "");
1009                         break;
1010                 case 1:
1011                         set(Tabular::SET_INTERLINE_SPACE, "default");
1012                         break;
1013                 case 2:
1014                         set(Tabular::SET_INTERLINE_SPACE,
1015                                 widgetsToLength(interlinespaceED,
1016                                         interlinespaceUnit));
1017                         break;
1018         }
1019 */
1020 }
1021
1022
1023 bool GuiTabular::initialiseParams(string const & data)
1024 {
1025         // try to get the current cell
1026         BufferView const * const bv = bufferview();
1027         InsetTabular const * current_inset = 0;
1028         if (bv) {
1029                 Cursor const & cur = bv->cursor();
1030                 // get the innermost tabular inset;
1031                 // assume that it is "ours"
1032                 for (int i = cur.depth() - 1; i >= 0; --i)
1033                         if (cur[i].inset().lyxCode() == TABULAR_CODE) {
1034                                 current_inset =
1035                                         static_cast<InsetTabular const *>(&cur[i].inset());
1036                                 active_cell_ = cur[i].idx();
1037                                 break;
1038                         }
1039         }
1040
1041         if (current_inset && data.empty()) {
1042                 tabular_ = Tabular(current_inset->tabular);
1043                 return true;
1044         }
1045
1046         InsetTabular tmp(const_cast<Buffer &>(buffer()));
1047         InsetTabular::string2params(data, tmp);
1048         tabular_ = Tabular(tmp.tabular);
1049         return true;
1050 }
1051
1052
1053 void GuiTabular::clearParams()
1054 {
1055         // This function is also called when LyX is closing and the dialog
1056         // is still open. At that time, the buffer might not be available
1057         // anymore.
1058         if (isBufferAvailable()) {
1059                 InsetTabular tmp(const_cast<Buffer &>(buffer()));
1060                 tabular_ = tmp.tabular;
1061         }
1062         active_cell_ = Tabular::npos;
1063 }
1064
1065
1066 Tabular::idx_type GuiTabular::getActiveCell() const
1067 {
1068         return active_cell_;
1069 }
1070
1071
1072 void GuiTabular::set(Tabular::Feature f, string const & arg)
1073 {
1074         string const data = featureAsString(f) + ' ' + arg;
1075         dispatch(FuncRequest(getLfun(), data));
1076 }
1077
1078
1079 void GuiTabular::setSpecial(string const & special)
1080 {
1081         if (tabular_.isMultiColumn(getActiveCell()))
1082                 set(Tabular::SET_SPECIAL_MULTI, special);
1083         else
1084                 set(Tabular::SET_SPECIAL_COLUMN, special);
1085 }
1086
1087
1088 void GuiTabular::setWidth(string const & width)
1089 {
1090         if (tabular_.isMultiColumn(getActiveCell()))
1091                 set(Tabular::SET_MPWIDTH, width);
1092         else
1093                 set(Tabular::SET_PWIDTH, width);
1094
1095         updateView();
1096 }
1097
1098
1099 void GuiTabular::toggleMultiColumn()
1100 {
1101         set(Tabular::MULTICOLUMN);
1102         updateView();
1103 }
1104
1105
1106 void GuiTabular::rotateTabular(bool yes)
1107 {
1108         if (yes)
1109                 set(Tabular::SET_ROTATE_TABULAR);
1110         else
1111                 set(Tabular::UNSET_ROTATE_TABULAR);
1112 }
1113
1114
1115 void GuiTabular::rotateCell(bool yes)
1116 {
1117         if (yes)
1118                 set(Tabular::SET_ROTATE_CELL);
1119         else
1120                 set(Tabular::UNSET_ROTATE_CELL);
1121 }
1122
1123
1124 void GuiTabular::halign(GuiTabular::HALIGN h)
1125 {
1126         Tabular::Feature num = Tabular::ALIGN_LEFT;
1127         Tabular::Feature multi_num = Tabular::M_ALIGN_LEFT;
1128
1129         switch (h) {
1130                 case LEFT:
1131                         num = Tabular::ALIGN_LEFT;
1132                         multi_num = Tabular::M_ALIGN_LEFT;
1133                         break;
1134                 case CENTER:
1135                         num = Tabular::ALIGN_CENTER;
1136                         multi_num = Tabular::M_ALIGN_CENTER;
1137                         break;
1138                 case RIGHT:
1139                         num = Tabular::ALIGN_RIGHT;
1140                         multi_num = Tabular::M_ALIGN_RIGHT;
1141                         break;
1142                 case BLOCK:
1143                         num = Tabular::ALIGN_BLOCK;
1144                         //multi_num: no equivalent
1145                         break;
1146         }
1147
1148         if (tabular_.isMultiColumn(getActiveCell()))
1149                 set(multi_num);
1150         else
1151                 set(num);
1152 }
1153
1154
1155 void GuiTabular::valign(GuiTabular::VALIGN v)
1156 {
1157         Tabular::Feature num = Tabular::VALIGN_MIDDLE;
1158         Tabular::Feature multi_num = Tabular::M_VALIGN_MIDDLE;
1159
1160         switch (v) {
1161                 case TOP:
1162                         num = Tabular::VALIGN_TOP;
1163                         multi_num = Tabular::M_VALIGN_TOP;
1164                         break;
1165                 case MIDDLE:
1166                         num = Tabular::VALIGN_MIDDLE;
1167                         multi_num = Tabular::M_VALIGN_MIDDLE;
1168                         break;
1169                 case BOTTOM:
1170                         num = Tabular::VALIGN_BOTTOM;
1171                         multi_num = Tabular::M_VALIGN_BOTTOM;
1172                         break;
1173         }
1174
1175         if (tabular_.isMultiColumn(getActiveCell()))
1176                 set(multi_num);
1177         else
1178                 set(num);
1179 }
1180
1181
1182 void GuiTabular::booktabs(bool yes)
1183 {
1184         if (yes)
1185                 set(Tabular::SET_BOOKTABS);
1186         else
1187                 set(Tabular::UNSET_BOOKTABS);
1188 }
1189
1190
1191 void GuiTabular::longTabular(bool yes)
1192 {
1193         if (yes)
1194                 set(Tabular::SET_LONGTABULAR);
1195         else
1196                 set(Tabular::UNSET_LONGTABULAR);
1197 }
1198
1199
1200 // to get the status of the longtable row settings
1201 bool GuiTabular::funcEnabled(Tabular::Feature f) const
1202 {
1203         return getStatus(
1204                 FuncRequest(getLfun(), featureAsString(f))).enabled();
1205 }
1206
1207
1208 Dialog * createGuiTabular(GuiView & lv) { return new GuiTabular(lv); }
1209
1210
1211 } // namespace frontend
1212 } // namespace lyx
1213
1214 #include "moc_GuiTabular.cpp"