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::show()
139 bool GuiExternalDialog::activateAspectratio() const
141 if (widthUnitCO->currentIndex() == 0)
144 string const wstr = fromqstr(widthED->text());
147 bool const wIsDbl = isStrDbl(wstr);
148 if (wIsDbl && float_equal(convert<double>(wstr), 0.0, 0.05))
151 if (!wIsDbl && (!isValidLength(wstr, &l) || l.zero()))
154 string const hstr = fromqstr(heightED->text());
157 bool const hIsDbl = isStrDbl(hstr);
158 if (hIsDbl && float_equal(convert<double>(hstr), 0.0, 0.05))
160 if (!hIsDbl && (!isValidLength(hstr, &l) || l.zero()))
167 void GuiExternalDialog::bbChanged()
169 form_->controller().bbChanged(true);
174 void GuiExternalDialog::browseClicked()
176 int const choice = externalCO->currentIndex();
177 docstring const template_name =
178 from_utf8(form_->controller().getTemplate(choice).lyxName);
179 docstring const str =
180 form_->controller().browse(qstring_to_ucs4(fileED->text()),
183 fileED->setText(toqstr(str));
189 void GuiExternalDialog::change_adaptor()
195 void GuiExternalDialog::closeEvent(QCloseEvent * e)
202 void GuiExternalDialog::editClicked()
204 form_->controller().editExternal();
209 void GuiExternalDialog::extraChanged(const QString& text)
211 std::string const format = fromqstr(extraFormatCO->currentText());
212 form_->extra_[format] = text;
217 void GuiExternalDialog::formatChanged(const QString& format)
219 extraED->setText(form_->extra_[fromqstr(format)]);
223 void GuiExternalDialog::getbbClicked()
229 void GuiExternalDialog::sizeChanged()
231 aspectratioCB->setEnabled(activateAspectratio());
236 void GuiExternalDialog::templateChanged()
238 form_->updateTemplate();
243 void GuiExternalDialog::widthUnitChanged()
245 bool useHeight = (widthUnitCO->currentIndex() > 0);
248 widthED->setValidator(unsignedLengthValidator(widthED));
250 widthED->setValidator(new QDoubleValidator(0, 1000, 2, widthED));
252 heightED->setEnabled(useHeight);
253 heightUnitCO->setEnabled(useHeight);
258 /////////////////////////////////////////////////////////////////////
262 /////////////////////////////////////////////////////////////////////
266 Length::UNIT defaultUnit()
268 Length::UNIT default_unit = Length::CM;
269 switch (lyxrc.default_papersize) {
272 case PAPER_USEXECUTIVE:
273 default_unit = Length::IN;
282 void setDisplay(QCheckBox & displayCB, QComboBox & showCO, QLineEdit & scaleED,
283 external::DisplayType display, unsigned int scale,
288 case external::DefaultDisplay:
291 case external::MonochromeDisplay:
294 case external::GrayscaleDisplay:
297 case external::ColorDisplay:
300 case external::PreviewDisplay:
303 case external::NoDisplay:
308 showCO.setCurrentIndex(item);
309 bool const no_display = display == external::NoDisplay;
310 showCO.setEnabled(!no_display && !read_only);
311 displayCB.setChecked(!no_display);
312 scaleED.setEnabled(!no_display && !read_only);
313 scaleED.setText(toqstr(convert<string>(scale)));
317 void getDisplay(external::DisplayType & display,
318 unsigned int & scale,
319 QCheckBox const & displayCB,
320 QComboBox const & showCO,
321 QLineEdit const & scaleED)
323 switch (showCO.currentIndex()) {
325 display = external::DefaultDisplay;
328 display = external::MonochromeDisplay;
331 display = external::GrayscaleDisplay;
334 display = external::ColorDisplay;
337 display = external::PreviewDisplay;
341 if (!displayCB.isChecked())
342 display = external::NoDisplay;
344 scale = convert<int>(fromqstr(scaleED.text()));
348 void setRotation(QLineEdit & angleED, QComboBox & originCO,
349 external::RotationData const & data)
351 originCO.setCurrentIndex(int(data.origin()));
352 angleED.setText(toqstr(data.angle));
356 void getRotation(external::RotationData & data,
357 QLineEdit const & angleED, QComboBox const & originCO)
359 typedef external::RotationData::OriginType OriginType;
361 data.origin(static_cast<OriginType>(originCO.currentIndex()));
362 data.angle = fromqstr(angleED.text());
366 void setSize(QLineEdit & widthED, QComboBox & widthUnitCO,
367 QLineEdit & heightED, LengthCombo & heightUnitCO,
368 QCheckBox & aspectratioCB,
369 external::ResizeData const & data)
371 bool using_scale = data.usingScale();
372 std::string scale = data.scale;
373 if (data.no_resize()) {
374 // Everything is zero, so default to this!
380 widthED.setText(toqstr(scale));
381 widthUnitCO.setCurrentIndex(0);
383 widthED.setText(toqstr(convert<string>(data.width.value())));
384 // Because 'Scale' is position 0...
385 // Note also that width cannot be zero here, so
386 // we don't need to worry about the default unit.
387 widthUnitCO.setCurrentIndex(data.width.unit() + 1);
390 string const h = data.height.zero() ? string() : data.height.asString();
391 Length::UNIT default_unit = data.width.zero() ?
392 defaultUnit() : data.width.unit();
393 lengthToWidgets(&heightED, &heightUnitCO, h, default_unit);
395 heightED.setEnabled(!using_scale);
396 heightUnitCO.setEnabled(!using_scale);
398 aspectratioCB.setChecked(data.keepAspectRatio);
400 bool const disable_aspectRatio = using_scale ||
401 data.width.zero() || data.height.zero();
402 aspectratioCB.setEnabled(!disable_aspectRatio);
406 void getSize(external::ResizeData & data,
407 QLineEdit const & widthED, QComboBox const & widthUnitCO,
408 QLineEdit const & heightED, LengthCombo const & heightUnitCO,
409 QCheckBox const & aspectratioCB)
411 string const width = fromqstr(widthED.text());
413 if (widthUnitCO.currentIndex() > 0) {
414 // Subtract one, because scale is 0.
415 int const unit = widthUnitCO.currentIndex() - 1;
418 if (isValidLength(width, &w))
420 else if (isStrDbl(width))
421 data.width = Length(convert<double>(width),
422 static_cast<Length::UNIT>(unit));
424 data.width = Length();
426 data.scale = string();
429 // scaling instead of a width
431 data.width = Length();
434 data.height = Length(widgetsToLength(&heightED, &heightUnitCO));
436 data.keepAspectRatio = aspectratioCB.isChecked();
440 void setCrop(QCheckBox & clipCB,
441 QLineEdit & xlED, QLineEdit & ybED,
442 QLineEdit & xrED, QLineEdit & ytED,
443 external::ClipData const & data)
445 clipCB.setChecked(data.clip);
446 graphics::BoundingBox const & bbox = data.bbox;
447 xlED.setText(toqstr(convert<string>(bbox.xl)));
448 ybED.setText(toqstr(convert<string>(bbox.yb)));
449 xrED.setText(toqstr(convert<string>(bbox.xr)));
450 ytED.setText(toqstr(convert<string>(bbox.yt)));
454 void getCrop(external::ClipData & data,
455 QCheckBox const & clipCB,
456 QLineEdit const & xlED, QLineEdit const & ybED,
457 QLineEdit const & xrED, QLineEdit const & ytED,
460 data.clip = clipCB.isChecked();
465 data.bbox.xl = convert<int>(fromqstr(xlED.text()));
466 data.bbox.yb = convert<int>(fromqstr(ybED.text()));
467 data.bbox.xr = convert<int>(fromqstr(xrED.text()));
468 data.bbox.yt = convert<int>(fromqstr(ytED.text()));
472 void getExtra(external::ExtraData & data,
473 GuiExternal::MapType const & extra)
475 typedef GuiExternal::MapType MapType;
476 MapType::const_iterator it = extra.begin();
477 MapType::const_iterator const end = extra.end();
478 for (; it != end; ++it)
479 data.set(it->first, trim(fromqstr(it->second)));
485 GuiExternal::GuiExternal(GuiDialog & parent)
486 : GuiView<GuiExternalDialog>(parent, _("External Material"))
490 void GuiExternal::build_dialog()
492 dialog_.reset(new GuiExternalDialog(this));
494 bc().setOK(dialog_->okPB);
495 bc().setApply(dialog_->applyPB);
496 bc().setCancel(dialog_->closePB);
498 bc().addReadOnly(dialog_->fileED);
499 bc().addReadOnly(dialog_->browsePB);
500 bc().addReadOnly(dialog_->editPB);
501 bc().addReadOnly(dialog_->externalCO);
502 bc().addReadOnly(dialog_->draftCB);
503 bc().addReadOnly(dialog_->displayscaleED);
504 bc().addReadOnly(dialog_->showCO);
505 bc().addReadOnly(dialog_->displayCB);
506 bc().addReadOnly(dialog_->angleED);
507 bc().addReadOnly(dialog_->originCO);
508 bc().addReadOnly(dialog_->heightUnitCO);
509 bc().addReadOnly(dialog_->heightED);
510 bc().addReadOnly(dialog_->aspectratioCB);
511 bc().addReadOnly(dialog_->widthUnitCO);
512 bc().addReadOnly(dialog_->widthED);
513 bc().addReadOnly(dialog_->clipCB);
514 bc().addReadOnly(dialog_->getbbPB);
515 bc().addReadOnly(dialog_->ytED);
516 bc().addReadOnly(dialog_->xlED);
517 bc().addReadOnly(dialog_->xrED);
518 bc().addReadOnly(dialog_->ybED);
519 bc().addReadOnly(dialog_->extraFormatCO);
520 bc().addReadOnly(dialog_->extraED);
522 bc().addCheckedLineEdit(dialog_->angleED, dialog_->angleLA);
523 bc().addCheckedLineEdit(dialog_->displayscaleED, dialog_->scaleLA);
524 bc().addCheckedLineEdit(dialog_->heightED, dialog_->heightLA);
525 bc().addCheckedLineEdit(dialog_->widthED, dialog_->widthLA);
526 bc().addCheckedLineEdit(dialog_->xlED, dialog_->lbLA);
527 bc().addCheckedLineEdit(dialog_->ybED, dialog_->lbLA);
528 bc().addCheckedLineEdit(dialog_->xrED, dialog_->rtLA);
529 bc().addCheckedLineEdit(dialog_->ytED, dialog_->rtLA);
530 bc().addCheckedLineEdit(dialog_->fileED, dialog_->fileLA);
532 std::vector<string> templates(controller().getTemplates());
534 for (std::vector<string>::const_iterator cit = templates.begin();
535 cit != templates.end(); ++cit) {
536 dialog_->externalCO->addItem(qt_(*cit));
539 // Fill the origins combo
540 typedef vector<external::RotationDataType> Origins;
541 Origins const & all_origins = external::all_origins();
542 for (Origins::size_type i = 0; i != all_origins.size(); ++i)
543 dialog_->originCO->addItem(toqstr(external::origin_gui_str(i)));
545 // Fill the width combo
546 dialog_->widthUnitCO->addItem(qt_("Scale%"));
547 for (int i = 0; i < num_units; i++)
548 dialog_->widthUnitCO->addItem(qt_(unit_name_gui[i]));
552 void GuiExternal::update_contents()
554 dialog_->tab->setCurrentIndex(0);
555 InsetExternalParams const & params = controller().params();
558 params.filename.outputFilename(kernel().bufferFilepath());
559 dialog_->fileED->setText(toqstr(name));
561 dialog_->externalCO->setCurrentIndex(
562 controller().getTemplateNumber(params.templatename()));
565 dialog_->draftCB->setChecked(params.draft);
567 setDisplay(*dialog_->displayCB, *dialog_->showCO,
568 *dialog_->displayscaleED,
569 params.display, params.lyxscale, readOnly());
571 setRotation(*dialog_->angleED, *dialog_->originCO, params.rotationdata);
573 setSize(*dialog_->widthED, *dialog_->widthUnitCO,
574 *dialog_->heightED, *dialog_->heightUnitCO,
575 *dialog_->aspectratioCB,
578 setCrop(*dialog_->clipCB,
579 *dialog_->xlED, *dialog_->ybED,
580 *dialog_->xrED, *dialog_->ytED,
582 controller().bbChanged(!params.clipdata.bbox.empty());
588 void GuiExternal::updateTemplate()
590 external::Template templ =
591 controller().getTemplate(dialog_->externalCO->currentIndex());
592 dialog_->externalTB->setPlainText(qt_(templ.helpText));
594 // Ascertain which (if any) transformations the template supports
595 // and disable tabs hosting unsupported transforms.
596 typedef vector<external::TransformID> TransformIDs;
597 TransformIDs const transformIds = templ.transformIds;
598 TransformIDs::const_iterator tr_begin = transformIds.begin();
599 TransformIDs::const_iterator const tr_end = transformIds.end();
601 bool found = find(tr_begin, tr_end, external::Rotate) != tr_end;
602 dialog_->tab->setTabEnabled(
603 dialog_->tab->indexOf(dialog_->rotatetab), found);
604 found = find(tr_begin, tr_end, external::Resize) != tr_end;
605 dialog_->tab->setTabEnabled(
606 dialog_->tab->indexOf(dialog_->scaletab), found);
608 found = find(tr_begin, tr_end, external::Clip) != tr_end;
609 dialog_->tab->setTabEnabled(
610 dialog_->tab->indexOf(dialog_->croptab), found);
612 found = find(tr_begin, tr_end, external::Extra) != tr_end;
613 dialog_->tab->setTabEnabled(
614 dialog_->tab->indexOf(dialog_->optionstab), found);
619 // Ascertain whether the template has any formats supporting
620 // the 'Extra' option
621 QLineEdit * const extraED = dialog_->extraED;
622 QComboBox * const extraCB = dialog_->extraFormatCO;
628 external::Template::Formats::const_iterator it = templ.formats.begin();
629 external::Template::Formats::const_iterator end = templ.formats.end();
630 for (; it != end; ++it) {
631 if (it->second.option_transformers.find(external::Extra) ==
632 it->second.option_transformers.end())
634 string const format = it->first;
635 string const opt = controller().params().extradata.get(format);
636 extraCB->addItem(toqstr(format));
637 extra_[format] = toqstr(opt);
640 bool const enabled = extraCB->count() > 0;
642 dialog_->tab->setTabEnabled(
643 dialog_->tab->indexOf(dialog_->optionstab), enabled);
644 extraED->setEnabled(enabled && !kernel().isBufferReadonly());
645 extraCB->setEnabled(enabled);
648 extraCB->setCurrentIndex(0);
649 extraED->setText(extra_[fromqstr(extraCB->currentText())]);
654 void GuiExternal::apply()
656 InsetExternalParams params = controller().params();
658 params.filename.set(internal_path(fromqstr(dialog_->fileED->text())),
659 kernel().bufferFilepath());
661 params.settemplate(controller().getTemplate(
662 dialog_->externalCO->currentIndex()).lyxName);
664 params.draft = dialog_->draftCB->isChecked();
666 getDisplay(params.display, params.lyxscale,
667 *dialog_->displayCB, *dialog_->showCO,
668 *dialog_->displayscaleED);
670 if (dialog_->tab->isTabEnabled(
671 dialog_->tab->indexOf(dialog_->rotatetab)))
672 getRotation(params.rotationdata,
673 *dialog_->angleED, *dialog_->originCO);
675 if (dialog_->tab->isTabEnabled(
676 dialog_->tab->indexOf(dialog_->scaletab)))
677 getSize(params.resizedata,
678 *dialog_->widthED, *dialog_->widthUnitCO,
679 *dialog_->heightED, *dialog_->heightUnitCO,
680 *dialog_->aspectratioCB);
682 if (dialog_->tab->isTabEnabled(
683 dialog_->tab->indexOf(dialog_->croptab)))
684 getCrop(params.clipdata,
686 *dialog_->xlED, *dialog_->ybED,
687 *dialog_->xrED, *dialog_->ytED,
688 controller().bbChanged());
690 if (dialog_->tab->isTabEnabled(
691 dialog_->tab->indexOf(dialog_->optionstab)))
692 getExtra(params.extradata, extra_);
694 controller().setParams(params);
698 void GuiExternal::getBB()
700 dialog_->xlED->setText("0");
701 dialog_->ybED->setText("0");
702 dialog_->xrED->setText("0");
703 dialog_->ytED->setText("0");
705 string const filename = fromqstr(dialog_->fileED->text());
706 if (filename.empty())
709 string const bb = controller().readBB(filename);
713 dialog_->xlED->setText(toqstr(token(bb, ' ', 0)));
714 dialog_->ybED->setText(toqstr(token(bb, ' ', 1)));
715 dialog_->xrED->setText(toqstr(token(bb, ' ', 2)));
716 dialog_->ytED->setText(toqstr(token(bb, ' ', 3)));
718 controller().bbChanged(false);
721 } // namespace frontend
724 #include "GuiExternal_moc.cpp"