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