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 "lengthcommon.h"
17 #include "insets/ExternalTemplate.h"
18 #include "insets/InsetExternal.h"
20 #include "support/lstrings.h"
21 #include "support/convert.h"
22 #include "support/os.h"
23 #include "support/lyxlib.h"
25 #include "GuiExternal.h"
27 #include "LengthCombo.h"
28 #include "qt_helpers.h"
29 #include "Validator.h"
32 #include <QPushButton>
35 #include <QTextBrowser>
37 namespace external = lyx::external;
39 using lyx::support::isStrDbl;
40 using lyx::support::token;
41 using lyx::support::trim;
42 using lyx::support::float_equal;
44 using lyx::support::os::internal_path;
54 /////////////////////////////////////////////////////////////////////
58 /////////////////////////////////////////////////////////////////////
61 GuiExternalDialog::GuiExternalDialog(GuiExternal * form)
65 connect(okPB, SIGNAL(clicked()), form, SLOT(slotOK()));
66 connect(applyPB, SIGNAL(clicked()), form, SLOT(slotApply()));
67 connect(closePB, SIGNAL(clicked()), form, SLOT(slotClose()));
69 connect(displayCB, SIGNAL(toggled(bool)),
70 showCO, SLOT(setEnabled(bool)));
71 connect(displayCB, SIGNAL(toggled(bool)),
72 displayscaleED, SLOT(setEnabled(bool)));
73 connect(showCO, SIGNAL(activated(const QString&)),
74 this, SLOT(change_adaptor()));
75 connect(originCO, SIGNAL(activated(int)),
76 this, SLOT(change_adaptor()));
77 connect(aspectratioCB, SIGNAL(stateChanged(int)),
78 this, SLOT(change_adaptor()));
79 connect(browsePB, SIGNAL(clicked()),
80 this, SLOT(browseClicked()));
81 connect(editPB, SIGNAL(clicked()),
82 this, SLOT(editClicked()));
83 connect(externalCO, SIGNAL(activated(const QString &)),
84 this, SLOT(templateChanged()));
85 connect(extraED, SIGNAL(textChanged(const QString &)),
86 this, SLOT(extraChanged(const QString&)));
87 connect(extraFormatCO, SIGNAL(activated(const QString &)),
88 this, SLOT(formatChanged(const QString&)));
89 connect(widthUnitCO, SIGNAL(activated(int)),
90 this, SLOT(widthUnitChanged()));
91 connect(heightUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
92 this, SLOT(change_adaptor()));
93 connect(displayCB, SIGNAL(stateChanged(int)),
94 this, SLOT(change_adaptor()));
95 connect(displayscaleED, SIGNAL(textChanged(const QString &)),
96 this, SLOT(change_adaptor()));
97 connect(angleED, SIGNAL(textChanged(const QString &)),
98 this, SLOT(change_adaptor()));
99 connect(widthED, SIGNAL(textChanged(const QString &)),
100 this, SLOT(sizeChanged()));
101 connect(heightED, SIGNAL(textChanged(const QString &)),
102 this, SLOT(sizeChanged()));
103 connect(fileED, SIGNAL(textChanged(const QString &)),
104 this, SLOT(change_adaptor()));
105 connect(clipCB, SIGNAL(stateChanged(int)),
106 this, SLOT(change_adaptor()));
107 connect(getbbPB, SIGNAL(clicked()), this, SLOT(getbbClicked()));
108 connect(xrED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
109 connect(ytED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
110 connect(xlED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
111 connect(ybED, SIGNAL(textChanged(const QString &)), this, SLOT(bbChanged()));
112 connect(draftCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
114 QIntValidator * validator = new QIntValidator(displayscaleED);
115 validator->setBottom(1);
116 displayscaleED->setValidator(validator);
118 angleED->setValidator(new QDoubleValidator(-360, 360, 2, angleED));
120 xlED->setValidator(new QIntValidator(xlED));
121 ybED->setValidator(new QIntValidator(ybED));
122 xrED->setValidator(new QIntValidator(xrED));
123 ytED->setValidator(new QIntValidator(ytED));
125 widthED->setValidator(unsignedLengthValidator(widthED));
126 heightED->setValidator(unsignedLengthValidator(heightED));
128 setFocusProxy(fileED);
132 void GuiExternalDialog::showView()
138 bool GuiExternalDialog::activateAspectratio() const
140 if (widthUnitCO->currentIndex() == 0)
143 string const wstr = fromqstr(widthED->text());
146 bool const wIsDbl = isStrDbl(wstr);
147 if (wIsDbl && float_equal(convert<double>(wstr), 0.0, 0.05))
150 if (!wIsDbl && (!isValidLength(wstr, &l) || l.zero()))
153 string const hstr = fromqstr(heightED->text());
156 bool const hIsDbl = isStrDbl(hstr);
157 if (hIsDbl && float_equal(convert<double>(hstr), 0.0, 0.05))
159 if (!hIsDbl && (!isValidLength(hstr, &l) || l.zero()))
166 void GuiExternalDialog::bbChanged()
168 form_->controller().bbChanged(true);
173 void GuiExternalDialog::browseClicked()
175 int const choice = externalCO->currentIndex();
176 docstring const template_name =
177 from_utf8(form_->controller().getTemplate(choice).lyxName);
178 docstring const str =
179 form_->controller().browse(qstring_to_ucs4(fileED->text()),
182 fileED->setText(toqstr(str));
188 void GuiExternalDialog::change_adaptor()
194 void GuiExternalDialog::closeEvent(QCloseEvent * e)
201 void GuiExternalDialog::editClicked()
203 form_->controller().editExternal();
208 void GuiExternalDialog::extraChanged(const QString& text)
210 std::string const format = fromqstr(extraFormatCO->currentText());
211 form_->extra_[format] = text;
216 void GuiExternalDialog::formatChanged(const QString& format)
218 extraED->setText(form_->extra_[fromqstr(format)]);
222 void GuiExternalDialog::getbbClicked()
228 void GuiExternalDialog::sizeChanged()
230 aspectratioCB->setEnabled(activateAspectratio());
235 void GuiExternalDialog::templateChanged()
237 form_->updateTemplate();
242 void GuiExternalDialog::widthUnitChanged()
244 bool useHeight = (widthUnitCO->currentIndex() > 0);
247 widthED->setValidator(unsignedLengthValidator(widthED));
249 widthED->setValidator(new QDoubleValidator(0, 1000, 2, widthED));
251 heightED->setEnabled(useHeight);
252 heightUnitCO->setEnabled(useHeight);
257 /////////////////////////////////////////////////////////////////////
261 /////////////////////////////////////////////////////////////////////
265 Length::UNIT defaultUnit()
267 Length::UNIT default_unit = Length::CM;
268 switch (lyxrc.default_papersize) {
271 case PAPER_USEXECUTIVE:
272 default_unit = Length::IN;
281 void setDisplay(QCheckBox & displayCB, QComboBox & showCO, QLineEdit & scaleED,
282 external::DisplayType display, unsigned int scale,
287 case external::DefaultDisplay:
290 case external::MonochromeDisplay:
293 case external::GrayscaleDisplay:
296 case external::ColorDisplay:
299 case external::PreviewDisplay:
302 case external::NoDisplay:
307 showCO.setCurrentIndex(item);
308 bool const no_display = display == external::NoDisplay;
309 showCO.setEnabled(!no_display && !read_only);
310 displayCB.setChecked(!no_display);
311 scaleED.setEnabled(!no_display && !read_only);
312 scaleED.setText(toqstr(convert<string>(scale)));
316 void getDisplay(external::DisplayType & display,
317 unsigned int & scale,
318 QCheckBox const & displayCB,
319 QComboBox const & showCO,
320 QLineEdit const & scaleED)
322 switch (showCO.currentIndex()) {
324 display = external::DefaultDisplay;
327 display = external::MonochromeDisplay;
330 display = external::GrayscaleDisplay;
333 display = external::ColorDisplay;
336 display = external::PreviewDisplay;
340 if (!displayCB.isChecked())
341 display = external::NoDisplay;
343 scale = convert<int>(fromqstr(scaleED.text()));
347 void setRotation(QLineEdit & angleED, QComboBox & originCO,
348 external::RotationData const & data)
350 originCO.setCurrentIndex(int(data.origin()));
351 angleED.setText(toqstr(data.angle));
355 void getRotation(external::RotationData & data,
356 QLineEdit const & angleED, QComboBox const & originCO)
358 typedef external::RotationData::OriginType OriginType;
360 data.origin(static_cast<OriginType>(originCO.currentIndex()));
361 data.angle = fromqstr(angleED.text());
365 void setSize(QLineEdit & widthED, QComboBox & widthUnitCO,
366 QLineEdit & heightED, LengthCombo & heightUnitCO,
367 QCheckBox & aspectratioCB,
368 external::ResizeData const & data)
370 bool using_scale = data.usingScale();
371 std::string scale = data.scale;
372 if (data.no_resize()) {
373 // Everything is zero, so default to this!
379 widthED.setText(toqstr(scale));
380 widthUnitCO.setCurrentIndex(0);
382 widthED.setText(toqstr(convert<string>(data.width.value())));
383 // Because 'Scale' is position 0...
384 // Note also that width cannot be zero here, so
385 // we don't need to worry about the default unit.
386 widthUnitCO.setCurrentIndex(data.width.unit() + 1);
389 string const h = data.height.zero() ? string() : data.height.asString();
390 Length::UNIT default_unit = data.width.zero() ?
391 defaultUnit() : data.width.unit();
392 lengthToWidgets(&heightED, &heightUnitCO, h, default_unit);
394 heightED.setEnabled(!using_scale);
395 heightUnitCO.setEnabled(!using_scale);
397 aspectratioCB.setChecked(data.keepAspectRatio);
399 bool const disable_aspectRatio = using_scale ||
400 data.width.zero() || data.height.zero();
401 aspectratioCB.setEnabled(!disable_aspectRatio);
405 void getSize(external::ResizeData & data,
406 QLineEdit const & widthED, QComboBox const & widthUnitCO,
407 QLineEdit const & heightED, LengthCombo const & heightUnitCO,
408 QCheckBox const & aspectratioCB)
410 string const width = fromqstr(widthED.text());
412 if (widthUnitCO.currentIndex() > 0) {
413 // Subtract one, because scale is 0.
414 int const unit = widthUnitCO.currentIndex() - 1;
417 if (isValidLength(width, &w))
419 else if (isStrDbl(width))
420 data.width = Length(convert<double>(width),
421 static_cast<Length::UNIT>(unit));
423 data.width = Length();
425 data.scale = string();
428 // scaling instead of a width
430 data.width = Length();
433 data.height = Length(widgetsToLength(&heightED, &heightUnitCO));
435 data.keepAspectRatio = aspectratioCB.isChecked();
439 void setCrop(QCheckBox & clipCB,
440 QLineEdit & xlED, QLineEdit & ybED,
441 QLineEdit & xrED, QLineEdit & ytED,
442 external::ClipData const & data)
444 clipCB.setChecked(data.clip);
445 graphics::BoundingBox const & bbox = data.bbox;
446 xlED.setText(toqstr(convert<string>(bbox.xl)));
447 ybED.setText(toqstr(convert<string>(bbox.yb)));
448 xrED.setText(toqstr(convert<string>(bbox.xr)));
449 ytED.setText(toqstr(convert<string>(bbox.yt)));
453 void getCrop(external::ClipData & data,
454 QCheckBox const & clipCB,
455 QLineEdit const & xlED, QLineEdit const & ybED,
456 QLineEdit const & xrED, QLineEdit const & ytED,
459 data.clip = clipCB.isChecked();
464 data.bbox.xl = convert<int>(fromqstr(xlED.text()));
465 data.bbox.yb = convert<int>(fromqstr(ybED.text()));
466 data.bbox.xr = convert<int>(fromqstr(xrED.text()));
467 data.bbox.yt = convert<int>(fromqstr(ytED.text()));
471 void getExtra(external::ExtraData & data,
472 GuiExternal::MapType const & extra)
474 typedef GuiExternal::MapType MapType;
475 MapType::const_iterator it = extra.begin();
476 MapType::const_iterator const end = extra.end();
477 for (; it != end; ++it)
478 data.set(it->first, trim(fromqstr(it->second)));
484 GuiExternal::GuiExternal(GuiDialog & parent)
485 : GuiView<GuiExternalDialog>(parent, _("External Material"))
489 void GuiExternal::build_dialog()
491 dialog_.reset(new GuiExternalDialog(this));
493 bc().setOK(dialog_->okPB);
494 bc().setApply(dialog_->applyPB);
495 bc().setCancel(dialog_->closePB);
497 bc().addReadOnly(dialog_->fileED);
498 bc().addReadOnly(dialog_->browsePB);
499 bc().addReadOnly(dialog_->editPB);
500 bc().addReadOnly(dialog_->externalCO);
501 bc().addReadOnly(dialog_->draftCB);
502 bc().addReadOnly(dialog_->displayscaleED);
503 bc().addReadOnly(dialog_->showCO);
504 bc().addReadOnly(dialog_->displayCB);
505 bc().addReadOnly(dialog_->angleED);
506 bc().addReadOnly(dialog_->originCO);
507 bc().addReadOnly(dialog_->heightUnitCO);
508 bc().addReadOnly(dialog_->heightED);
509 bc().addReadOnly(dialog_->aspectratioCB);
510 bc().addReadOnly(dialog_->widthUnitCO);
511 bc().addReadOnly(dialog_->widthED);
512 bc().addReadOnly(dialog_->clipCB);
513 bc().addReadOnly(dialog_->getbbPB);
514 bc().addReadOnly(dialog_->ytED);
515 bc().addReadOnly(dialog_->xlED);
516 bc().addReadOnly(dialog_->xrED);
517 bc().addReadOnly(dialog_->ybED);
518 bc().addReadOnly(dialog_->extraFormatCO);
519 bc().addReadOnly(dialog_->extraED);
521 bc().addCheckedLineEdit(dialog_->angleED, dialog_->angleLA);
522 bc().addCheckedLineEdit(dialog_->displayscaleED, dialog_->scaleLA);
523 bc().addCheckedLineEdit(dialog_->heightED, dialog_->heightLA);
524 bc().addCheckedLineEdit(dialog_->widthED, dialog_->widthLA);
525 bc().addCheckedLineEdit(dialog_->xlED, dialog_->lbLA);
526 bc().addCheckedLineEdit(dialog_->ybED, dialog_->lbLA);
527 bc().addCheckedLineEdit(dialog_->xrED, dialog_->rtLA);
528 bc().addCheckedLineEdit(dialog_->ytED, dialog_->rtLA);
529 bc().addCheckedLineEdit(dialog_->fileED, dialog_->fileLA);
531 std::vector<string> templates(controller().getTemplates());
533 for (std::vector<string>::const_iterator cit = templates.begin();
534 cit != templates.end(); ++cit) {
535 dialog_->externalCO->addItem(qt_(*cit));
538 // Fill the origins combo
539 typedef vector<external::RotationDataType> Origins;
540 Origins const & all_origins = external::all_origins();
541 for (Origins::size_type i = 0; i != all_origins.size(); ++i)
542 dialog_->originCO->addItem(toqstr(external::origin_gui_str(i)));
544 // Fill the width combo
545 dialog_->widthUnitCO->addItem(qt_("Scale%"));
546 for (int i = 0; i < num_units; i++)
547 dialog_->widthUnitCO->addItem(qt_(unit_name_gui[i]));
551 void GuiExternal::update_contents()
553 dialog_->tab->setCurrentIndex(0);
554 InsetExternalParams const & params = controller().params();
557 params.filename.outputFilename(kernel().bufferFilepath());
558 dialog_->fileED->setText(toqstr(name));
560 dialog_->externalCO->setCurrentIndex(
561 controller().getTemplateNumber(params.templatename()));
564 dialog_->draftCB->setChecked(params.draft);
566 setDisplay(*dialog_->displayCB, *dialog_->showCO,
567 *dialog_->displayscaleED,
568 params.display, params.lyxscale, readOnly());
570 setRotation(*dialog_->angleED, *dialog_->originCO, params.rotationdata);
572 setSize(*dialog_->widthED, *dialog_->widthUnitCO,
573 *dialog_->heightED, *dialog_->heightUnitCO,
574 *dialog_->aspectratioCB,
577 setCrop(*dialog_->clipCB,
578 *dialog_->xlED, *dialog_->ybED,
579 *dialog_->xrED, *dialog_->ytED,
581 controller().bbChanged(!params.clipdata.bbox.empty());
587 void GuiExternal::updateTemplate()
589 external::Template templ =
590 controller().getTemplate(dialog_->externalCO->currentIndex());
591 dialog_->externalTB->setPlainText(qt_(templ.helpText));
593 // Ascertain which (if any) transformations the template supports
594 // and disable tabs hosting unsupported transforms.
595 typedef vector<external::TransformID> TransformIDs;
596 TransformIDs const transformIds = templ.transformIds;
597 TransformIDs::const_iterator tr_begin = transformIds.begin();
598 TransformIDs::const_iterator const tr_end = transformIds.end();
600 bool found = find(tr_begin, tr_end, external::Rotate) != tr_end;
601 dialog_->tab->setTabEnabled(
602 dialog_->tab->indexOf(dialog_->rotatetab), found);
603 found = find(tr_begin, tr_end, external::Resize) != tr_end;
604 dialog_->tab->setTabEnabled(
605 dialog_->tab->indexOf(dialog_->scaletab), found);
607 found = find(tr_begin, tr_end, external::Clip) != tr_end;
608 dialog_->tab->setTabEnabled(
609 dialog_->tab->indexOf(dialog_->croptab), found);
611 found = find(tr_begin, tr_end, external::Extra) != tr_end;
612 dialog_->tab->setTabEnabled(
613 dialog_->tab->indexOf(dialog_->optionstab), found);
618 // Ascertain whether the template has any formats supporting
619 // the 'Extra' option
620 QLineEdit * const extraED = dialog_->extraED;
621 QComboBox * const extraCB = dialog_->extraFormatCO;
627 external::Template::Formats::const_iterator it = templ.formats.begin();
628 external::Template::Formats::const_iterator end = templ.formats.end();
629 for (; it != end; ++it) {
630 if (it->second.option_transformers.find(external::Extra) ==
631 it->second.option_transformers.end())
633 string const format = it->first;
634 string const opt = controller().params().extradata.get(format);
635 extraCB->addItem(toqstr(format));
636 extra_[format] = toqstr(opt);
639 bool const enabled = extraCB->count() > 0;
641 dialog_->tab->setTabEnabled(
642 dialog_->tab->indexOf(dialog_->optionstab), enabled);
643 extraED->setEnabled(enabled && !kernel().isBufferReadonly());
644 extraCB->setEnabled(enabled);
647 extraCB->setCurrentIndex(0);
648 extraED->setText(extra_[fromqstr(extraCB->currentText())]);
653 void GuiExternal::applyView()
655 InsetExternalParams params = controller().params();
657 params.filename.set(internal_path(fromqstr(dialog_->fileED->text())),
658 kernel().bufferFilepath());
660 params.settemplate(controller().getTemplate(
661 dialog_->externalCO->currentIndex()).lyxName);
663 params.draft = dialog_->draftCB->isChecked();
665 getDisplay(params.display, params.lyxscale,
666 *dialog_->displayCB, *dialog_->showCO,
667 *dialog_->displayscaleED);
669 if (dialog_->tab->isTabEnabled(
670 dialog_->tab->indexOf(dialog_->rotatetab)))
671 getRotation(params.rotationdata,
672 *dialog_->angleED, *dialog_->originCO);
674 if (dialog_->tab->isTabEnabled(
675 dialog_->tab->indexOf(dialog_->scaletab)))
676 getSize(params.resizedata,
677 *dialog_->widthED, *dialog_->widthUnitCO,
678 *dialog_->heightED, *dialog_->heightUnitCO,
679 *dialog_->aspectratioCB);
681 if (dialog_->tab->isTabEnabled(
682 dialog_->tab->indexOf(dialog_->croptab)))
683 getCrop(params.clipdata,
685 *dialog_->xlED, *dialog_->ybED,
686 *dialog_->xrED, *dialog_->ytED,
687 controller().bbChanged());
689 if (dialog_->tab->isTabEnabled(
690 dialog_->tab->indexOf(dialog_->optionstab)))
691 getExtra(params.extradata, extra_);
693 controller().setParams(params);
697 void GuiExternal::getBB()
699 dialog_->xlED->setText("0");
700 dialog_->ybED->setText("0");
701 dialog_->xrED->setText("0");
702 dialog_->ytED->setText("0");
704 string const filename = fromqstr(dialog_->fileED->text());
705 if (filename.empty())
708 string const bb = controller().readBB(filename);
712 dialog_->xlED->setText(toqstr(token(bb, ' ', 0)));
713 dialog_->ybED->setText(toqstr(token(bb, ' ', 1)));
714 dialog_->xrED->setText(toqstr(token(bb, ' ', 2)));
715 dialog_->ytED->setText(toqstr(token(bb, ' ', 3)));
717 controller().bbChanged(false);
720 } // namespace frontend
723 #include "GuiExternal_moc.cpp"