2 * \file GuiExternal.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Angus Leeming
9 * Full author contact details are available in file CREDITS.
14 #include "GuiExternal.h"
16 #include "ControlExternal.h"
17 #include "lengthcommon.h"
20 #include "insets/ExternalTemplate.h"
21 #include "insets/InsetExternal.h"
23 #include "support/lstrings.h"
24 #include "support/convert.h"
25 #include "support/os.h"
26 #include "support/lyxlib.h"
28 #include "LengthCombo.h"
29 #include "qt_helpers.h"
30 #include "Validator.h"
32 #include <QCloseEvent>
35 #include <QPushButton>
37 #include <QTextBrowser>
39 namespace external = lyx::external;
41 using lyx::support::isStrDbl;
42 using lyx::support::token;
43 using lyx::support::trim;
44 using lyx::support::float_equal;
46 using lyx::support::os::internal_path;
55 GuiExternalDialog::GuiExternalDialog(LyXView & lv)
56 : GuiDialog(lv, "external")
59 setViewTitle(_("External Material"));
60 setController(new ControlExternal(*this));
62 connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
63 connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
64 connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
66 connect(displayCB, SIGNAL(toggled(bool)),
67 showCO, SLOT(setEnabled(bool)));
68 connect(displayCB, SIGNAL(toggled(bool)),
69 displayscaleED, SLOT(setEnabled(bool)));
70 connect(showCO, SIGNAL(activated(const QString&)),
71 this, SLOT(change_adaptor()));
72 connect(originCO, SIGNAL(activated(int)),
73 this, SLOT(change_adaptor()));
74 connect(aspectratioCB, SIGNAL(stateChanged(int)),
75 this, SLOT(change_adaptor()));
76 connect(browsePB, SIGNAL(clicked()),
77 this, SLOT(browseClicked()));
78 connect(editPB, SIGNAL(clicked()),
79 this, SLOT(editClicked()));
80 connect(externalCO, SIGNAL(activated(const QString &)),
81 this, SLOT(templateChanged()));
82 connect(extraED, SIGNAL(textChanged(const QString &)),
83 this, SLOT(extraChanged(const QString&)));
84 connect(extraFormatCO, SIGNAL(activated(const QString &)),
85 this, SLOT(formatChanged(const QString&)));
86 connect(widthUnitCO, SIGNAL(activated(int)),
87 this, SLOT(widthUnitChanged()));
88 connect(heightUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
89 this, SLOT(change_adaptor()));
90 connect(displayCB, SIGNAL(stateChanged(int)),
91 this, SLOT(change_adaptor()));
92 connect(displayscaleED, SIGNAL(textChanged(const QString &)),
93 this, SLOT(change_adaptor()));
94 connect(angleED, SIGNAL(textChanged(const QString &)),
95 this, SLOT(change_adaptor()));
96 connect(widthED, SIGNAL(textChanged(const QString &)),
97 this, SLOT(sizeChanged()));
98 connect(heightED, SIGNAL(textChanged(const QString &)),
99 this, SLOT(sizeChanged()));
100 connect(fileED, SIGNAL(textChanged(const QString &)),
101 this, SLOT(change_adaptor()));
102 connect(clipCB, SIGNAL(stateChanged(int)),
103 this, SLOT(change_adaptor()));
104 connect(getbbPB, SIGNAL(clicked()), this, SLOT(getbbClicked()));
105 connect(xrED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
106 connect(ytED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
107 connect(xlED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
108 connect(ybED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
109 connect(draftCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
111 QIntValidator * validator = new QIntValidator(displayscaleED);
112 validator->setBottom(1);
113 displayscaleED->setValidator(validator);
115 angleED->setValidator(new QDoubleValidator(-360, 360, 2, angleED));
117 xlED->setValidator(new QIntValidator(xlED));
118 ybED->setValidator(new QIntValidator(ybED));
119 xrED->setValidator(new QIntValidator(xrED));
120 ytED->setValidator(new QIntValidator(ytED));
122 widthED->setValidator(unsignedLengthValidator(widthED));
123 heightED->setValidator(unsignedLengthValidator(heightED));
125 setFocusProxy(fileED);
127 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
130 bc().setApply(applyPB);
131 bc().setCancel(closePB);
133 bc().addReadOnly(fileED);
134 bc().addReadOnly(browsePB);
135 bc().addReadOnly(editPB);
136 bc().addReadOnly(externalCO);
137 bc().addReadOnly(draftCB);
138 bc().addReadOnly(displayscaleED);
139 bc().addReadOnly(showCO);
140 bc().addReadOnly(displayCB);
141 bc().addReadOnly(angleED);
142 bc().addReadOnly(originCO);
143 bc().addReadOnly(heightUnitCO);
144 bc().addReadOnly(heightED);
145 bc().addReadOnly(aspectratioCB);
146 bc().addReadOnly(widthUnitCO);
147 bc().addReadOnly(widthED);
148 bc().addReadOnly(clipCB);
149 bc().addReadOnly(getbbPB);
150 bc().addReadOnly(ytED);
151 bc().addReadOnly(xlED);
152 bc().addReadOnly(xrED);
153 bc().addReadOnly(ybED);
154 bc().addReadOnly(extraFormatCO);
155 bc().addReadOnly(extraED);
157 bc().addCheckedLineEdit(angleED, angleLA);
158 bc().addCheckedLineEdit(displayscaleED, scaleLA);
159 bc().addCheckedLineEdit(heightED, heightLA);
160 bc().addCheckedLineEdit(widthED, widthLA);
161 bc().addCheckedLineEdit(xlED, lbLA);
162 bc().addCheckedLineEdit(ybED, lbLA);
163 bc().addCheckedLineEdit(xrED, rtLA);
164 bc().addCheckedLineEdit(ytED, rtLA);
165 bc().addCheckedLineEdit(fileED, fileLA);
167 std::vector<string> templates(controller().getTemplates());
169 for (std::vector<string>::const_iterator cit = templates.begin();
170 cit != templates.end(); ++cit) {
171 externalCO->addItem(qt_(*cit));
174 // Fill the origins combo
175 typedef vector<external::RotationDataType> Origins;
176 Origins const & all_origins = external::all_origins();
177 for (Origins::size_type i = 0; i != all_origins.size(); ++i)
178 originCO->addItem(toqstr(external::origin_gui_str(i)));
180 // Fill the width combo
181 widthUnitCO->addItem(qt_("Scale%"));
182 for (int i = 0; i < num_units; i++)
183 widthUnitCO->addItem(qt_(unit_name_gui[i]));
187 ControlExternal & GuiExternalDialog::controller()
189 return static_cast<ControlExternal &>(GuiDialog::controller());
193 bool GuiExternalDialog::activateAspectratio() const
195 if (widthUnitCO->currentIndex() == 0)
198 string const wstr = fromqstr(widthED->text());
201 bool const wIsDbl = isStrDbl(wstr);
202 if (wIsDbl && float_equal(convert<double>(wstr), 0.0, 0.05))
205 if (!wIsDbl && (!isValidLength(wstr, &l) || l.zero()))
208 string const hstr = fromqstr(heightED->text());
211 bool const hIsDbl = isStrDbl(hstr);
212 if (hIsDbl && float_equal(convert<double>(hstr), 0.0, 0.05))
214 if (!hIsDbl && (!isValidLength(hstr, &l) || l.zero()))
221 void GuiExternalDialog::bbChanged()
223 controller().bbChanged(true);
228 void GuiExternalDialog::browseClicked()
230 int const choice = externalCO->currentIndex();
231 docstring const template_name =
232 from_utf8(controller().getTemplate(choice).lyxName);
233 docstring const str =
234 controller().browse(qstring_to_ucs4(fileED->text()),
237 fileED->setText(toqstr(str));
243 void GuiExternalDialog::change_adaptor()
249 void GuiExternalDialog::closeEvent(QCloseEvent * e)
256 void GuiExternalDialog::editClicked()
258 controller().editExternal();
263 void GuiExternalDialog::extraChanged(const QString& text)
265 std::string const format = fromqstr(extraFormatCO->currentText());
266 extra_[format] = text;
271 void GuiExternalDialog::formatChanged(const QString& format)
273 extraED->setText(extra_[fromqstr(format)]);
277 void GuiExternalDialog::getbbClicked()
283 void GuiExternalDialog::sizeChanged()
285 aspectratioCB->setEnabled(activateAspectratio());
290 void GuiExternalDialog::templateChanged()
297 void GuiExternalDialog::widthUnitChanged()
299 bool useHeight = (widthUnitCO->currentIndex() > 0);
302 widthED->setValidator(unsignedLengthValidator(widthED));
304 widthED->setValidator(new QDoubleValidator(0, 1000, 2, widthED));
306 heightED->setEnabled(useHeight);
307 heightUnitCO->setEnabled(useHeight);
315 Length::UNIT defaultUnit()
317 Length::UNIT default_unit = Length::CM;
318 switch (lyxrc.default_papersize) {
321 case PAPER_USEXECUTIVE:
322 default_unit = Length::IN;
331 void setDisplay(QCheckBox & displayCB, QComboBox & showCO, QLineEdit & scaleED,
332 external::DisplayType display, unsigned int scale,
337 case external::DefaultDisplay:
340 case external::MonochromeDisplay:
343 case external::GrayscaleDisplay:
346 case external::ColorDisplay:
349 case external::PreviewDisplay:
352 case external::NoDisplay:
357 showCO.setCurrentIndex(item);
358 bool const no_display = display == external::NoDisplay;
359 showCO.setEnabled(!no_display && !read_only);
360 displayCB.setChecked(!no_display);
361 scaleED.setEnabled(!no_display && !read_only);
362 scaleED.setText(QString::number(scale));
366 void getDisplay(external::DisplayType & display,
367 unsigned int & scale,
368 QCheckBox const & displayCB,
369 QComboBox const & showCO,
370 QLineEdit const & scaleED)
372 switch (showCO.currentIndex()) {
374 display = external::DefaultDisplay;
377 display = external::MonochromeDisplay;
380 display = external::GrayscaleDisplay;
383 display = external::ColorDisplay;
386 display = external::PreviewDisplay;
390 if (!displayCB.isChecked())
391 display = external::NoDisplay;
393 scale = scaleED.text().toInt();
397 void setRotation(QLineEdit & angleED, QComboBox & originCO,
398 external::RotationData const & data)
400 originCO.setCurrentIndex(int(data.origin()));
401 angleED.setText(toqstr(data.angle));
405 void getRotation(external::RotationData & data,
406 QLineEdit const & angleED, QComboBox const & originCO)
408 typedef external::RotationData::OriginType OriginType;
410 data.origin(static_cast<OriginType>(originCO.currentIndex()));
411 data.angle = fromqstr(angleED.text());
415 void setSize(QLineEdit & widthED, QComboBox & widthUnitCO,
416 QLineEdit & heightED, LengthCombo & heightUnitCO,
417 QCheckBox & aspectratioCB,
418 external::ResizeData const & data)
420 bool using_scale = data.usingScale();
421 std::string scale = data.scale;
422 if (data.no_resize()) {
423 // Everything is zero, so default to this!
429 widthED.setText(toqstr(scale));
430 widthUnitCO.setCurrentIndex(0);
432 widthED.setText(QString::number(data.width.value()));
433 // Because 'Scale' is position 0...
434 // Note also that width cannot be zero here, so
435 // we don't need to worry about the default unit.
436 widthUnitCO.setCurrentIndex(data.width.unit() + 1);
439 string const h = data.height.zero() ? string() : data.height.asString();
440 Length::UNIT default_unit = data.width.zero() ?
441 defaultUnit() : data.width.unit();
442 lengthToWidgets(&heightED, &heightUnitCO, h, default_unit);
444 heightED.setEnabled(!using_scale);
445 heightUnitCO.setEnabled(!using_scale);
447 aspectratioCB.setChecked(data.keepAspectRatio);
449 bool const disable_aspectRatio = using_scale ||
450 data.width.zero() || data.height.zero();
451 aspectratioCB.setEnabled(!disable_aspectRatio);
455 void getSize(external::ResizeData & data,
456 QLineEdit const & widthED, QComboBox const & widthUnitCO,
457 QLineEdit const & heightED, LengthCombo const & heightUnitCO,
458 QCheckBox const & aspectratioCB)
460 string const width = fromqstr(widthED.text());
462 if (widthUnitCO.currentIndex() > 0) {
463 // Subtract one, because scale is 0.
464 int const unit = widthUnitCO.currentIndex() - 1;
467 if (isValidLength(width, &w))
469 else if (isStrDbl(width))
470 data.width = Length(convert<double>(width),
471 static_cast<Length::UNIT>(unit));
473 data.width = Length();
475 data.scale = string();
478 // scaling instead of a width
480 data.width = Length();
483 data.height = Length(widgetsToLength(&heightED, &heightUnitCO));
485 data.keepAspectRatio = aspectratioCB.isChecked();
489 void setCrop(QCheckBox & clipCB,
490 QLineEdit & xlED, QLineEdit & ybED,
491 QLineEdit & xrED, QLineEdit & ytED,
492 external::ClipData const & data)
494 clipCB.setChecked(data.clip);
495 graphics::BoundingBox const & bbox = data.bbox;
496 xlED.setText(QString::number(bbox.xl));
497 ybED.setText(QString::number(bbox.yb));
498 xrED.setText(QString::number(bbox.xr));
499 ytED.setText(QString::number(bbox.yt));
503 void getCrop(external::ClipData & data,
504 QCheckBox const & clipCB,
505 QLineEdit const & xlED, QLineEdit const & ybED,
506 QLineEdit const & xrED, QLineEdit const & ytED,
509 data.clip = clipCB.isChecked();
514 data.bbox.xl = xlED.text().toInt();
515 data.bbox.yb = ybED.text().toInt();
516 data.bbox.xr = xrED.text().toInt();
517 data.bbox.yt = ytED.text().toInt();
521 void getExtra(external::ExtraData & data,
522 GuiExternalDialog::MapType const & extra)
524 typedef GuiExternalDialog::MapType MapType;
525 MapType::const_iterator it = extra.begin();
526 MapType::const_iterator const end = extra.end();
527 for (; it != end; ++it)
528 data.set(it->first, trim(fromqstr(it->second)));
535 void GuiExternalDialog::updateContents()
537 tab->setCurrentIndex(0);
538 InsetExternalParams const & params = controller().params();
541 params.filename.outputFilename(controller().bufferFilepath());
542 fileED->setText(toqstr(name));
544 externalCO->setCurrentIndex(
545 controller().getTemplateNumber(params.templatename()));
548 draftCB->setChecked(params.draft);
550 setDisplay(*displayCB, *showCO,
552 params.display, params.lyxscale, controller().isBufferReadonly());
554 setRotation(*angleED, *originCO, params.rotationdata);
556 setSize(*widthED, *widthUnitCO,
557 *heightED, *heightUnitCO,
565 controller().bbChanged(!params.clipdata.bbox.empty());
571 void GuiExternalDialog::updateTemplate()
573 external::Template templ =
574 controller().getTemplate(externalCO->currentIndex());
575 externalTB->setPlainText(qt_(templ.helpText));
577 // Ascertain which (if any) transformations the template supports
578 // and disable tabs hosting unsupported transforms.
579 typedef vector<external::TransformID> TransformIDs;
580 TransformIDs const transformIds = templ.transformIds;
581 TransformIDs::const_iterator tr_begin = transformIds.begin();
582 TransformIDs::const_iterator const tr_end = transformIds.end();
584 bool found = std::find(tr_begin, tr_end, external::Rotate) != tr_end;
585 tab->setTabEnabled(tab->indexOf(rotatetab), found);
586 found = std::find(tr_begin, tr_end, external::Resize) != tr_end;
587 tab->setTabEnabled(tab->indexOf(scaletab), found);
589 found = std::find(tr_begin, tr_end, external::Clip) != tr_end;
590 tab->setTabEnabled(tab->indexOf(croptab), found);
592 found = std::find(tr_begin, tr_end, external::Extra) != tr_end;
593 tab->setTabEnabled(tab->indexOf(optionstab), found);
598 // Ascertain whether the template has any formats supporting
599 // the 'Extra' option
602 extraFormatCO->clear();
604 external::Template::Formats::const_iterator it = templ.formats.begin();
605 external::Template::Formats::const_iterator end = templ.formats.end();
606 for (; it != end; ++it) {
607 if (it->second.option_transformers.find(external::Extra) ==
608 it->second.option_transformers.end())
610 string const format = it->first;
611 string const opt = controller().params().extradata.get(format);
612 extraFormatCO->addItem(toqstr(format));
613 extra_[format] = toqstr(opt);
616 bool const enabled = extraFormatCO->count() > 0;
619 tab->indexOf(optionstab), enabled);
620 extraED->setEnabled(enabled && !controller().isBufferReadonly());
621 extraFormatCO->setEnabled(enabled);
624 extraFormatCO->setCurrentIndex(0);
625 extraED->setText(extra_[fromqstr(extraFormatCO->currentText())]);
630 void GuiExternalDialog::applyView()
632 InsetExternalParams params = controller().params();
634 params.filename.set(internal_path(fromqstr(fileED->text())),
635 controller().bufferFilepath());
637 params.settemplate(controller().getTemplate(
638 externalCO->currentIndex()).lyxName);
640 params.draft = draftCB->isChecked();
642 getDisplay(params.display, params.lyxscale,
646 if (tab->isTabEnabled(tab->indexOf(rotatetab)))
647 getRotation(params.rotationdata, *angleED, *originCO);
649 if (tab->isTabEnabled(tab->indexOf(scaletab)))
650 getSize(params.resizedata, *widthED, *widthUnitCO,
651 *heightED, *heightUnitCO, *aspectratioCB);
653 if (tab->isTabEnabled(tab->indexOf(croptab)))
654 getCrop(params.clipdata, *clipCB, *xlED, *ybED,
655 *xrED, *ytED, controller().bbChanged());
657 if (tab->isTabEnabled(tab->indexOf(optionstab)))
658 getExtra(params.extradata, extra_);
660 controller().setParams(params);
664 void GuiExternalDialog::getBB()
671 string const filename = fromqstr(fileED->text());
672 if (filename.empty())
675 string const bb = controller().readBB(filename);
679 xlED->setText(toqstr(token(bb, ' ', 0)));
680 ybED->setText(toqstr(token(bb, ' ', 1)));
681 xrED->setText(toqstr(token(bb, ' ', 2)));
682 ytED->setText(toqstr(token(bb, ' ', 3)));
684 controller().bbChanged(false);
687 } // namespace frontend
690 #include "GuiExternal_moc.cpp"