]> git.lyx.org Git - lyx.git/blob - src/frontends/qt3/QTabular.C
Extracted from r14281
[lyx.git] / src / frontends / qt3 / 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> > base_class;
40
41 QTabular::QTabular(Dialog & parent)
42         : 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_->multicolumnCB);
54         bcview().addReadOnly(dialog_->rotateCellCB);
55         bcview().addReadOnly(dialog_->rotateTabularCB);
56         bcview().addReadOnly(dialog_->specialAlignmentED);
57         bcview().addReadOnly(dialog_->widthED);
58         bcview().addReadOnly(dialog_->widthUnit);
59         bcview().addReadOnly(dialog_->hAlignCB);
60         bcview().addReadOnly(dialog_->vAlignCB);
61         bcview().addReadOnly(dialog_->borderSetPB);
62         bcview().addReadOnly(dialog_->borderUnsetPB);
63         bcview().addReadOnly(dialog_->borders);
64         bcview().addReadOnly(dialog_->booktabsRB);
65         bcview().addReadOnly(dialog_->borderDefaultRB);
66         bcview().addReadOnly(dialog_->longTabularCB);
67         bcview().addReadOnly(dialog_->headerStatusCB);
68         bcview().addReadOnly(dialog_->headerBorderAboveCB);
69         bcview().addReadOnly(dialog_->headerBorderBelowCB);
70         bcview().addReadOnly(dialog_->firstheaderStatusCB);
71         bcview().addReadOnly(dialog_->firstheaderBorderAboveCB);
72         bcview().addReadOnly(dialog_->firstheaderBorderBelowCB);
73         bcview().addReadOnly(dialog_->firstheaderNoContentsCB);
74         bcview().addReadOnly(dialog_->footerStatusCB);
75         bcview().addReadOnly(dialog_->footerBorderAboveCB);
76         bcview().addReadOnly(dialog_->footerBorderBelowCB);
77         bcview().addReadOnly(dialog_->lastfooterStatusCB);
78         bcview().addReadOnly(dialog_->lastfooterBorderAboveCB);
79         bcview().addReadOnly(dialog_->lastfooterBorderBelowCB);
80         bcview().addReadOnly(dialog_->lastfooterNoContentsCB);
81         bcview().addReadOnly(dialog_->newpageCB);
82         bcview().addReadOnly(dialog_->topspaceED);
83         bcview().addReadOnly(dialog_->topspaceUnit);
84         bcview().addReadOnly(dialog_->topspaceCO);
85         bcview().addReadOnly(dialog_->bottomspaceED);
86         bcview().addReadOnly(dialog_->bottomspaceUnit);
87         bcview().addReadOnly(dialog_->bottomspaceCO);
88         bcview().addReadOnly(dialog_->interlinespaceED);
89         bcview().addReadOnly(dialog_->interlinespaceUnit);
90         bcview().addReadOnly(dialog_->interlinespaceCO);
91
92         // initialize the length validator
93         addCheckedLineEdit(bcview(), dialog_->widthED,
94                 dialog_->fixedWidthColLA);
95         addCheckedLineEdit(bcview(), dialog_->topspaceED,
96                 dialog_->topspaceLA);
97         addCheckedLineEdit(bcview(), dialog_->bottomspaceED,
98                 dialog_->bottomspaceLA);
99         addCheckedLineEdit(bcview(), dialog_->interlinespaceED,
100                 dialog_->interlinespaceLA);
101 }
102
103
104 bool QTabular::isValid()
105 {
106         return true;
107 }
108
109
110 void QTabular::update_borders()
111 {
112         LyXTabular const & tabular = controller().tabular();
113         LyXTabular::idx_type const cell = controller().getActiveCell();
114         bool const isMulticolumnCell = tabular.isMultiColumn(cell);
115         bool const useBookTabs = tabular.useBookTabs();
116
117         if (!isMulticolumnCell) {
118                 dialog_->borders->setLeftEnabled(!useBookTabs);
119                 dialog_->borders->setRightEnabled(!useBookTabs);
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->repaint();
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 to set
132         // if we don't use booktabs and if we are in first/last cell of row
133         // or if the left/right cell is also a multicolumn.
134         if (tabular.isFirstCellInRow(cell) || tabular.isMultiColumn(cell - 1)) {
135                 dialog_->borders->setLeftEnabled(!useBookTabs);
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(!useBookTabs);
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->repaint();
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         dialog_->borderDefaultRB->setChecked(!tabular.useBookTabs());
174
175         dialog_->booktabsRB->setChecked(tabular.useBookTabs());
176
177         update_borders();
178
179         LyXLength pwidth;
180         string special;
181
182         if (multicol) {
183                 special = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_MULTI);
184                 pwidth = tabular.getMColumnPWidth(cell);
185         } else {
186                 special = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_COLUMN);
187                 pwidth = tabular.getColumnPWidth(cell);
188         }
189
190         dialog_->specialAlignmentED->setText(toqstr(special));
191
192         bool const isReadonly = bc().bp().isReadOnly();
193         dialog_->specialAlignmentED->setEnabled(!isReadonly);
194
195         LyXLength::UNIT default_unit = controller().useMetricUnits() ? LyXLength::CM : LyXLength::IN;
196
197         string colwidth;
198         if (!pwidth.zero())
199                 colwidth = pwidth.asString();
200         lengthToWidgets(dialog_->widthED, dialog_->widthUnit,
201                 colwidth, default_unit);
202
203         dialog_->widthED->setEnabled(!isReadonly);
204         dialog_->widthUnit->setEnabled(!isReadonly);
205
206         dialog_->hAlignCB->clear();
207         dialog_->hAlignCB->insertItem(qt_("Left"));
208         dialog_->hAlignCB->insertItem(qt_("Center"));
209         dialog_->hAlignCB->insertItem(qt_("Right"));
210         if (!multicol && !pwidth.zero())
211                 dialog_->hAlignCB->insertItem(qt_("Block"));
212
213         int align = 0;
214         switch (tabular.getAlignment(cell)) {
215         case LYX_ALIGN_LEFT:
216                 align = 0;
217                 break;
218         case LYX_ALIGN_CENTER:
219                 align = 1;
220                 break;
221         case LYX_ALIGN_RIGHT:
222                 align = 2;
223                 break;
224         case LYX_ALIGN_BLOCK:
225         {
226                 if (!multicol && !pwidth.zero())
227                         align = 3;
228                 break;
229         }
230         default:
231                 align = 0;
232                 break;
233         }
234         dialog_->hAlignCB->setCurrentItem(align);
235
236         int valign = 0;
237         switch (tabular.getVAlignment(cell)) {
238         case LyXTabular::LYX_VALIGN_TOP:
239                 valign = 0;
240                 break;
241         case LyXTabular::LYX_VALIGN_MIDDLE:
242                 valign = 1;
243                 break;
244         case LyXTabular::LYX_VALIGN_BOTTOM:
245                 valign = 2;
246                 break;
247         default:
248                 valign = 1;
249                 break;
250         }
251         if (pwidth.zero())
252                 valign = 1;
253         dialog_->vAlignCB->setCurrentItem(valign);
254
255         dialog_->hAlignCB->setEnabled(true);
256         dialog_->vAlignCB->setEnabled(!pwidth.zero());
257
258         if (tabular.row_info[row].top_space.empty()
259             && !tabular.row_info[row].top_space_default) {
260                 dialog_->topspaceCO->setCurrentItem(0);
261         } else if (tabular.row_info[row].top_space_default) {
262                 dialog_->topspaceCO->setCurrentItem(1);
263         } else {
264                 dialog_->topspaceCO->setCurrentItem(2);
265                 lengthToWidgets(dialog_->topspaceED, 
266                                 dialog_->topspaceUnit,
267                                 tabular.row_info[row].top_space.asString(),
268                                 default_unit);
269         }
270         dialog_->topspaceED->setEnabled(!isReadonly 
271                 && (dialog_->topspaceCO->currentItem() == 2));
272         dialog_->topspaceUnit->setEnabled(!isReadonly 
273                 && (dialog_->topspaceCO->currentItem() == 2));
274         dialog_->topspaceCO->setEnabled(!isReadonly);
275
276         if (tabular.row_info[row].bottom_space.empty()
277             && !tabular.row_info[row].bottom_space_default) {
278                 dialog_->bottomspaceCO->setCurrentItem(0);
279         } else if (tabular.row_info[row].bottom_space_default) {
280                 dialog_->bottomspaceCO->setCurrentItem(1);
281         } else {
282                 dialog_->bottomspaceCO->setCurrentItem(2);
283                 lengthToWidgets(dialog_->bottomspaceED, 
284                                 dialog_->bottomspaceUnit,
285                                 tabular.row_info[row].bottom_space.asString(),
286                                 default_unit);
287         }
288         dialog_->bottomspaceED->setEnabled(!isReadonly 
289                 && (dialog_->bottomspaceCO->currentItem() == 2));
290         dialog_->bottomspaceUnit->setEnabled(!isReadonly 
291                 && (dialog_->bottomspaceCO->currentItem() == 2));
292         dialog_->bottomspaceCO->setEnabled(!isReadonly);
293
294         if (tabular.row_info[row].interline_space.empty()
295             && !tabular.row_info[row].interline_space_default) {
296                 dialog_->interlinespaceCO->setCurrentItem(0);
297         } else if (tabular.row_info[row].interline_space_default) {
298                 dialog_->interlinespaceCO->setCurrentItem(1);
299         } else {
300                 dialog_->interlinespaceCO->setCurrentItem(2);
301                 lengthToWidgets(dialog_->interlinespaceED, 
302                                 dialog_->interlinespaceUnit,
303                                 tabular.row_info[row].interline_space.asString(),
304                                 default_unit);
305         }
306         dialog_->interlinespaceED->setEnabled(!isReadonly 
307                 && (dialog_->interlinespaceCO->currentItem() == 2));
308         dialog_->interlinespaceUnit->setEnabled(!isReadonly 
309                 && (dialog_->interlinespaceCO->currentItem() == 2));
310         dialog_->interlinespaceCO->setEnabled(!isReadonly);
311
312         if (!tabular.isLongTabular()) {
313                 dialog_->headerStatusCB->setChecked(false);
314                 dialog_->headerBorderAboveCB->setChecked(false);
315                 dialog_->headerBorderBelowCB->setChecked(false);
316                 dialog_->firstheaderStatusCB->setChecked(false);
317                 dialog_->firstheaderBorderAboveCB->setChecked(false);
318                 dialog_->firstheaderBorderBelowCB->setChecked(false);
319                 dialog_->firstheaderNoContentsCB->setChecked(false);
320                 dialog_->footerStatusCB->setChecked(false);
321                 dialog_->footerBorderAboveCB->setChecked(false);
322                 dialog_->footerBorderBelowCB->setChecked(false);
323                 dialog_->lastfooterStatusCB->setChecked(false);
324                 dialog_->lastfooterBorderAboveCB->setChecked(false);
325                 dialog_->lastfooterBorderBelowCB->setChecked(false);
326                 dialog_->lastfooterNoContentsCB->setChecked(false);
327                 dialog_->newpageCB->setChecked(false);
328                 dialog_->newpageCB->setEnabled(false);
329                 return;
330         }
331
332         LyXTabular::ltType ltt;
333         bool use_empty;
334         bool row_set = tabular.getRowOfLTHead(row, ltt);
335         dialog_->headerStatusCB->setChecked(row_set);
336         if (ltt.set) {
337                 dialog_->headerBorderAboveCB->setChecked(ltt.topDL);
338                 dialog_->headerBorderBelowCB->setChecked(ltt.bottomDL);
339                 use_empty = true;
340         } else {
341                 dialog_->headerBorderAboveCB->setChecked(false);
342                 dialog_->headerBorderBelowCB->setChecked(false);
343                 dialog_->headerBorderAboveCB->setEnabled(false);
344                 dialog_->headerBorderBelowCB->setEnabled(false);
345                 dialog_->firstheaderNoContentsCB->setChecked(false);
346                 dialog_->firstheaderNoContentsCB->setEnabled(false);
347                 use_empty = false;
348         }
349
350         row_set = tabular.getRowOfLTFirstHead(row, ltt);
351         dialog_->firstheaderStatusCB->setChecked(row_set);
352         if (ltt.set && (!ltt.empty || !use_empty)) {
353                 dialog_->firstheaderBorderAboveCB->setChecked(ltt.topDL);
354                 dialog_->firstheaderBorderBelowCB->setChecked(ltt.bottomDL);
355         } else {
356                 dialog_->firstheaderBorderAboveCB->setEnabled(false);
357                 dialog_->firstheaderBorderBelowCB->setEnabled(false);
358                 dialog_->firstheaderBorderAboveCB->setChecked(false);
359                 dialog_->firstheaderBorderBelowCB->setChecked(false);
360                 if (use_empty) {
361                         dialog_->firstheaderNoContentsCB->setChecked(ltt.empty);
362                         if (ltt.empty)
363                                 dialog_->firstheaderStatusCB->setEnabled(false);
364                 }
365         }
366
367         row_set = tabular.getRowOfLTFoot(row, ltt);
368         dialog_->footerStatusCB->setChecked(row_set);
369         if (ltt.set) {
370                 dialog_->footerBorderAboveCB->setChecked(ltt.topDL);
371                 dialog_->footerBorderBelowCB->setChecked(ltt.bottomDL);
372                 use_empty = true;
373         } else {
374                 dialog_->footerBorderAboveCB->setChecked(false);
375                 dialog_->footerBorderBelowCB->setChecked(false);
376                 dialog_->footerBorderAboveCB->setEnabled(false);
377                 dialog_->footerBorderBelowCB->setEnabled(false);
378                 dialog_->lastfooterNoContentsCB->setChecked(false);
379                 dialog_->lastfooterNoContentsCB->setEnabled(false);
380                 use_empty = false;
381         }
382
383         row_set = tabular.getRowOfLTLastFoot(row, ltt);
384                 dialog_->lastfooterStatusCB->setChecked(row_set);
385         if (ltt.set && (!ltt.empty || !use_empty)) {
386                 dialog_->lastfooterBorderAboveCB->setChecked(ltt.topDL);
387                 dialog_->lastfooterBorderBelowCB->setChecked(ltt.bottomDL);
388         } else {
389                 dialog_->lastfooterBorderAboveCB->setEnabled(false);
390                 dialog_->lastfooterBorderBelowCB->setEnabled(false);
391                 dialog_->lastfooterBorderAboveCB->setChecked(false);
392                 dialog_->lastfooterBorderBelowCB->setChecked(false);
393                 if (use_empty) {
394                         dialog_->lastfooterNoContentsCB->setChecked(ltt.empty);
395                         if (ltt.empty)
396                                 dialog_->lastfooterStatusCB->setEnabled(false);
397                 }
398         }
399         dialog_->newpageCB->setChecked(tabular.getLTNewPage(row));
400 }
401
402
403 void QTabular::closeGUI()
404 {
405         // ugly hack to auto-apply the stuff that hasn't been
406         // yet. don't let this continue to exist ...
407
408         // Subtle here, we must /not/ apply any changes and
409         // then refer to tabular, as it will have been freed
410         // since the changes update the actual controller().tabular()
411         LyXTabular const & tabular(controller().tabular());
412
413         // apply the fixed width values
414         LyXTabular::idx_type const cell = controller().getActiveCell();
415         bool const multicol = tabular.isMultiColumn(cell);
416         string width = widgetsToLength(dialog_->widthED, dialog_->widthUnit);
417         string width2;
418
419         LyXLength llen = tabular.getColumnPWidth(cell);
420         LyXLength llenMulti = tabular.getMColumnPWidth(cell);
421
422         if (multicol && !llenMulti.zero())
423                         width2 = llenMulti.asString();
424         else if (!multicol && !llen.zero())
425                         width2 = llen.asString();
426
427         // apply the special alignment
428         string const sa1 = fromqstr(dialog_->specialAlignmentED->text());
429         string sa2;
430
431         if (multicol)
432                 sa2 = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_MULTI);
433         else
434                 sa2 = tabular.getAlignSpecial(cell, LyXTabular::SET_SPECIAL_COLUMN);
435
436         if (sa1 != sa2) {
437                 if (multicol)
438                         controller().set(LyXTabular::SET_SPECIAL_MULTI, sa1);
439                 else
440                         controller().set(LyXTabular::SET_SPECIAL_COLUMN, sa1);
441         }
442
443         if (width != width2) {
444                 if (multicol)
445                         controller().set(LyXTabular::SET_MPWIDTH, width);
446                 else
447                         controller().set(LyXTabular::SET_PWIDTH, width);
448         }
449
450         switch (dialog_->topspaceCO->currentItem()) {
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->currentItem()) {
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->currentItem()) {
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 } // namespace frontend
494 } // namespace lyx