]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiBox.cpp
GuiBox: fix bug 3242 http://bugzilla.lyx.org/show_bug.cgi?id=3242:
[lyx.git] / src / frontends / qt4 / GuiBox.cpp
1 /**
2  * \file GuiBox.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna (Minipage stuff)
7  * \author Martin Vermeer
8  * \author Jürgen Spitzmüller
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiBox.h"
16
17 #include "LengthCombo.h"
18 #include "qt_helpers.h"
19 #include "lengthcommon.h"
20 #include "LyXRC.h" // to set the default length values
21 #include "Validator.h"
22
23 #include "insets/InsetBox.h"
24
25 #include "support/lstrings.h"
26
27 #include <QPushButton>
28 #include <QLineEdit>
29 #include <QCloseEvent>
30
31
32 using std::string;
33
34 namespace lyx {
35 namespace frontend {
36
37 GuiBoxDialog::GuiBoxDialog(LyXView & lv)
38         : GuiDialog(lv, "box")
39 {
40         setupUi(this);
41         setViewTitle(_("Box Settings"));
42         setController(new ControlBox(*this));
43
44         // fill the box type choice
45         box_gui_tokens(ids_, gui_names_);
46         for (unsigned int i = 0; i < gui_names_.size(); ++i)
47                 typeCO->addItem(toqstr(gui_names_[i]));
48
49         // add the special units to the height choice
50         // width needs different handling
51         box_gui_tokens_special_length(ids_spec_, gui_names_spec_);
52         for (unsigned int i = 1; i < gui_names_spec_.size(); ++i)
53                 heightUnitsLC->addItem(toqstr(gui_names_spec_[i]));
54
55         connect(restorePB, SIGNAL(clicked()), this, SLOT(slotRestore()));
56         connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
57         connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
58         connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
59
60         connect(widthED, SIGNAL(textChanged(const QString &)),
61                 this, SLOT(change_adaptor()));
62         connect(widthUnitsLC, SIGNAL(selectionChanged(lyx::Length::UNIT)),
63                 this, SLOT(change_adaptor()));
64         connect(valignCO, SIGNAL(highlighted(const QString &)),
65                 this, SLOT(change_adaptor()));
66         connect(heightCB, SIGNAL(stateChanged(int)),
67                 this, SLOT(change_adaptor()));
68         connect(heightED, SIGNAL(textChanged(const QString &)),
69                 this, SLOT(change_adaptor()));
70         connect(heightUnitsLC, SIGNAL(selectionChanged(lyx::Length::UNIT) ),
71                 this, SLOT(change_adaptor()));
72         connect(restorePB, SIGNAL(clicked()), this, SLOT(restoreClicked()));
73         connect(typeCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
74         connect(typeCO, SIGNAL(activated(int)), this, SLOT(typeChanged(int)));
75         connect(heightCB, SIGNAL(stateChanged(int)), this, SLOT(heightChecked(int)));
76         connect(halignCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
77         connect(ialignCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
78         connect(innerBoxCO, SIGNAL(activated(const QString&)),
79                 this, SLOT(innerBoxChanged(const QString &)));
80         connect(innerBoxCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
81
82         heightED->setValidator(unsignedLengthValidator(heightED));
83         widthED->setValidator(unsignedLengthValidator(widthED));
84
85         bc().setPolicy(ButtonPolicy::OkApplyCancelReadOnlyPolicy);
86
87         bc().addReadOnly(typeCO);
88         bc().addReadOnly(innerBoxCO);
89         bc().addReadOnly(valignCO);
90         bc().addReadOnly(ialignCO);
91         bc().addReadOnly(halignCO);
92         bc().addReadOnly(widthED);
93         bc().addReadOnly(widthUnitsLC);
94         bc().addReadOnly(heightCB);
95         bc().addReadOnly(heightED);
96         bc().addReadOnly(heightUnitsLC);
97
98         bc().setRestore(restorePB);
99         bc().setOK(okPB);
100         bc().setApply(applyPB);
101         bc().setCancel(closePB);
102
103         // initialize the length validator
104         bc().addCheckedLineEdit(widthED, widthLA);
105         bc().addCheckedLineEdit(heightED, heightCB);
106 }
107
108
109 ControlBox & GuiBoxDialog::controller()
110 {
111         return static_cast<ControlBox &>(GuiDialog::controller());
112 }
113
114
115 void GuiBoxDialog::closeEvent(QCloseEvent * e)
116 {
117         slotClose();
118         e->accept();
119 }
120
121
122 void GuiBoxDialog::change_adaptor()
123 {
124         changed();
125 }
126
127
128 void GuiBoxDialog::innerBoxChanged(const QString & str)
129 {
130         bool const ibox = (str != qt_("None"));
131         valignCO->setEnabled(ibox);
132         ialignCO->setEnabled(ibox);
133         halignCO->setEnabled(!ibox);
134         heightCB->setEnabled(ibox);
135         if (heightCB->checkState() == Qt::Checked && ibox) {
136                 heightED->setEnabled(true);
137                 heightUnitsLC->setEnabled(true);
138         }
139         setSpecial(ibox);
140 }
141
142
143 void GuiBoxDialog::typeChanged(int index)
144 {
145         bool const frameless = (index == 0);
146         if (frameless) {
147                 valignCO->setEnabled(true);
148                 ialignCO->setEnabled(true);
149                 halignCO->setEnabled(false);
150                 heightCB->setEnabled(true);
151                 heightED->setEnabled(true);
152                 heightUnitsLC->setEnabled(true);
153                 setSpecial(true);
154         }
155         int itype = innerBoxCO->currentIndex();
156         setInnerType(frameless, itype);
157 }
158
159
160 void GuiBoxDialog::heightChecked(int checkState)
161 {
162         if (checkState == Qt::Unchecked) {
163                 heightED->setEnabled(false);
164                 heightUnitsLC->setEnabled(false);
165         } else { 
166                 heightED->setEnabled(true);
167                 heightUnitsLC->setEnabled(true);
168         }
169 }
170
171 void GuiBoxDialog::restoreClicked()
172 {
173         setInnerType(true, 2);
174         widthED->setText("100");
175         widthUnitsLC->setCurrentItem(Length::PCW);
176         heightCB->setCheckState(Qt::Checked);
177         heightED->setText("1");
178         for (int j = 0; j < heightUnitsLC->count(); j++) {
179                 if (heightUnitsLC->itemText(j) == qt_("Total Height"))
180                         heightUnitsLC->setCurrentItem(j);
181         }
182 }
183
184
185 void GuiBoxDialog::updateContents()
186 {
187         string type(controller().params().type);
188         for (unsigned int i = 0; i < gui_names_.size(); ++i) {
189                 if (type == ids_[i])
190                         typeCO->setCurrentIndex(i);
191         }
192
193         // default: minipage
194         unsigned int inner_type = 2;
195         if (!controller().params().inner_box)
196                 // none
197                 inner_type = 0;
198         if (controller().params().use_parbox)
199                 // parbox
200                 inner_type = 1;
201         bool frameless = (controller().params().type == "Frameless");
202         setInnerType(frameless, inner_type);
203
204         char c = controller().params().pos;
205         valignCO->setCurrentIndex(string("tcb").find(c, 0));
206         c = controller().params().inner_pos;
207         ialignCO->setCurrentIndex(string("tcbs").find(c, 0));
208         c = controller().params().hor_pos;
209         halignCO->setCurrentIndex(string("lcrs").find(c, 0));
210
211         bool ibox = controller().params().inner_box;
212         valignCO->setEnabled(ibox);
213         ialignCO->setEnabled(ibox);
214         halignCO->setEnabled(!ibox);
215         setSpecial(ibox);
216
217         Length::UNIT default_unit =
218                 (lyxrc.default_papersize > 3) ? Length::CM : Length::IN;
219
220         lengthToWidgets(widthED, widthUnitsLC,
221                 (controller().params().width).asString(), default_unit);
222
223         string const special = controller().params().special;
224         if (!special.empty() && special != "none") {
225                 QString spc;
226                 for (unsigned int i = 0; i < gui_names_spec_.size(); i++) {
227                         if (special == ids_spec_[i])
228                                 spc = toqstr(gui_names_spec_[i].c_str());
229                 }
230                 for (int j = 0; j < widthUnitsLC->count(); j++) {
231                         if (widthUnitsLC->itemText(j) == spc)
232                                 widthUnitsLC->setCurrentIndex(j);
233                 }
234         }
235
236         lengthToWidgets(heightED, heightUnitsLC,
237                 (controller().params().height).asString(), default_unit);
238
239         string const height_special = controller().params().height_special;
240         if (!height_special.empty() && height_special != "none") {
241                 QString hspc;
242                 for (unsigned int i = 0; i < gui_names_spec_.size(); i++) {
243                         if (height_special == ids_spec_[i]) {
244                                 hspc = toqstr(gui_names_spec_[i].c_str());
245                         }
246                 }
247                 for (int j = 0; j < heightUnitsLC->count(); j++) {
248                         if (heightUnitsLC->itemText(j) == hspc) {
249                                 heightUnitsLC->setCurrentIndex(j);
250                         }
251                 }
252         }
253         heightCB->setEnabled(ibox);
254 }
255
256
257 void GuiBoxDialog::applyView()
258 {
259         controller().params().type =
260                 ids_[typeCO->currentIndex()];
261
262         controller().params().inner_box =
263                 innerBoxCO->currentText() != qt_("None");
264         controller().params().use_parbox =
265                 innerBoxCO->currentText() ==  qt_("Parbox");
266
267         controller().params().pos =
268                 "tcb"[valignCO->currentIndex()];
269         controller().params().inner_pos =
270                 "tcbs"[ialignCO->currentIndex()];
271         controller().params().hor_pos =
272                 "lcrs"[halignCO->currentIndex()];
273
274         int i = 0;
275         bool spec = false;
276         QString special = widthUnitsLC->currentText();
277         QString value = widthED->text();
278         if (special == qt_("Height")) {
279                 i = 1;
280                 spec = true;
281         } else if (special == qt_("Depth")) {
282                 i = 2;
283                 spec = true;
284         } else if (special == qt_("Total Height")) {
285                 i = 3;
286                 spec = true;
287         } else if (special == qt_("Width")) {
288                 i = 4;
289                 spec = true;
290         }
291         // the user might insert a non-special value in the line edit
292         if (isValidLength(fromqstr(value))) {
293                 i = 0;
294                 spec = false;
295         }
296         controller().params().special = ids_spec_[i];
297
298         string width;
299         if (spec) {
300                 width = fromqstr(value);
301                 // beware: bogosity! the unit is simply ignored in this case
302                 width += "in";
303         } else
304                 width = widgetsToLength(widthED, widthUnitsLC);
305
306         controller().params().width = Length(width);
307
308         i = 0;
309         spec = false;
310         special = heightUnitsLC->currentText();
311         value = heightED->text();
312         if (special == qt_("Height")) {
313                 i = 1;
314                 spec = true;
315         } else if (special == qt_("Depth")) {
316                 i = 2;
317                 spec = true;
318         } else if (special == qt_("Total Height")) {
319                 i = 3;
320                 spec = true;
321         } else if (special == qt_("Width")) {
322                 i = 4;
323                 spec = true;
324         }
325         // the user might insert a non-special value in the line edit
326         if (isValidLength(fromqstr(value))) {
327                 i = 0;
328                 spec = false;
329         }
330         controller().params().height_special = ids_spec_[i];
331
332         string height;
333         if (spec  && !isValidLength(fromqstr(heightED->text()))) {
334                 height = fromqstr(value);
335                 // beware: bogosity! the unit is simply ignored in this case
336                 height += "in";
337         } else
338                 height = widgetsToLength(heightED, heightUnitsLC);
339
340         // the height parameter is omitted in InsetBox.cpp when the value
341         // is "1in" and "Total Height" is used as unit.
342         // 1in + "Total Height" means "1\height" which is the LaTeX default when
343         // no height is given
344         if (heightCB->checkState() == Qt::Checked)
345                 controller().params().height = Length(height);
346         else {
347                 controller().params().height = Length("1in");
348                 controller().params().height_special = ids_spec_[3];
349         }
350 }
351
352
353 void GuiBoxDialog::setSpecial(bool ibox)
354 {
355         box_gui_tokens_special_length(ids_spec_, gui_names_spec_);
356         // check if the widget contains the special units
357         int count = widthUnitsLC->count();
358         bool has_special = false;
359         for (int i = 0; i < count; i++)
360                 if (widthUnitsLC->itemText(i).contains(qt_("Total Height")) > 0)
361                         has_special = true;
362         // insert 'em if needed...
363         if (!ibox && !has_special) {
364                 for (unsigned int i = 1; i < gui_names_spec_.size(); i++)
365                         widthUnitsLC->addItem(toqstr(gui_names_spec_[i]));
366         // ... or remove 'em if needed
367         } else if (ibox && has_special) {
368                 widthUnitsLC->clear();
369                 for (int i = 0; i < num_units; i++)
370                         widthUnitsLC->addItem(qt_(unit_name_gui[i]));
371         }
372 }
373
374
375 void GuiBoxDialog::setInnerType(bool frameless, int i)
376 {
377         // with "frameless" boxes, inner box is mandatory (i.e. is the actual box)
378         // we have to remove "none" then and adjust the combo
379         if (frameless) {
380                 innerBoxCO->clear();
381                 innerBoxCO->addItem(qt_("Parbox"));
382                 innerBoxCO->addItem(qt_("Minipage"));
383                 if (i != 0)
384                         innerBoxCO->setCurrentIndex(i - 1);
385                 else
386                         innerBoxCO->setCurrentIndex(i);
387         } else {
388                 if (innerBoxCO->count() == 2)
389                         ++i;
390                 innerBoxCO->clear();
391                 innerBoxCO->addItem(qt_("None"));
392                 innerBoxCO->addItem(qt_("Parbox"));
393                 innerBoxCO->addItem(qt_("Minipage"));
394                 innerBoxCO->setCurrentIndex(i);
395         }
396 }
397
398 } // namespace frontend
399 } // namespace lyx
400
401
402 #include "GuiBox_moc.cpp"