]> git.lyx.org Git - lyx.git/blob - src/frontends/qt2/QExternal.C
Minipage is no more (long live the box inset)
[lyx.git] / src / frontends / qt2 / QExternal.C
1 /**
2  * \file QExternal.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 Angus Leeming
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "debug.h"
15 #include "lengthcommon.h"
16 #include "lyxrc.h"
17
18 #include "controllers/ControlExternal.h"
19
20 #include "insets/ExternalTemplate.h"
21 #include "insets/insetexternal.h"
22
23 #include "support/lstrings.h"
24 #include "support/tostr.h"
25
26 #include "QExternal.h"
27 #include "QExternalDialog.h"
28 #include "Qt2BC.h"
29
30 #include "checkedwidgets.h"
31 #include "lengthcombo.h"
32 #include "qt_helpers.h"
33
34 #include <qlineedit.h>
35 #include <qpushbutton.h>
36 #include <qcheckbox.h>
37 #include <qcombobox.h>
38 #include <qtabwidget.h>
39 #include <qtextview.h>
40
41 namespace external = lyx::external;
42
43 using lyx::support::isStrDbl;
44 using lyx::support::strToDbl;
45 using lyx::support::strToInt;
46 using lyx::support::token;
47 using lyx::support::trim;
48
49 using std::string;
50 using std::vector;
51 using std::find;
52
53
54 namespace {
55
56 LyXLength::UNIT defaultUnit()
57 {
58         LyXLength::UNIT default_unit = LyXLength::CM;
59         switch (lyxrc.default_papersize) {
60         case PAPER_USLETTER:
61         case PAPER_LEGALPAPER:
62         case PAPER_EXECUTIVEPAPER:
63                 default_unit = LyXLength::IN;
64                 break;
65         default:
66                 break;
67         }
68         return default_unit;
69 }
70
71
72 void setDisplay(QCheckBox & displayCB, QComboBox & showCO, QLineEdit & scaleED,
73                 external::DisplayType display, unsigned int scale,
74                 bool read_only)
75 {
76         int item = 0;
77         switch (display) {
78         case external::DefaultDisplay:
79                 item = 0;
80                 break;
81         case external::MonochromeDisplay:
82                 item = 1;
83                 break;
84         case external::GrayscaleDisplay:
85                 item = 2;
86                 break;
87         case external::ColorDisplay:
88                 item = 3;
89                 break;
90         case external::PreviewDisplay:
91                 item = 4;
92                 break;
93         case external::NoDisplay:
94                 item = 0;
95                 break;
96         }
97
98         showCO.setCurrentItem(item);
99         bool const no_display = display == lyx::external::NoDisplay;
100         showCO.setEnabled(!no_display && !read_only);
101         displayCB.setChecked(!no_display);
102         scaleED.setEnabled(!no_display && !read_only);
103         scaleED.setText(toqstr(tostr(scale)));
104 }
105
106
107 void getDisplay(external::DisplayType & display,
108                 unsigned int & scale,
109                 QCheckBox const & displayCB,
110                 QComboBox const & showCO,
111                 QLineEdit const & scaleED)
112 {
113         switch (showCO.currentItem()) {
114         case 0:
115                 display = external::DefaultDisplay;
116                 break;
117         case 1:
118                 display = external::MonochromeDisplay;
119                 break;
120         case 2:
121                 display = external::GrayscaleDisplay;
122                 break;
123         case 3:
124                 display = external::ColorDisplay;
125                 break;
126         case 4:
127                 display = external::PreviewDisplay;
128                 break;
129         }
130
131         if (!displayCB.isChecked())
132                 display = external::NoDisplay;
133
134         scale = strToInt(fromqstr(scaleED.text()));
135 }
136
137
138 void setRotation(QLineEdit & angleED, QComboBox & originCO,
139                  external::RotationData const & data)
140 {
141         originCO.setCurrentItem(int(data.origin()));
142         angleED.setText(toqstr(tostr(data.angle())));
143 }
144
145
146 void getRotation(external::RotationData & data,
147                  QLineEdit const & angleED, QComboBox const & originCO)
148 {
149         typedef external::RotationData::OriginType OriginType;
150
151         data.origin(static_cast<OriginType>(originCO.currentItem()));
152         data.angle(strToDbl(fromqstr(angleED.text())));
153 }
154
155
156 void setSize(QLineEdit & widthED, QComboBox & widthUnitCO,
157              QLineEdit & heightED, LengthCombo & heightUnitCO,
158              QCheckBox & aspectratioCB,
159              external::ResizeData const & data)
160 {
161         bool using_scale = data.usingScale();
162         double scale =  data.scale;
163         if (data.no_resize()) {
164                 // Everything is zero, so default to this!
165                 using_scale = true;
166                 scale = 100;
167         }
168
169         if (using_scale) {
170                 widthED.setText(toqstr(tostr(scale)));
171                 widthUnitCO.setCurrentItem(0);
172         } else {
173                 widthED.setText(toqstr(tostr(data.width.value())));
174                 // Because 'Scale' is position 0...
175                 // Note also that width cannot be zero here, so
176                 // we don't need to worry about the default unit.
177                 widthUnitCO.setCurrentItem(data.width.unit() + 1);
178         }
179
180         string const h = data.height.zero() ? string() : data.height.asString();
181         LyXLength::UNIT default_unit = data.width.zero() ?
182                 defaultUnit() : data.width.unit();
183         lengthToWidgets(&heightED, &heightUnitCO, h, default_unit);
184
185         heightED.setEnabled(!using_scale);
186         heightUnitCO.setEnabled(!using_scale);
187
188         aspectratioCB.setChecked(data.keepAspectRatio);
189
190         bool const disable_aspectRatio = using_scale ||
191                 data.width.zero() || data.height.zero();
192         aspectratioCB.setEnabled(!disable_aspectRatio);
193 }
194
195
196 void getSize(external::ResizeData & data,
197              QLineEdit const & widthED, QComboBox const & widthUnitCO,
198              QLineEdit const & heightED, LengthCombo const & heightUnitCO,
199              QCheckBox const & aspectratioCB)
200 {
201         string const width = fromqstr(widthED.text());
202
203         if (widthUnitCO.currentItem() > 0) {
204                 // Subtract one, because scale is 0.
205                 int const unit = widthUnitCO.currentItem() - 1;
206
207                 LyXLength w;
208                 if (isValidLength(width, &w))
209                         data.width = w;
210                 else if (isStrDbl(width))
211                         data.width = LyXLength(strToDbl(width),
212                                            static_cast<LyXLength::UNIT>(unit));
213                 else
214                         data.width = LyXLength();
215
216                 data.scale = 0.0;
217
218         } else {
219                 // scaling instead of a width
220                 data.scale = strToDbl(width);
221                 data.width = LyXLength();
222         }
223
224         data.height = LyXLength(widgetsToLength(&heightED, &heightUnitCO));
225
226         data.keepAspectRatio = aspectratioCB.isChecked();
227 }
228
229
230 void setCrop(QCheckBox & clipCB,
231              QLineEdit & xlED, QLineEdit & ybED,
232              QLineEdit & xrED, QLineEdit & ytED,
233              external::ClipData const & data)
234 {
235         clipCB.setChecked(data.clip);
236         lyx::graphics::BoundingBox const & bbox = data.bbox;
237         xlED.setText(toqstr(tostr(bbox.xl)));
238         ybED.setText(toqstr(tostr(bbox.yb)));
239         xrED.setText(toqstr(tostr(bbox.xr)));
240         ytED.setText(toqstr(tostr(bbox.yt)));
241 }
242
243
244 void getCrop(external::ClipData & data,
245              QCheckBox const & clipCB,
246              QLineEdit const & xlED, QLineEdit const & ybED,
247              QLineEdit const & xrED, QLineEdit const & ytED,
248              bool bb_changed)
249 {
250         data.clip = clipCB.isChecked();
251
252         if (!bb_changed)
253                 return;
254
255         data.bbox.xl = strToInt(fromqstr(xlED.text()));
256         data.bbox.yb = strToInt(fromqstr(ybED.text()));
257         data.bbox.xr = strToInt(fromqstr(xrED.text()));
258         data.bbox.yt = strToInt(fromqstr(ytED.text()));
259 }
260
261
262 void getExtra(external::ExtraData & data,
263               QExternal::MapType const & extra)
264 {
265         typedef QExternal::MapType MapType;
266         MapType::const_iterator it  = extra.begin();
267         MapType::const_iterator const end = extra.end();
268         for (; it != end; ++it)
269                 data.set(it->first, trim(fromqstr(it->second)));
270 }
271
272 } // namespace anon
273
274
275 typedef QController<ControlExternal, QView<QExternalDialog> > base_class;
276
277 QExternal::QExternal(Dialog & parent)
278         : base_class(parent, _("LyX: External Material"))
279 {}
280
281
282 void QExternal::build_dialog()
283 {
284         dialog_.reset(new QExternalDialog(this));
285
286         bcview().setOK(dialog_->okPB);
287         bcview().setApply(dialog_->applyPB);
288         bcview().setCancel(dialog_->closePB);
289
290         bcview().addReadOnly(dialog_->fileED);
291         bcview().addReadOnly(dialog_->browsePB);
292         bcview().addReadOnly(dialog_->editPB);
293         bcview().addReadOnly(dialog_->externalCO);
294         bcview().addReadOnly(dialog_->draftCB);
295         bcview().addReadOnly(dialog_->displayscaleED);
296         bcview().addReadOnly(dialog_->showCO);
297         bcview().addReadOnly(dialog_->displayCB);
298         bcview().addReadOnly(dialog_->angleED);
299         bcview().addReadOnly(dialog_->originCO);
300         bcview().addReadOnly(dialog_->heightUnitCO);
301         bcview().addReadOnly(dialog_->heightED);
302         bcview().addReadOnly(dialog_->aspectratioCB);
303         bcview().addReadOnly(dialog_->widthUnitCO);
304         bcview().addReadOnly(dialog_->widthED);
305         bcview().addReadOnly(dialog_->clipCB);
306         bcview().addReadOnly(dialog_->getbbPB);
307         bcview().addReadOnly(dialog_->ytED);
308         bcview().addReadOnly(dialog_->xlED);
309         bcview().addReadOnly(dialog_->xrED);
310         bcview().addReadOnly(dialog_->ybED);
311         bcview().addReadOnly(dialog_->extraFormatCO);
312         bcview().addReadOnly(dialog_->extraED);
313
314         addCheckedLineEdit(bcview(), dialog_->angleED, dialog_->angleLA);
315         addCheckedLineEdit(bcview(), dialog_->displayscaleED, dialog_->scaleLA);
316         addCheckedLineEdit(bcview(), dialog_->heightED, dialog_->heightLA);
317         addCheckedLineEdit(bcview(), dialog_->widthED, dialog_->widthLA);
318         addCheckedLineEdit(bcview(), dialog_->xlED, dialog_->lbLA);
319         addCheckedLineEdit(bcview(), dialog_->ybED, dialog_->lbLA);
320         addCheckedLineEdit(bcview(), dialog_->xrED, dialog_->rtLA);
321         addCheckedLineEdit(bcview(), dialog_->ytED, dialog_->rtLA);
322
323         std::vector<string> templates(controller().getTemplates());
324
325         for (std::vector<string>::const_iterator cit = templates.begin();
326                 cit != templates.end(); ++cit) {
327                 dialog_->externalCO->insertItem(toqstr(*cit), -1);
328         }
329
330         // Fill the origins combo
331         typedef vector<external::RotationDataType> Origins;
332         Origins const & all_origins = external::all_origins();
333         for (Origins::size_type i = 0; i != all_origins.size(); ++i)
334                 dialog_->originCO->insertItem(toqstr(external::origin_gui_str(i)));
335
336         // Fill the width combo
337         dialog_->widthUnitCO->insertItem(qt_("Scale%"));
338         for (int i = 0; i < num_units; i++)
339                 dialog_->widthUnitCO->insertItem(unit_name_gui[i], -1);
340 }
341
342
343 void QExternal::update_contents()
344 {
345         dialog_->tab->setCurrentPage(0);
346         InsetExternalParams const & params = controller().params();
347
348         string const name =
349                 params.filename.outputFilename(kernel().bufferFilepath());
350         dialog_->fileED->setText(toqstr(name));
351
352         dialog_->externalCO->setCurrentItem(
353                 controller().getTemplateNumber(params.templatename()));
354         updateTemplate();
355
356         dialog_->draftCB->setChecked(params.draft);
357
358         setDisplay(*dialog_->displayCB, *dialog_->showCO,
359                    *dialog_->displayscaleED,
360                    params.display, params.lyxscale, readOnly());
361
362         setRotation(*dialog_->angleED, *dialog_->originCO, params.rotationdata);
363
364         setSize(*dialog_->widthED, *dialog_->widthUnitCO,
365                 *dialog_->heightED, *dialog_->heightUnitCO,
366                 *dialog_->aspectratioCB,
367                 params.resizedata);
368
369         setCrop(*dialog_->clipCB,
370                 *dialog_->xlED, *dialog_->ybED,
371                 *dialog_->xrED, *dialog_->ytED,
372                 params.clipdata);
373         controller().bbChanged(!params.clipdata.bbox.empty());
374
375         isValid();
376 }
377
378
379 void QExternal::updateTemplate()
380 {
381         external::Template templ =
382                 controller().getTemplate(dialog_->externalCO->currentItem());
383         dialog_->externalTV->setText(toqstr(templ.helpText));
384
385         // Ascertain which (if any) transformations the template supports
386         // and disable tabs hosting unsupported transforms.
387         typedef vector<external::TransformID> TransformIDs;
388         TransformIDs const transformIds = templ.transformIds;
389         TransformIDs::const_iterator tr_begin = transformIds.begin();
390         TransformIDs::const_iterator const tr_end = transformIds.end();
391
392         bool found = find(tr_begin, tr_end, external::Rotate) != tr_end;
393         dialog_->tab->setTabEnabled(dialog_->rotatetab, found);
394
395         found = find(tr_begin, tr_end, external::Resize) != tr_end;
396         dialog_->tab->setTabEnabled(dialog_->scaletab, found);
397
398         found = find(tr_begin, tr_end, external::Clip) != tr_end;
399         dialog_->tab->setTabEnabled(dialog_->croptab, found);
400
401         found = find(tr_begin, tr_end, external::Extra) != tr_end;
402         dialog_->tab->setTabEnabled(dialog_->optionstab, found);
403         if (!found)
404                 return;
405
406         // Ascertain whether the template has any formats supporting
407         // the 'Extra' option
408         QLineEdit * const extraED = dialog_->extraED;
409         QComboBox * const extraCB = dialog_->extraFormatCO;
410
411         extra_.clear();
412         extraED->clear();
413         extraCB->clear();
414
415         external::Template::Formats::const_iterator it  = templ.formats.begin();
416         external::Template::Formats::const_iterator end = templ.formats.end();
417         for (; it != end; ++it) {
418                 if (it->second.option_transformers.find(external::Extra) ==
419                     it->second.option_transformers.end())
420                         continue;
421                 string const format = it->first;
422                 string const opt = controller().params().extradata.get(format);
423                 extraCB->insertItem(toqstr(format));
424                 extra_[format] = toqstr(opt);
425         }
426
427         bool const enabled = extraCB->count()  > 0;
428
429         dialog_->tab->setTabEnabled(dialog_->optionstab, enabled);
430         extraED->setEnabled(enabled && !kernel().isBufferReadonly());
431         extraCB->setEnabled(enabled);
432
433         if (enabled) {
434                 extraCB->setCurrentItem(0);
435                 extraED->setText(extra_[fromqstr(extraCB->currentText())]);
436         }
437 }
438
439
440 void QExternal::apply()
441 {
442         InsetExternalParams params = controller().params();
443
444         params.filename.set(fromqstr(dialog_->fileED->text()),
445                             kernel().bufferFilepath());
446
447         params.settemplate(controller().getTemplate(
448                                    dialog_->externalCO->currentItem()).lyxName);
449
450         params.draft = dialog_->draftCB->isChecked();
451
452         getDisplay(params.display, params.lyxscale,
453                    *dialog_->displayCB, *dialog_->showCO,
454                    *dialog_->displayscaleED);
455
456         if (dialog_->tab->isTabEnabled(dialog_->rotatetab))
457                 getRotation(params.rotationdata,
458                             *dialog_->angleED, *dialog_->originCO);
459
460         if (dialog_->tab->isTabEnabled(dialog_->scaletab))
461                 getSize(params.resizedata,
462                         *dialog_->widthED, *dialog_->widthUnitCO,
463                         *dialog_->heightED, *dialog_->heightUnitCO,
464                         *dialog_->aspectratioCB);
465
466         if (dialog_->tab->isTabEnabled(dialog_->croptab))
467                 getCrop(params.clipdata,
468                         *dialog_->clipCB,
469                         *dialog_->xlED, *dialog_->ybED,
470                         *dialog_->xrED, *dialog_->ytED,
471                         controller().bbChanged());
472
473         if (dialog_->tab->isTabEnabled(dialog_->optionstab))
474                 getExtra(params.extradata, extra_);
475
476         controller().setParams(params);
477 }
478
479
480 void QExternal::getBB()
481 {
482         dialog_->xlED->setText("0");
483         dialog_->ybED->setText("0");
484         dialog_->xrED->setText("0");
485         dialog_->ytED->setText("0");
486
487         string const filename = fromqstr(dialog_->fileED->text());
488         if (filename.empty())
489                 return;
490
491         string const bb = controller().readBB(filename);
492         if (bb.empty())
493                 return;
494
495         dialog_->xlED->setText(toqstr(token(bb, ' ', 0)));
496         dialog_->ybED->setText(toqstr(token(bb, ' ', 1)));
497         dialog_->xrED->setText(toqstr(token(bb, ' ', 2)));
498         dialog_->ytED->setText(toqstr(token(bb, ' ', 3)));
499
500         controller().bbChanged(false);
501 }