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
8 * \author Asger Alstrup
10 * Full author contact details are available in file CREDITS.
15 #include "GuiExternal.h"
17 #include "FuncRequest.h"
18 #include "support/gettext.h"
22 #include "insets/ExternalSupport.h"
23 #include "insets/ExternalTemplate.h"
24 #include "insets/InsetExternal.h"
26 #include "graphics/GraphicsCache.h"
27 #include "graphics/GraphicsCacheItem.h"
28 #include "graphics/GraphicsImage.h"
30 #include "support/convert.h"
31 #include "support/filetools.h"
32 #include "support/lstrings.h"
33 #include "support/lyxlib.h"
34 #include "support/os.h"
36 #include "LengthCombo.h"
37 #include "qt_helpers.h"
38 #include "Validator.h"
43 #include <QPushButton>
45 #include <QTextBrowser>
48 using namespace lyx::support
;
53 using namespace external
;
57 RotationDataType origins
[] = {
58 RotationData::DEFAULT
,
59 RotationData::TOPLEFT
,
60 RotationData::BOTTOMLEFT
,
61 RotationData::BASELINELEFT
,
63 RotationData::TOPCENTER
,
64 RotationData::BOTTOMCENTER
,
65 RotationData::BASELINECENTER
,
66 RotationData::TOPRIGHT
,
67 RotationData::BOTTOMRIGHT
,
68 RotationData::BASELINERIGHT
72 // These are the strings, corresponding to the above, that the GUI should
73 // use. Note that they can/should be translated.
74 char const * const origin_gui_strs
[] = {
76 N_("Top left"), N_("Bottom left"), N_("Baseline left"),
77 N_("Center"), N_("Top center"), N_("Bottom center"), N_("Baseline center"),
78 N_("Top right"), N_("Bottom right"), N_("Baseline right")
81 external::Template
getTemplate(int i
)
83 external::TemplateManager::Templates::const_iterator i1
84 = external::TemplateManager::get().getTemplates().begin();
92 GuiExternal::GuiExternal(GuiView
& lv
)
93 : GuiDialog(lv
, "external", qt_("External Material")), bbChanged_(false)
97 connect(okPB
, SIGNAL(clicked()), this, SLOT(slotOK()));
98 connect(applyPB
, SIGNAL(clicked()), this, SLOT(slotApply()));
99 connect(closePB
, SIGNAL(clicked()), this, SLOT(slotClose()));
102 connect(displayGB, SIGNAL(toggled(bool)),
103 displayscaleED, SLOT(setEnabled(bool)));
105 connect(originCO
, SIGNAL(activated(int)),
106 this, SLOT(change_adaptor()));
107 connect(aspectratioCB
, SIGNAL(stateChanged(int)),
108 this, SLOT(change_adaptor()));
109 connect(browsePB
, SIGNAL(clicked()),
110 this, SLOT(browseClicked()));
111 connect(externalCO
, SIGNAL(activated(QString
)),
112 this, SLOT(templateChanged()));
113 connect(extraED
, SIGNAL(textChanged(QString
)),
114 this, SLOT(extraChanged(QString
)));
115 connect(extraFormatCO
, SIGNAL(activated(QString
)),
116 this, SLOT(formatChanged(QString
)));
117 connect(widthUnitCO
, SIGNAL(activated(int)),
118 this, SLOT(widthUnitChanged()));
119 connect(heightUnitCO
, SIGNAL(selectionChanged(lyx::Length::UNIT
)),
120 this, SLOT(change_adaptor()));
121 connect(displayGB
, SIGNAL(toggled(bool)),
122 this, SLOT(change_adaptor()));
123 connect(displayscaleED
, SIGNAL(textChanged(QString
)),
124 this, SLOT(change_adaptor()));
125 connect(angleED
, SIGNAL(textChanged(QString
)),
126 this, SLOT(change_adaptor()));
127 connect(widthED
, SIGNAL(textChanged(QString
)),
128 this, SLOT(sizeChanged()));
129 connect(heightED
, SIGNAL(textChanged(QString
)),
130 this, SLOT(sizeChanged()));
131 connect(fileED
, SIGNAL(textChanged(QString
)),
132 this, SLOT(change_adaptor()));
133 connect(clipCB
, SIGNAL(stateChanged(int)),
134 this, SLOT(change_adaptor()));
135 connect(getbbPB
, SIGNAL(clicked()), this, SLOT(getbbClicked()));
136 connect(xrED
, SIGNAL(textChanged(QString
)), this, SLOT(bbChanged()));
137 connect(ytED
, SIGNAL(textChanged(QString
)), this, SLOT(bbChanged()));
138 connect(xlED
, SIGNAL(textChanged(QString
)), this, SLOT(bbChanged()));
139 connect(ybED
, SIGNAL(textChanged(QString
)), this, SLOT(bbChanged()));
140 connect(draftCB
, SIGNAL(clicked()), this, SLOT(change_adaptor()));
142 QIntValidator
* validator
= new QIntValidator(displayscaleED
);
143 validator
->setBottom(1);
144 displayscaleED
->setValidator(validator
);
146 angleED
->setValidator(new QDoubleValidator(-360, 360, 2, angleED
));
148 xlED
->setValidator(new QIntValidator(xlED
));
149 ybED
->setValidator(new QIntValidator(ybED
));
150 xrED
->setValidator(new QIntValidator(xrED
));
151 ytED
->setValidator(new QIntValidator(ytED
));
153 widthED
->setValidator(unsignedLengthValidator(widthED
));
154 heightED
->setValidator(unsignedLengthValidator(heightED
));
156 setFocusProxy(fileED
);
158 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy
);
161 bc().setApply(applyPB
);
162 bc().setCancel(closePB
);
164 bc().addReadOnly(fileED
);
165 bc().addReadOnly(browsePB
);
166 bc().addReadOnly(externalCO
);
167 bc().addReadOnly(draftCB
);
168 bc().addReadOnly(displayscaleED
);
169 bc().addReadOnly(displayGB
);
170 bc().addReadOnly(angleED
);
171 bc().addReadOnly(originCO
);
172 bc().addReadOnly(heightUnitCO
);
173 bc().addReadOnly(heightED
);
174 bc().addReadOnly(aspectratioCB
);
175 bc().addReadOnly(widthUnitCO
);
176 bc().addReadOnly(widthED
);
177 bc().addReadOnly(clipCB
);
178 bc().addReadOnly(getbbPB
);
179 bc().addReadOnly(ytED
);
180 bc().addReadOnly(xlED
);
181 bc().addReadOnly(xrED
);
182 bc().addReadOnly(ybED
);
183 bc().addReadOnly(extraFormatCO
);
184 bc().addReadOnly(extraED
);
186 bc().addCheckedLineEdit(angleED
, angleLA
);
187 bc().addCheckedLineEdit(displayscaleED
, scaleLA
);
188 bc().addCheckedLineEdit(heightED
, heightLA
);
189 bc().addCheckedLineEdit(widthED
, widthLA
);
190 bc().addCheckedLineEdit(xlED
, lbLA
);
191 bc().addCheckedLineEdit(ybED
, lbLA
);
192 bc().addCheckedLineEdit(xrED
, rtLA
);
193 bc().addCheckedLineEdit(ytED
, rtLA
);
194 bc().addCheckedLineEdit(fileED
, fileLA
);
196 external::TemplateManager::Templates::const_iterator i1
, i2
;
197 i1
= external::TemplateManager::get().getTemplates().begin();
198 i2
= external::TemplateManager::get().getTemplates().end();
199 for (; i1
!= i2
; ++i1
)
200 externalCO
->addItem(qt_(i1
->second
.lyxName
));
202 // Fill the origins combo
203 for (size_t i
= 0; i
!= sizeof(origins
) / sizeof(origins
[0]); ++i
)
204 originCO
->addItem(qt_(origin_gui_strs
[i
]));
207 widthUnitCO
->insertItem(0, qt_("Scale%"), "scale");
211 bool GuiExternal::activateAspectratio() const
216 string
const wstr
= fromqstr(widthED
->text());
219 bool const wIsDbl
= isStrDbl(wstr
);
220 if (wIsDbl
&& float_equal(convert
<double>(wstr
), 0.0, 0.05))
223 if (!wIsDbl
&& (!isValidLength(wstr
, &l
) || l
.zero()))
226 string
const hstr
= fromqstr(heightED
->text());
229 bool const hIsDbl
= isStrDbl(hstr
);
230 if (hIsDbl
&& float_equal(convert
<double>(hstr
), 0.0, 0.05))
232 if (!hIsDbl
&& (!isValidLength(hstr
, &l
) || l
.zero()))
239 bool GuiExternal::usingScale() const
241 return (widthUnitCO
->itemData(
242 widthUnitCO
->currentIndex()).toString() == "scale");
246 void GuiExternal::bbChanged()
253 void GuiExternal::browseClicked()
255 int const choice
= externalCO
->currentIndex();
256 QString
const template_name
= toqstr(getTemplate(choice
).lyxName
);
257 QString
const str
= browse(fileED
->text(), template_name
);
258 if (!str
.isEmpty()) {
259 fileED
->setText(str
);
265 void GuiExternal::change_adaptor()
271 void GuiExternal::extraChanged(const QString
& text
)
273 extra_
[extraFormatCO
->currentText()] = text
;
278 void GuiExternal::formatChanged(const QString
& format
)
280 extraED
->setText(extra_
[format
]);
284 void GuiExternal::getbbClicked()
291 string
const filename
= fromqstr(fileED
->text());
292 if (filename
.empty())
295 FileName
const abs_file(support::makeAbsPath(filename
, fromqstr(bufferFilepath())));
297 // try to get it from the file, if possible
298 string bb
= readBB_from_PSFile(abs_file
);
300 // we don't, so ask the Graphics Cache if it has loaded the file
304 graphics::Cache
& gc
= graphics::Cache::get();
305 if (gc
.inCache(abs_file
)) {
306 graphics::Image
const * image
= gc
.item(abs_file
)->image();
309 width
= image
->width();
310 height
= image
->height();
313 bb
= "0 0 " + convert
<string
>(width
) + ' ' + convert
<string
>(height
);
316 xlED
->setText(toqstr(token(bb
, ' ', 0)));
317 ybED
->setText(toqstr(token(bb
, ' ', 1)));
318 xrED
->setText(toqstr(token(bb
, ' ', 2)));
319 ytED
->setText(toqstr(token(bb
, ' ', 3)));
325 void GuiExternal::sizeChanged()
327 aspectratioCB
->setEnabled(activateAspectratio());
332 void GuiExternal::templateChanged()
339 void GuiExternal::widthUnitChanged()
342 widthED
->setValidator(new QDoubleValidator(0, 1000, 2, widthED
));
344 widthED
->setValidator(unsignedLengthValidator(widthED
));
346 heightED
->setEnabled(!usingScale());
347 heightUnitCO
->setEnabled(!usingScale());
352 static void setRotation(QLineEdit
& angleED
, QComboBox
& originCO
,
353 external::RotationData
const & data
)
355 originCO
.setCurrentIndex(int(data
.origin()));
356 angleED
.setText(toqstr(data
.angle
));
360 static void getRotation(external::RotationData
& data
,
361 QLineEdit
const & angleED
, QComboBox
const & originCO
)
363 typedef external::RotationData::OriginType OriginType
;
365 data
.origin(static_cast<OriginType
>(originCO
.currentIndex()));
366 data
.angle
= fromqstr(angleED
.text());
370 static void setSize(QLineEdit
& widthED
, LengthCombo
& widthUnitCO
,
371 QLineEdit
& heightED
, LengthCombo
& heightUnitCO
,
372 QCheckBox
& aspectratioCB
,
373 external::ResizeData
const & data
)
375 bool using_scale
= data
.usingScale();
376 string scale
= data
.scale
;
377 if (data
.no_resize()) {
378 // Everything is zero, so default to this!
384 widthED
.setText(toqstr(scale
));
385 widthUnitCO
.setCurrentItem("scale");
387 lengthToWidgets(&widthED
, &widthUnitCO
,
388 data
.width
.asString(), Length::defaultUnit());
390 string
const h
= data
.height
.zero() ? string() : data
.height
.asString();
391 Length::UNIT
const default_unit
= data
.width
.zero() ?
392 Length::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 static void getSize(external::ResizeData
& data
,
407 QLineEdit
const & widthED
, QComboBox
const & widthUnitCO
,
408 QLineEdit
const & heightED
, LengthCombo
const & heightUnitCO
,
409 QCheckBox
const & aspectratioCB
, bool const scaling
)
411 string
const width
= fromqstr(widthED
.text());
414 // scaling instead of a width
416 data
.width
= Length();
418 data
.width
= Length(widgetsToLength(&widthED
, &widthUnitCO
));
419 data
.scale
= string();
421 data
.height
= Length(widgetsToLength(&heightED
, &heightUnitCO
));
422 data
.keepAspectRatio
= aspectratioCB
.isChecked();
426 void setCrop(QCheckBox
& clipCB
,
427 QLineEdit
& xlED
, QLineEdit
& ybED
,
428 QLineEdit
& xrED
, QLineEdit
& ytED
,
429 external::ClipData
const & data
)
431 clipCB
.setChecked(data
.clip
);
432 graphics::BoundingBox
const & bbox
= data
.bbox
;
433 xlED
.setText(QString::number(bbox
.xl
));
434 ybED
.setText(QString::number(bbox
.yb
));
435 xrED
.setText(QString::number(bbox
.xr
));
436 ytED
.setText(QString::number(bbox
.yt
));
440 static void getCrop(external::ClipData
& data
,
441 QCheckBox
const & clipCB
,
442 QLineEdit
const & xlED
, QLineEdit
const & ybED
,
443 QLineEdit
const & xrED
, QLineEdit
const & ytED
,
446 data
.clip
= clipCB
.isChecked();
451 data
.bbox
.xl
= xlED
.text().toInt();
452 data
.bbox
.yb
= ybED
.text().toInt();
453 data
.bbox
.xr
= xrED
.text().toInt();
454 data
.bbox
.yt
= ytED
.text().toInt();
458 void GuiExternal::updateContents()
461 params_
.filename
.outputFilename(fromqstr(bufferFilepath()));
462 fileED
->setText(toqstr(name
));
465 external::TemplateManager::Templates::const_iterator i1
, i2
;
466 i1
= external::TemplateManager::get().getTemplates().begin();
467 i2
= external::TemplateManager::get().getTemplates().end();
468 for (int i
= 0; i1
!= i2
; ++i1
, ++i
) {
469 if (i1
->second
.lyxName
== params_
.templatename()) {
475 externalCO
->setCurrentIndex(index
);
478 draftCB
->setChecked(params_
.draft
);
480 displayGB
->setChecked(params_
.display
);
481 displayscaleED
->setText(QString::number(params_
.lyxscale
));
482 bool scaled
= params_
.display
&& !isBufferReadonly() &&
483 (params_
.preview_mode
!= PREVIEW_INSTANT
);
484 displayscaleED
->setEnabled(scaled
);
485 scaleLA
->setEnabled(scaled
);
486 displayGB
->setEnabled(lyxrc
.display_graphics
);
489 setRotation(*angleED
, *originCO
, params_
.rotationdata
);
491 setSize(*widthED
, *widthUnitCO
, *heightED
, *heightUnitCO
,
492 *aspectratioCB
, params_
.resizedata
);
494 setCrop(*clipCB
, *xlED
, *ybED
, *xrED
, *ytED
, params_
.clipdata
);
495 bbChanged_
= !params_
.clipdata
.bbox
.empty();
501 void GuiExternal::updateTemplate()
503 external::Template templ
= getTemplate(externalCO
->currentIndex());
504 externalTB
->setPlainText(qt_(templ
.helpText
));
506 // Ascertain which (if any) transformations the template supports
507 // and disable tabs and Group Boxes hosting unsupported transforms.
508 typedef vector
<external::TransformID
> TransformIDs
;
509 TransformIDs
const transformIds
= templ
.transformIds
;
510 TransformIDs::const_iterator tr_begin
= transformIds
.begin();
511 TransformIDs::const_iterator
const tr_end
= transformIds
.end();
513 bool found
= std::find(tr_begin
, tr_end
, external::Rotate
) != tr_end
;
514 rotationGB
->setEnabled(found
);
516 found
= std::find(tr_begin
, tr_end
, external::Resize
) != tr_end
;
517 scaleGB
->setEnabled(found
);
519 found
= std::find(tr_begin
, tr_end
, external::Clip
) != tr_end
;
520 cropGB
->setEnabled(found
);
522 tab
->setTabEnabled(tab
->indexOf(sizetab
),
523 rotationGB
->isEnabled()
524 || scaleGB
->isEnabled()
525 || cropGB
->isEnabled());
527 found
= std::find(tr_begin
, tr_end
, external::Extra
) != tr_end
;
528 optionsGB
->setEnabled(found
);
530 bool scaled
= displayGB
->isChecked() && displayGB
->isEnabled() &&
531 !isBufferReadonly() && (templ
.preview_mode
!= PREVIEW_INSTANT
);
532 displayscaleED
->setEnabled(scaled
);
533 scaleLA
->setEnabled(scaled
);
538 // Ascertain whether the template has any formats supporting
539 // the 'Extra' option
542 extraFormatCO
->clear();
544 external::Template::Formats::const_iterator it
= templ
.formats
.begin();
545 external::Template::Formats::const_iterator end
= templ
.formats
.end();
546 for (; it
!= end
; ++it
) {
547 if (it
->second
.option_transformers
.find(external::Extra
) ==
548 it
->second
.option_transformers
.end())
550 string
const format
= it
->first
;
551 string
const opt
= params_
.extradata
.get(format
);
552 extraFormatCO
->addItem(toqstr(format
));
553 extra_
[toqstr(format
)] = toqstr(opt
);
556 bool const enabled
= extraFormatCO
->count() > 0;
558 optionsGB
->setEnabled(enabled
);
559 extraED
->setEnabled(enabled
&& !isBufferReadonly());
560 extraFormatCO
->setEnabled(enabled
);
563 extraFormatCO
->setCurrentIndex(0);
564 extraED
->setText(extra_
[extraFormatCO
->currentText()]);
569 void GuiExternal::applyView()
571 params_
.filename
.set(fromqstr(fileED
->text()), fromqstr(bufferFilepath()));
572 params_
.settemplate(getTemplate(externalCO
->currentIndex()).lyxName
);
574 params_
.draft
= draftCB
->isChecked();
575 params_
.lyxscale
= displayscaleED
->text().toInt();
576 params_
.display
= displayGB
->isChecked();
578 if (rotationGB
->isEnabled())
579 getRotation(params_
.rotationdata
, *angleED
, *originCO
);
581 if (scaleGB
->isEnabled())
582 getSize(params_
.resizedata
, *widthED
, *widthUnitCO
,
583 *heightED
, *heightUnitCO
, *aspectratioCB
, usingScale());
585 if (cropGB
->isEnabled())
586 getCrop(params_
.clipdata
, *clipCB
, *xlED
, *ybED
,
587 *xrED
, *ytED
, bbChanged_
);
589 if (optionsGB
->isEnabled()) {
590 MapType::const_iterator it
= extra_
.begin();
591 MapType::const_iterator
const end
= extra_
.end();
592 for (; it
!= end
; ++it
)
593 params_
.extradata
.set(fromqstr(it
.key()), fromqstr(it
.value().trimmed()));
598 bool GuiExternal::initialiseParams(string
const & data
)
600 InsetExternal::string2params(data
, buffer(), params_
);
605 void GuiExternal::clearParams()
607 params_
= InsetExternalParams();
611 void GuiExternal::dispatchParams()
613 string
const lfun
= InsetExternal::params2string(params_
, buffer());
614 dispatch(FuncRequest(getLfun(), lfun
));
618 static QStringList
templateFilters(QString
const & template_name
)
620 /// Determine the template file extension
621 external::TemplateManager
const & etm
=
622 external::TemplateManager::get();
623 external::Template
const * const et_ptr
=
624 etm
.getTemplateByName(fromqstr(template_name
));
626 return fileFilters(et_ptr
? toqstr(et_ptr
->fileRegExp
) : QString());
630 QString
GuiExternal::browse(QString
const & input
,
631 QString
const & template_name
) const
633 QString
const title
= qt_("Select external file");
634 QString
const bufpath
= bufferFilepath();
635 QStringList
const filter
= templateFilters(template_name
);
637 QString
const label1
= qt_("Documents|#o#O");
638 QString
const dir1
= toqstr(lyxrc
.document_path
);
640 return browseRelFile(input
, bufpath
, title
, filter
, false, label1
, dir1
);
644 Dialog
* createGuiExternal(GuiView
& lv
) { return new GuiExternal(lv
); }
647 } // namespace frontend
650 #include "moc_GuiExternal.cpp"