]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/QTabular.C
* src/frontends/qt4/ui/QTabularUi.ui:
[lyx.git] / src / frontends / qt4 / QTabular.C
1 /**
2  * \file QTabular.C
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 "checkedwidgets.h"
16 #include "QTabular.h"
17 #include "QTabularDialog.h"
18 #include "Qt2BC.h"
19
20 #include "lengthcombo.h"
21 #include "qt_helpers.h"
22
23 #include "controllers/ButtonController.h"
24 #include "controllers/ControlTabular.h"
25
26 #include "support/convert.h"
27
28 #include <qcheckbox.h>
29 #include <qlineedit.h>
30 #include <qpushbutton.h>
31 #include <qradiobutton.h>
32 #include "qsetborder.h"
33
34 using std::string;
35
36 namespace lyx {
37 namespace frontend {
38
39 typedef QController<ControlTabular, QView<QTabularDialog> > tabular_base_class;
40
41 QTabular::QTabular(Dialog & parent)
42         : tabular_base_class(parent, _("Table Settings"))
43 {
44 }
45
46
47 void QTabular::build_dialog()
48 {
49         dialog_.reset(new QTabularDialog(this));
50
51         bcview().setCancel(dialog_->closePB);
52
53         bcview().addReadOnly(dialog_->topspaceED);
54         bcview().addReadOnly(dialog_->topspaceUnit);
55         bcview().addReadOnly(dialog_->topspaceCO);
56         bcview().addReadOnly(dialog_->bottomspaceED);
57         bcview().addReadOnly(dialog_->bottomspaceUnit);
58         bcview().addReadOnly(dialog_->bottomspaceCO);
59         bcview().addReadOnly(dialog_->interlinespaceED);
60         bcview().addReadOnly(dialog_->interlinespaceUnit);
61         bcview().addReadOnly(dialog_->interlinespaceCO);
62         bcview().addReadOnly(dialog_->borderDefaultRB);
63         bcview().addReadOnly(dialog_->booktabsRB);
64
65         bcview().addReadOnly(dialog_->multicolumnCB);
66         bcview().addReadOnly(dialog_->rotateCellCB);
67         bcview().addReadOnly(dialog_->rotateTabularCB);
68         bcview().addReadOnly(dialog_->specialAlignmentED);
69         bcview().addReadOnly(dialog_->widthED);
70         bcview().addReadOnly(dialog_->widthUnit);
71         bcview().addReadOnly(dialog_->hAlignCB);
72         bcview().addReadOnly(dialog_->vAlignCB);
73         bcview().addReadOnly(dialog_->borderSetPB);
74         bcview().addReadOnly(dialog_->borderUnsetPB);
75         bcview().addReadOnly(dialog_->borders);
76         bcview().addReadOnly(dialog_->longTabularCB);
77         bcview().addReadOnly(dialog_->headerStatusCB);
78         bcview().addReadOnly(dialog_->headerBorderAboveCB);
79         bcview().addReadOnly(dialog_->headerBorderBelowCB);
80         bcview().addReadOnly(dialog_->firstheaderStatusCB);
81         bcview().addReadOnly(dialog_->firstheaderBorderAboveCB);
82         bcview().addReadOnly(dialog_->firstheaderBorderBelowCB);
83         bcview().addReadOnly(dialog_->firstheaderNoContentsCB);
84         bcview().addReadOnly(dialog_->footerStatusCB);
85         bcview().addReadOnly(dialog_->footerBorderAboveCB);
86         bcview().addReadOnly(dialog_->footerBorderBelowCB);
87         bcview().addReadOnly(dialog_->lastfooterStatusCB);
88         bcview().addReadOnly(dialog_->lastfooterBorderAboveCB);
89         bcview().addReadOnly(dialog_->lastfooterBorderBelowCB);
90         bcview().addReadOnly(dialog_->lastfooterNoContentsCB);
91         bcview().addReadOnly(dialog_->newpageCB);
92
93         // initialize the length validator
94         addCheckedLineEdit(bcview(), dialog_->widthED,
95                 dialog_->fixedWidthColLA);
96         addCheckedLineEdit(bcview(), dialog_->topspaceED,
97                 dialog_->topspaceLA);
98         addCheckedLineEdit(bcview(), dialog_->bottomspaceED,
99                 dialog_->bottomspaceLA);
100         addCheckedLineEdit(bcview(), dialog_->interlinespaceED,
101                 dialog_->interlinespaceLA);
102 }
103
104
105 bool QTabular::isValid()
106 {
107         return true;
108 }
109
110
111 void QTabular::update_borders()
112 {
113         LyXTabular const & tabular = controller().tabular();
114         LyXTabular::idx_type const cell = controller().getActiveCell();
115         bool const isMulticolumnCell = tabular.isMultiColumn(cell);
116
117         if (!isMulticolumnCell) {
118                 dialog_->borders->setLeftEnabled(true);
119                 dialog_->borders->setRightEnabled(true);
120                 dialog_->borders->setTop(tabular.topLine(cell, true));
121                 dialog_->borders->setBottom(tabular.bottomLine(cell, true));
122                 dialog_->borders->setLeft(tabular.leftLine(cell, true));
123                 dialog_->borders->setRight(tabular.rightLine(cell, true));
124                 // repaint the setborder widget
125                 dialog_->borders->update();
126                 return;
127         }
128
129         dialog_->borders->setTop(tabular.topLine(cell));
130         dialog_->borders->setBottom(tabular.bottomLine(cell));
131         // pay attention to left/right lines: they are only allowed
132         // to set if we are in first/last cell of row or if the left/right
133         // cell is also a multicolumn.
134         if (tabular.isFirstCellInRow(cell) || tabular.isMultiColumn(cell - 1)) {
135                 dialog_->borders->setLeftEnabled(true);
136                 dialog_->borders->setLeft(tabular.leftLine(cell));
137         } else {
138                 dialog_->borders->setLeft(false);
139                 dialog_->borders->setLeftEnabled(false);
140         }
141         if (tabular.isLastCellInRow(cell) || tabular.isMultiColumn(cell + 1)) {
142                 dialog_->borders->setRightEnabled(true);
143                 dialog_->borders->setRight(tabular.rightLine(cell));
144         } else {
145                 dialog_->borders->setRight(false);
146                 dialog_->borders->setRightEnabled(false);
147         }
148         // repaint the setborder widget
149         dialog_->borders->update();
150 }
151
152
153 void QTabular::update_contents()
154 {
155         LyXTabular const & tabular(controller().tabular());
156         LyXTabular::idx_type const cell = controller().getActiveCell();
157
158         LyXTabular::row_type const row(tabular.row_of_cell(cell));
159         LyXTabular::col_type const col(tabular.column_of_cell(cell));
160
161         dialog_->tabularRowED->setText(toqstr(convert<string>(row + 1)));
162         dialog_->tabularColumnED->setText(toqstr(convert<string>(col + 1)));
163
164         bool const multicol(tabular.isMultiColumn(cell));
165
166         dialog_->multicolumnCB->setChecked(multicol);
167
168         dialog_->rotateCellCB->setChecked(tabular.getRotateCell(cell));
169         dialog_->rotateTabularCB->setChecked(tabular.getRotateTabular());
170
171         dialog_->longTabularCB->setChecked(tabular.isLongTabular());
172
173         update_borders();
174
175         LyXLength pwidth;
176         docstring special;
177
178         if (multicol) {
179                 special = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_MULTI);
180                 pwidth = tabular.getMColumnPWidth(cell);
181         } else {
182                 special = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_COLUMN);
183                 pwidth = tabular.getColumnPWidth(cell);
184         }
185
186         dialog_->specialAlignmentED->setText(toqstr(special));
187
188         bool const isReadonly = bc().bp().isReadOnly();
189         dialog_->specialAlignmentED->setEnabled(!isReadonly);
190
191         LyXLength::UNIT default_unit = controller().useMetricUnits() ? LyXLength::CM : LyXLength::IN;
192
193         dialog_->borderDefaultRB->setChecked(!tabular.useBookTabs());
194         dialog_->booktabsRB->setChecked(tabular.useBookTabs());
195
196         if (tabular.row_info[row].top_space.empty()
197             && !tabular.row_info[row].top_space_default) {
198                 dialog_->topspaceCO->setCurrentIndex(0);
199         } else if (tabular.row_info[row].top_space_default) {
200                 dialog_->topspaceCO->setCurrentIndex(1);
201         } else {
202                 dialog_->topspaceCO->setCurrentIndex(2);
203                 lengthToWidgets(dialog_->topspaceED, 
204                                 dialog_->topspaceUnit,
205                                 tabular.row_info[row].top_space.asString(),
206                                 default_unit);
207         }
208         dialog_->topspaceED->setEnabled(!isReadonly 
209                 && (dialog_->topspaceCO->currentIndex() == 2));
210         dialog_->topspaceUnit->setEnabled(!isReadonly 
211                 && (dialog_->topspaceCO->currentIndex() == 2));
212         dialog_->topspaceCO->setEnabled(!isReadonly);
213
214         if (tabular.row_info[row].bottom_space.empty()
215             && !tabular.row_info[row].bottom_space_default) {
216                 dialog_->bottomspaceCO->setCurrentIndex(0);
217         } else if (tabular.row_info[row].bottom_space_default) {
218                 dialog_->bottomspaceCO->setCurrentIndex(1);
219         } else {
220                 dialog_->bottomspaceCO->setCurrentIndex(2);
221                 lengthToWidgets(dialog_->bottomspaceED, 
222                                 dialog_->bottomspaceUnit,
223                                 tabular.row_info[row].bottom_space.asString(),
224                                 default_unit);
225         }
226         dialog_->bottomspaceED->setEnabled(!isReadonly 
227                 && (dialog_->bottomspaceCO->currentIndex() == 2));
228         dialog_->bottomspaceUnit->setEnabled(!isReadonly 
229                 && (dialog_->bottomspaceCO->currentIndex() == 2));
230         dialog_->bottomspaceCO->setEnabled(!isReadonly);
231
232         if (tabular.row_info[row].interline_space.empty()
233             && !tabular.row_info[row].interline_space_default) {
234                 dialog_->interlinespaceCO->setCurrentIndex(0);
235         } else if (tabular.row_info[row].interline_space_default) {
236                 dialog_->interlinespaceCO->setCurrentIndex(1);
237         } else {
238                 dialog_->interlinespaceCO->setCurrentIndex(2);
239                 lengthToWidgets(dialog_->interlinespaceED, 
240                                 dialog_->interlinespaceUnit,
241                                 tabular.row_info[row].interline_space.asString(),
242                                 default_unit);
243         }
244         dialog_->interlinespaceED->setEnabled(!isReadonly 
245                 && (dialog_->interlinespaceCO->currentIndex() == 2));
246         dialog_->interlinespaceUnit->setEnabled(!isReadonly 
247                 && (dialog_->interlinespaceCO->currentIndex() == 2));
248         dialog_->interlinespaceCO->setEnabled(!isReadonly);
249
250         string colwidth;
251         if (!pwidth.zero())
252                 colwidth = pwidth.asString();
253         lengthToWidgets(dialog_->widthED, dialog_->widthUnit,
254                 colwidth, default_unit);
255
256         dialog_->widthED->setEnabled(!isReadonly);
257         dialog_->widthUnit->setEnabled(!isReadonly);
258
259         dialog_->hAlignCB->clear();
260         dialog_->hAlignCB->addItem(qt_("Left"));
261         dialog_->hAlignCB->addItem(qt_("Center"));
262         dialog_->hAlignCB->addItem(qt_("Right"));
263         if (!multicol && !pwidth.zero())
264                 dialog_->hAlignCB->addItem(qt_("Justified"));
265
266         int align = 0;
267         switch (tabular.getAlignment(cell)) {
268         case LYX_ALIGN_LEFT:
269                 align = 0;
270                 break;
271         case LYX_ALIGN_CENTER:
272                 align = 1;
273                 break;
274         case LYX_ALIGN_RIGHT:
275                 align = 2;
276                 break;
277         case LYX_ALIGN_BLOCK:
278         {
279                 if (!multicol && !pwidth.zero())
280                         align = 3;
281                 break;
282         }
283         default:
284                 align = 0;
285                 break;
286         }
287         dialog_->hAlignCB->setCurrentIndex(align);
288
289         int valign = 0;
290         switch (tabular.getVAlignment(cell)) {
291         case LyXTabular::LYX_VALIGN_TOP:
292                 valign = 0;
293                 break;
294         case LyXTabular::LYX_VALIGN_MIDDLE:
295                 valign = 1;
296                 break;
297         case LyXTabular::LYX_VALIGN_BOTTOM:
298                 valign = 2;
299                 break;
300         default:
301                 valign = 1;
302                 break;
303         }
304         if (pwidth.zero())
305                 valign = 1;
306         dialog_->vAlignCB->setCurrentIndex(valign);
307
308         dialog_->hAlignCB->setEnabled(true);
309         dialog_->vAlignCB->setEnabled(!pwidth.zero());
310
311         if (!tabular.isLongTabular()) {
312                 dialog_->headerStatusCB->setChecked(false);
313                 dialog_->headerBorderAboveCB->setChecked(false);
314                 dialog_->headerBorderBelowCB->setChecked(false);
315                 dialog_->firstheaderStatusCB->setChecked(false);
316                 dialog_->firstheaderBorderAboveCB->setChecked(false);
317                 dialog_->firstheaderBorderBelowCB->setChecked(false);
318                 dialog_->firstheaderNoContentsCB->setChecked(false);
319                 dialog_->footerStatusCB->setChecked(false);
320                 dialog_->footerBorderAboveCB->setChecked(false);
321                 dialog_->footerBorderBelowCB->setChecked(false);
322                 dialog_->lastfooterStatusCB->setChecked(false);
323                 dialog_->lastfooterBorderAboveCB->setChecked(false);
324                 dialog_->lastfooterBorderBelowCB->setChecked(false);
325                 dialog_->lastfooterNoContentsCB->setChecked(false);
326                 dialog_->newpageCB->setChecked(false);
327                 dialog_->newpageCB->setEnabled(false);
328                 return;
329         }
330
331         LyXTabular::ltType ltt;
332         bool use_empty;
333         bool row_set = tabular.getRowOfLTHead(row, ltt);
334         dialog_->headerStatusCB->setChecked(row_set);
335         if (ltt.set) {
336                 dialog_->headerBorderAboveCB->setChecked(ltt.topDL);
337                 dialog_->headerBorderBelowCB->setChecked(ltt.bottomDL);
338                 use_empty = true;
339         } else {
340                 dialog_->headerBorderAboveCB->setChecked(false);
341                 dialog_->headerBorderBelowCB->setChecked(false);
342                 dialog_->headerBorderAboveCB->setEnabled(false);
343                 dialog_->headerBorderBelowCB->setEnabled(false);
344                 dialog_->firstheaderNoContentsCB->setChecked(false);
345                 dialog_->firstheaderNoContentsCB->setEnabled(false);
346                 use_empty = false;
347         }
348
349         row_set = tabular.getRowOfLTFirstHead(row, ltt);
350         dialog_->firstheaderStatusCB->setChecked(row_set);
351         if (ltt.set && (!ltt.empty || !use_empty)) {
352                 dialog_->firstheaderBorderAboveCB->setChecked(ltt.topDL);
353                 dialog_->firstheaderBorderBelowCB->setChecked(ltt.bottomDL);
354         } else {
355                 dialog_->firstheaderBorderAboveCB->setEnabled(false);
356                 dialog_->firstheaderBorderBelowCB->setEnabled(false);
357                 dialog_->firstheaderBorderAboveCB->setChecked(false);
358                 dialog_->firstheaderBorderBelowCB->setChecked(false);
359                 if (use_empty) {
360                         dialog_->firstheaderNoContentsCB->setChecked(ltt.empty);
361                         if (ltt.empty)
362                                 dialog_->firstheaderStatusCB->setEnabled(false);
363                 }
364         }
365
366         row_set = tabular.getRowOfLTFoot(row, ltt);
367         dialog_->footerStatusCB->setChecked(row_set);
368         if (ltt.set) {
369                 dialog_->footerBorderAboveCB->setChecked(ltt.topDL);
370                 dialog_->footerBorderBelowCB->setChecked(ltt.bottomDL);
371                 use_empty = true;
372         } else {
373                 dialog_->footerBorderAboveCB->setChecked(false);
374                 dialog_->footerBorderBelowCB->setChecked(false);
375                 dialog_->footerBorderAboveCB->setEnabled(false);
376                 dialog_->footerBorderBelowCB->setEnabled(false);
377                 dialog_->lastfooterNoContentsCB->setChecked(false);
378                 dialog_->lastfooterNoContentsCB->setEnabled(false);
379                 use_empty = false;
380         }
381
382         row_set = tabular.getRowOfLTLastFoot(row, ltt);
383                 dialog_->lastfooterStatusCB->setChecked(row_set);
384         if (ltt.set && (!ltt.empty || !use_empty)) {
385                 dialog_->lastfooterBorderAboveCB->setChecked(ltt.topDL);
386                 dialog_->lastfooterBorderBelowCB->setChecked(ltt.bottomDL);
387         } else {
388                 dialog_->lastfooterBorderAboveCB->setEnabled(false);
389                 dialog_->lastfooterBorderBelowCB->setEnabled(false);
390                 dialog_->lastfooterBorderAboveCB->setChecked(false);
391                 dialog_->lastfooterBorderBelowCB->setChecked(false);
392                 if (use_empty) {
393                         dialog_->lastfooterNoContentsCB->setChecked(ltt.empty);
394                         if (ltt.empty)
395                                 dialog_->lastfooterStatusCB->setEnabled(false);
396                 }
397         }
398         dialog_->newpageCB->setChecked(tabular.getLTNewPage(row));
399 }
400
401
402 void QTabular::closeGUI()
403 {
404         // ugly hack to auto-apply the stuff that hasn't been
405         // yet. don't let this continue to exist ...
406
407         // Subtle here, we must /not/ apply any changes and
408         // then refer to tabular, as it will have been freed
409         // since the changes update the actual controller().tabular()
410         LyXTabular const & tabular(controller().tabular());
411
412         // apply the fixed width values
413         LyXTabular::idx_type const cell = controller().getActiveCell();
414         bool const multicol = tabular.isMultiColumn(cell);
415         string width = widgetsToLength(dialog_->widthED, dialog_->widthUnit);
416         string width2;
417
418         LyXLength llen = tabular.getColumnPWidth(cell);
419         LyXLength llenMulti = tabular.getMColumnPWidth(cell);
420
421         if (multicol && !llenMulti.zero())
422                         width2 = llenMulti.asString();
423         else if (!multicol && !llen.zero())
424                         width2 = llen.asString();
425
426         // apply the special alignment
427         docstring const sa1 = qstring_to_ucs4(dialog_->specialAlignmentED->text());
428         docstring sa2;
429
430         if (multicol)
431                 sa2 = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_MULTI);
432         else
433                 sa2 = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_COLUMN);
434
435         if (sa1 != sa2) {
436                 if (multicol)
437                         controller().set(LyXTabular::SET_SPECIAL_MULTI, to_utf8(sa1));
438                 else
439                         controller().set(LyXTabular::SET_SPECIAL_COLUMN, to_utf8(sa1));
440         }
441
442         if (width != width2) {
443                 if (multicol)
444                         controller().set(LyXTabular::SET_MPWIDTH, width);
445                 else
446                         controller().set(LyXTabular::SET_PWIDTH, width);
447         }
448
449         /* DO WE NEED THIS?
450         switch (dialog_->topspaceCO->currentIndex()) {
451                 case 0:
452                         controller().set(LyXTabular::SET_TOP_SPACE, "");
453                         break;
454                 case 1:
455                         controller().set(LyXTabular::SET_TOP_SPACE, "default");
456                         break;
457                 case 2:
458                         controller().set(LyXTabular::SET_TOP_SPACE,
459                                 widgetsToLength(dialog_->topspaceED, 
460                                         dialog_->topspaceUnit));
461                         break;
462         }
463
464         switch (dialog_->bottomspaceCO->currentIndex()) {
465                 case 0:
466                         controller().set(LyXTabular::SET_BOTTOM_SPACE, "");
467                         break;
468                 case 1:
469                         controller().set(LyXTabular::SET_BOTTOM_SPACE, "default");
470                         break;
471                 case 2:
472                         controller().set(LyXTabular::SET_BOTTOM_SPACE,
473                                 widgetsToLength(dialog_->bottomspaceED, 
474                                         dialog_->bottomspaceUnit));
475                         break;
476         }
477
478         switch (dialog_->interlinespaceCO->currentIndex()) {
479                 case 0:
480                         controller().set(LyXTabular::SET_INTERLINE_SPACE, "");
481                         break;
482                 case 1:
483                         controller().set(LyXTabular::SET_INTERLINE_SPACE, "default");
484                         break;
485                 case 2:
486                         controller().set(LyXTabular::SET_INTERLINE_SPACE,
487                                 widgetsToLength(dialog_->interlinespaceED, 
488                                         dialog_->interlinespaceUnit));
489                         break;
490         }
491 */
492 }
493
494 } // namespace frontend
495 } // namespace lyx