2 * \file GuiGraphics.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
10 * \author Richard Heck
12 * Full author contact details are available in file CREDITS.
17 #include "GuiGraphics.h"
18 #include "frontends/alert.h"
19 #include "qt_helpers.h"
20 #include "Validator.h"
23 #include "FuncRequest.h"
24 #include "LengthCombo.h"
29 #include "graphics/epstools.h"
30 #include "graphics/GraphicsCache.h"
31 #include "graphics/GraphicsCacheItem.h"
32 #include "graphics/GraphicsImage.h"
34 #include "insets/InsetGraphics.h"
36 #include "support/convert.h"
37 #include "support/debug.h"
38 #include "support/filetools.h"
39 #include "support/gettext.h"
40 #include "support/lstrings.h"
41 #include "support/os.h"
42 #include "support/Package.h"
43 #include "support/types.h"
46 #include <QFileDialog>
49 #include <QPushButton>
56 using namespace lyx::support;
60 // These are the strings that are stored in the LyX file and which
61 // correspond to the LaTeX identifiers shown in the comments at the
63 char const * const rorigin_lyx_strs[] = {
64 // the LaTeX default is leftBaseline
66 "leftTop", "leftBottom", "leftBaseline", // lt lb lB
67 "center", "centerTop", "centerBottom", "centerBaseline", // c ct cb cB
68 "rightTop", "rightBottom", "rightBaseline" }; // rt rb rB
70 // These are the strings, corresponding to the above, that the GUI should
71 // use. Note that they can/should be translated.
72 char const * const rorigin_gui_strs[] = {
74 N_("Top left"), N_("Bottom left"), N_("Baseline left"),
75 N_("Center"), N_("Top center"), N_("Bottom center"), N_("Baseline center"),
76 N_("Top right"), N_("Bottom right"), N_("Baseline right") };
78 size_t const rorigin_size = sizeof(rorigin_lyx_strs) / sizeof(char *);
80 static string const autostr = N_("automatically");
88 //FIXME setAutoTextCB should really take an argument, as indicated, that
89 //determines what text is to be written for "auto". But making
90 //that work involves more extensive revisions than we now want
91 //to make, since "auto" also appears in paramsToDialog().
92 //The right way to do this, I think, would be to define a class
93 //checkedLengthSet (and a partnering labeledLengthSete) that encapsulated
94 //the checkbox, line edit, and length combo together, and then made e.g.
95 //lengthToWidgets, widgetsToLength, etc, all public methods of that class.
96 //Perhaps even the validator could be exposed through it.
98 * sets a checkbox-line edit-length combo group, using "text" if the
99 * checkbox is unchecked and clearing the line edit if it previously
102 static void setAutoTextCB(QCheckBox * checkBox, QLineEdit * lineEdit,
103 LengthCombo * lengthCombo/*, string text = "auto"*/)
105 if (!checkBox->isChecked())
106 lengthToWidgets(lineEdit, lengthCombo,
107 _(autostr), lengthCombo->currentLengthItem());
108 else if (lineEdit->text() == qt_(autostr))
109 lengthToWidgets(lineEdit, lengthCombo, string(),
110 lengthCombo->currentLengthItem());
114 GuiGraphics::GuiGraphics(GuiView & lv)
115 : GuiDialog(lv, "graphics", qt_("Graphics")), bbChanged(false)
120 connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
121 connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
122 connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
123 connect(restorePB, SIGNAL(clicked()), this, SLOT(slotRestore()));
126 connect(filename, SIGNAL(textChanged(const QString &)),
127 this, SLOT(change_adaptor()));
128 connect(WidthCB, SIGNAL(clicked()),
129 this, SLOT(change_adaptor()));
130 connect(HeightCB, SIGNAL(clicked()),
131 this, SLOT(change_adaptor()));
132 connect(Width, SIGNAL(textChanged(const QString &)),
133 this, SLOT(updateAspectRatioStatus()));
134 connect(Width, SIGNAL(textChanged(const QString &)),
135 this, SLOT(change_adaptor()));
136 connect(Height, SIGNAL(textChanged(const QString &)),
137 this, SLOT(updateAspectRatioStatus()));
138 connect(Height, SIGNAL(textChanged(const QString &)),
139 this, SLOT(change_adaptor()));
140 connect(heightUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
141 this, SLOT(change_adaptor()));
142 connect(widthUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
143 this, SLOT(change_adaptor()));
144 connect(aspectratio, SIGNAL(stateChanged(int)),
145 this, SLOT(change_adaptor()));
146 connect(angle, SIGNAL(textChanged(const QString &)),
147 this, SLOT(change_adaptor()));
148 connect(origin, SIGNAL(activated(int)),
149 this, SLOT(change_adaptor()));
150 connect(scaleCB, SIGNAL(clicked()),
151 this, SLOT(change_adaptor()));
152 connect(Scale, SIGNAL(textChanged(const QString &)),
153 this, SLOT(change_adaptor()));
154 connect(rotateOrderCB, SIGNAL(clicked()),
155 this, SLOT(change_adaptor()));
157 filename->setValidator(new PathValidator(true, filename));
158 setFocusProxy(filename);
160 QDoubleValidator * scaleValidator =
161 new DoubleAutoValidator(Scale, qt_(autostr));
162 scaleValidator->setBottom(0);
163 scaleValidator->setDecimals(256); //I guess that will do
164 Scale->setValidator(scaleValidator);
165 Height->setValidator(unsignedLengthAutoValidator(Height, qt_(autostr)));
166 Width->setValidator(unsignedLengthAutoValidator(Width, qt_(autostr)));
167 angle->setValidator(new QDoubleValidator(-360, 360, 2, angle));
170 connect(clip, SIGNAL(stateChanged(int)),
171 this, SLOT(change_adaptor()));
172 connect(lbY, SIGNAL(textChanged(const QString&)),
173 this, SLOT(changeBB()));
174 connect(lbYunit, SIGNAL(activated(int)),
175 this, SLOT(changeBB()));
176 connect(rtY, SIGNAL(textChanged(const QString&)),
177 this, SLOT(changeBB()));
178 connect(rtYunit, SIGNAL(activated(int)),
179 this, SLOT(changeBB()));
180 connect(lbX, SIGNAL(textChanged(const QString&)),
181 this, SLOT(changeBB()));
182 connect(lbXunit, SIGNAL(activated(int)),
183 this, SLOT(changeBB()));
184 connect(rtX, SIGNAL(textChanged(const QString&)),
185 this, SLOT(changeBB()));
186 connect(rtXunit, SIGNAL(activated(int)),
187 this, SLOT(changeBB()));
188 connect(getPB, SIGNAL(clicked()),
189 this, SLOT(change_adaptor()));
191 lbX->setValidator(new QDoubleValidator(lbX));
192 lbY->setValidator(new QDoubleValidator(lbY));
193 rtX->setValidator(new QDoubleValidator(rtX));
194 rtY->setValidator(new QDoubleValidator(rtY));
197 connect(latexoptions, SIGNAL(textChanged(const QString&)),
198 this, SLOT(change_adaptor()));
199 connect(draftCB, SIGNAL(stateChanged(int)),
200 this, SLOT(change_adaptor()));
201 // FIXME: we should connect to clicked() when we move to Qt 4.2 because
202 // the toggled(bool) signal is also trigged when we update the widgets
203 // (rgh-4/07) this isn't as much or a problem as it was, because we're now
204 // using blockSignals() to keep from triggering that signal when we call
205 // setChecked(). Note, too, that clicked() would get called whenever it
206 // is clicked, even right clicked (I think), not just whenever it is
208 connect(displayGB, SIGNAL(toggled(bool)), this, SLOT(change_adaptor()));
209 connect(displayscale, SIGNAL(textChanged(const QString&)),
210 this, SLOT(change_adaptor()));
211 connect(groupCO, SIGNAL(currentIndexChanged(int)),
212 this, SLOT(changeGroup(int)));
214 displayscale->setValidator(new QIntValidator(displayscale));
216 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
218 bc().setApply(applyPB);
219 bc().setRestore(restorePB);
220 bc().setCancel(closePB);
222 bc().addReadOnly(latexoptions);
223 bc().addReadOnly(filenameL);
224 bc().addReadOnly(filename);
225 bc().addReadOnly(browsePB);
226 bc().addReadOnly(bbFrame);
227 bc().addReadOnly(draftCB);
228 bc().addReadOnly(clip);
229 bc().addReadOnly(displayGB);
230 bc().addReadOnly(sizeGB);
231 bc().addReadOnly(rotationGB);
232 bc().addReadOnly(latexoptions);
233 bc().addReadOnly(getPB);
234 bc().addReadOnly(rotateOrderCB);
236 // initialize the length validator
237 bc().addCheckedLineEdit(Scale, scaleCB);
238 bc().addCheckedLineEdit(Width, WidthCB);
239 bc().addCheckedLineEdit(Height, HeightCB);
240 bc().addCheckedLineEdit(displayscale, scaleLA);
241 bc().addCheckedLineEdit(angle, angleL);
242 bc().addCheckedLineEdit(lbX, xL);
243 bc().addCheckedLineEdit(lbY, yL);
244 bc().addCheckedLineEdit(rtX, xL_2);
245 bc().addCheckedLineEdit(rtY, yL_2);
246 bc().addCheckedLineEdit(filename, filenameL);
250 void GuiGraphics::change_adaptor()
253 string const fname = fromqstr(filename->text());
254 FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
255 Format const * fmt = theFormats().getFormat(theFormats().getFormatFromFile(dest_fname));
256 LYXERR(Debug::GRAPHICS, "fmt: " << fmt
257 << ", fmt_name: " << theFormats().getFormatFromFile(dest_fname));
258 editPB->setEnabled(!fname.empty() && !dest_fname.isDirectory() && dest_fname.exists());
259 chooseSamplePB->setEnabled(!fname.empty() && !dest_fname.isDirectory());
263 void GuiGraphics::changeGroup(int /* index */)
265 QString const new_group = groupCO->itemData(
266 groupCO->currentIndex()).toString();
268 // check if the old group consisted only of this member
269 if (current_group_ != fromqstr(new_group)
270 && graphics::countGroupMembers(buffer(), current_group_) == 1) {
271 if (!new_group.isEmpty()) {
272 if (Alert::prompt(_("Dissolve previous group?"),
273 bformat(_("If you assign this graphic to group '%2$s',\n"
274 "the previously assigned group '%1$s' will be dissolved,\n"
275 "because this graphic was its only member.\n"
276 "How do you want to proceed?"),
277 from_utf8(current_group_), qstring_to_ucs4(new_group)),
279 bformat(_("Stick with group '%1$s'"),
280 from_utf8(current_group_)),
281 bformat(_("Assign to group '%1$s' anyway"),
282 qstring_to_ucs4(new_group))) == 0) {
283 groupCO->setCurrentIndex(
284 groupCO->findData(toqstr(current_group_), Qt::MatchExactly));
288 if (Alert::prompt(_("Dissolve previous group?"),
289 bformat(_("If you sign off this graphic from group '%1$s',\n"
290 "the group will be dissolved,\n"
291 "because this graphic was its only member.\n"
292 "How do you want to proceed?"),
293 from_utf8(current_group_)),
295 bformat(_("Stick with group '%1$s'"),
296 from_utf8(current_group_)),
297 bformat(_("Sign off from group '%1$s'"),
298 from_utf8(current_group_))) == 0) {
299 groupCO->setCurrentIndex(
300 groupCO->findData(toqstr(current_group_), Qt::MatchExactly));
306 if (new_group.isEmpty()) {
311 string grp = graphics::getGroupParams(buffer(), fromqstr(new_group));
313 // group does not exist yet
318 // filename might have been changed
319 QString current_filename = filename->text();
321 // group exists: load params into the dialog
322 groupCO->blockSignals(true);
323 InsetGraphics::string2params(grp, buffer(), params_);
324 paramsToDialog(params_);
325 groupCO->blockSignals(false);
328 filename->setText(current_filename);
334 void GuiGraphics::on_newGroupPB_clicked()
337 if (!Alert::askForText(newgroup, _("Enter unique group name:")))
339 if (newgroup.empty())
341 if (groupCO->findData(toqstr(newgroup), Qt::MatchExactly) != -1) {
342 Alert::warning(_("Group already defined!"),
343 bformat(_("A graphics group with the name '%1$s' already exists."),
347 groupCO->addItem(toqstr(newgroup), toqstr(newgroup));
348 groupCO->setCurrentIndex(
349 groupCO->findData(toqstr(newgroup), Qt::MatchExactly));
353 void GuiGraphics::changeBB()
356 LYXERR(Debug::GRAPHICS, "[bb_Changed set to true]");
361 void GuiGraphics::on_browsePB_clicked()
363 QString const str = browse(filename->text());
364 if (!str.isEmpty()) {
365 filename->setText(str);
371 bool GuiGraphics::checkFileExists()
373 string const fname = fromqstr(filename->text());
374 FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
375 if (fname.empty() || !dest_fname.exists()) {
376 return frontend::Alert::prompt(
377 _("Continue?"), bformat(_("File '%1$s' does not exist. Continue?"), from_utf8(dest_fname.absFileName())),
378 0, 1, _("&Yes"), _("&No")) == 0;
384 void GuiGraphics::on_chooseSamplePB_clicked()
386 string fname = fromqstr(filename->text());
387 FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
388 string fmt_name = theFormats().getFormatFromFile(FileName(fname));
389 string filter("Any file (*.*)");
390 if (!fmt_name.empty()) {
391 Format const *fmt = theFormats().getFormat(fmt_name);
392 filter = to_utf8(fmt->prettyname()) + " Files (*." + dest_fname.extension() + ")";
394 if (fname.empty() || dest_fname.isDirectory()) {
395 frontend::Alert::warning(_("Invalid destination file name!"), _("Invalid destination file name!"));
399 QString const samplesDir = toqstr(addPath(package().user_support().absFileName(), "samples"));
400 string sample_name = fromqstr(QFileDialog::getOpenFileName(this, toqstr("Please, select sample template"), samplesDir, toqstr(filter)));
401 if (sample_name.empty())
402 // User pressed Cancel
404 FileName sample_fname = FileName(sample_name);
406 //FileName sample_fname = libFileSearch(toqstr("samples"), toqstr(sample_name));
407 if (sample_fname.isDirectory() || !sample_fname.exists()) {
408 frontend::Alert::warning(_("Invalid sample file name"), _("Invalid sample file name"));
412 string sample_fmt_name = theFormats().getFormatFromFile(sample_fname);
413 if (fmt_name.empty() && !sample_fmt_name.empty()) {
414 fmt_name = sample_fmt_name;
415 string ext = theFormats().getFormat(fmt_name)->extension();
417 fname = fname + "." + ext;
418 dest_fname.set(FileName(fromqstr(bufferFilePath())), fname);
419 filename->setText(toqstr(fname));
423 if (fname.empty() || dest_fname.isDirectory()) {
424 frontend::Alert::warning(_("Invalid destination file name!"), _("Cannot copy sample file on an invalid destination file!"));
428 if (!dest_fname.exists() || (dest_fname.exists() &&
429 frontend::Alert::prompt(
430 _("Overwrite?"), bformat(_("File '%1$s' already exists. Overwrite with sample from template?"), from_utf8(dest_fname.absFileName())),
431 0, 1, _("&Yes"), _("&No")) == 0)) {
432 sample_fname.copyTo(dest_fname);
433 dest_fname.refresh();
439 void GuiGraphics::on_editPB_clicked()
441 string const fname = fromqstr(filename->text());
442 FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
443 string fmt_name = theFormats().getFormatFromFile(FileName(fname));
444 if (checkFileExists())
445 theFormats().edit(buffer(), dest_fname, fmt_name);
449 void GuiGraphics::on_okPB_clicked()
451 if (checkFileExists())
456 void GuiGraphics::on_getPB_clicked()
462 void GuiGraphics::setAutoText()
464 if (scaleCB->isChecked())
466 if (!Scale->isEnabled() && Scale->text() != "100")
467 Scale->setText(qt_(autostr));
469 setAutoTextCB(WidthCB, Width, widthUnit);
470 setAutoTextCB(HeightCB, Height, heightUnit);
474 void GuiGraphics::on_scaleCB_toggled(bool setScale)
476 Scale->setEnabled(setScale);
478 Scale->setText("100");
479 Scale->setFocus(Qt::OtherFocusReason);
482 WidthCB->setDisabled(setScale);
483 WidthCB->blockSignals(true);
484 WidthCB->setChecked(false);
485 WidthCB->blockSignals(false);
486 Width->setEnabled(false);
487 widthUnit->setEnabled(false);
489 HeightCB->setDisabled(setScale);
490 HeightCB->blockSignals(true);
491 HeightCB->setChecked(false);
492 HeightCB->blockSignals(false);
493 Height->setEnabled(false);
494 heightUnit->setEnabled(false);
496 rotateOrderCB->setEnabled((WidthCB->isChecked() ||
497 HeightCB->isChecked() ||
498 scaleCB->isChecked()) &&
499 (angle->text() != "0"));
502 updateAspectRatioStatus();
506 void GuiGraphics::on_WidthCB_toggled(bool setWidth)
508 Width->setEnabled(setWidth);
509 widthUnit->setEnabled(setWidth);
511 Width->setFocus(Qt::OtherFocusReason);
513 bool const setHeight = HeightCB->isChecked();
514 scaleCB->setEnabled(!setWidth && !setHeight);
515 //already will be unchecked, so don't need to do that
516 Scale->setEnabled((!setWidth && !setHeight) //=scaleCB->isEnabled()
517 && scaleCB->isChecked()); //should be false, but let's check
518 rotateOrderCB->setEnabled((setWidth || setHeight ||
519 scaleCB->isChecked()) &&
520 (angle->text() != "0"));
523 updateAspectRatioStatus();
527 void GuiGraphics::on_HeightCB_toggled(bool setHeight)
529 Height->setEnabled(setHeight);
530 heightUnit->setEnabled(setHeight);
532 Height->setFocus(Qt::OtherFocusReason);
534 bool const setWidth = WidthCB->isChecked();
535 scaleCB->setEnabled(!setWidth && !setHeight);
537 Scale->setEnabled((!setWidth && !setHeight) //=scaleCB->isEnabled()
538 && scaleCB->isChecked()); //should be false
539 rotateOrderCB->setEnabled((setWidth || setHeight ||
540 scaleCB->isChecked()) &&
541 (angle->text() != "0"));
544 updateAspectRatioStatus();
548 void GuiGraphics::updateAspectRatioStatus()
550 // keepaspectratio only makes sense if both a width _and_ a
551 // height are given, since its function is (see graphics manual):
552 // "If set to true then specifying both 'width' and 'height'
553 // (or 'totalheight') does not distort the figure but scales
554 // such that neither of the specified dimensions is _exceeded_."
555 aspectratio->setEnabled(
556 WidthCB->isChecked() && !Width->text().isEmpty()
557 && Width->text() != qt_(autostr)
558 && HeightCB->isChecked() && !Height->text().isEmpty()
559 && Height->text() != qt_(autostr)
561 if (!aspectratio->isEnabled())
562 aspectratio->setChecked(false);
566 void GuiGraphics::on_aspectratio_toggled(bool aspectratio)
569 WidthCB->setText(qt_("Set max. &width:"));
570 HeightCB->setText(qt_("Set max. &height:"));
571 Width->setToolTip(qt_("Maximal width of image in output"));
572 Height->setToolTip(qt_("Maximal height of image in output"));
574 WidthCB->setText(qt_("Set &width:"));
575 HeightCB->setText(qt_("Set &height:"));
576 Width->setToolTip(qt_("Width of image in output"));
577 Height->setToolTip(qt_("Height of image in output"));
582 void GuiGraphics::on_angle_textChanged(const QString & filename)
584 rotateOrderCB->setEnabled((WidthCB->isChecked() ||
585 HeightCB->isChecked() ||
586 scaleCB->isChecked()) &&
591 void GuiGraphics::paramsToDialog(InsetGraphicsParams const & igp)
593 static char const * const bb_units[] = { "bp", "cm", "mm", "in" };
594 static char const * const bb_units_gui[] = { N_("bp"), N_("cm"), N_("mm"), N_("in[[unit of measure]]") };
595 size_t const bb_size = sizeof(bb_units) / sizeof(bb_units[0]);
602 for (size_t i = 0; i < bb_size; i++) {
603 lbXunit->addItem(qt_(bb_units_gui[i]),
604 toqstr(bb_units[i]));
605 lbYunit->addItem(qt_(bb_units_gui[i]),
606 toqstr(bb_units[i]));
607 rtXunit->addItem(qt_(bb_units_gui[i]),
608 toqstr(bb_units[i]));
609 rtYunit->addItem(qt_(bb_units_gui[i]),
610 toqstr(bb_units[i]));
613 // set the right default unit
614 Length::UNIT const defaultUnit = Length::defaultUnit();
616 //lyxerr << bufferFilePath();
618 igp.filename.outputFileName(fromqstr(bufferFilePath()));
619 filename->setText(toqstr(name));
621 // set the bounding box values
622 if (igp.bbox.empty()) {
623 string const bb = readBoundingBox(igp.filename.absFileName());
624 // the values from the file always have the bigpoint-unit bp
625 doubleToWidget(lbX, token(bb, ' ', 0));
626 doubleToWidget(lbY, token(bb, ' ', 1));
627 doubleToWidget(rtX, token(bb, ' ', 2));
628 doubleToWidget(rtY, token(bb, ' ', 3));
629 lbXunit->setCurrentIndex(0);
630 lbYunit->setCurrentIndex(0);
631 rtXunit->setCurrentIndex(0);
632 rtYunit->setCurrentIndex(0);
635 // get the values from the inset
636 doubleToWidget(lbX, igp.bbox.xl.value());
637 string unit = unit_name[igp.bbox.xl.unit()];
638 lbXunit->setCurrentIndex(lbXunit->findData(toqstr(unit)));
639 doubleToWidget(lbY, igp.bbox.yb.value());
640 unit = unit_name[igp.bbox.yb.unit()];
641 lbYunit->setCurrentIndex(lbYunit->findData(toqstr(unit)));
642 doubleToWidget(rtX, igp.bbox.xr.value());
643 unit = unit_name[igp.bbox.xr.unit()];
644 rtXunit->setCurrentIndex(rtXunit->findData(toqstr(unit)));
645 doubleToWidget(rtY, igp.bbox.yt.value());
646 unit = unit_name[igp.bbox.yt.unit()];
647 rtYunit->setCurrentIndex(rtYunit->findData(toqstr(unit)));
651 // Update the draft and clip mode
652 draftCB->setChecked(igp.draft);
653 clip->setChecked(igp.clip);
654 displayGB->setChecked(igp.display);
655 displayscale->setText(toqstr(convert<string>(igp.lyxscale)));
657 // the output section (width/height)
659 doubleToWidget(Scale, igp.scale);
660 //igp.scale defaults to 100, so we treat it as empty
661 bool const scaleChecked = !igp.scale.empty() && igp.scale != "100";
662 scaleCB->blockSignals(true);
663 scaleCB->setChecked(scaleChecked);
664 scaleCB->blockSignals(false);
665 Scale->setEnabled(scaleChecked);
666 displayGB->setEnabled(lyxrc.display_graphics);
669 graphics::getGraphicsGroups(buffer(), grp);
670 set<string>::const_iterator it = grp.begin();
671 set<string>::const_iterator end = grp.end();
672 groupCO->blockSignals(true);
674 for (; it != end; ++it)
675 groupCO->addItem(toqstr(*it), toqstr(*it));
676 groupCO->insertItem(0, qt_("None"), QString());
677 if (igp.groupId.empty())
678 groupCO->setCurrentIndex(0);
680 groupCO->setCurrentIndex(
681 groupCO->findData(toqstr(igp.groupId), Qt::MatchExactly));
682 groupCO->blockSignals(false);
684 if (igp.width.value() == 0)
685 lengthToWidgets(Width, widthUnit, _(autostr), defaultUnit);
687 lengthToWidgets(Width, widthUnit, igp.width, defaultUnit);
689 bool const widthChecked = !Width->text().isEmpty() &&
690 Width->text() != qt_(autostr);
691 WidthCB->blockSignals(true);
692 WidthCB->setChecked(widthChecked);
693 WidthCB->blockSignals(false);
694 Width->setEnabled(widthChecked);
695 widthUnit->setEnabled(widthChecked);
697 if (igp.height.value() == 0)
698 lengthToWidgets(Height, heightUnit, _(autostr), defaultUnit);
700 lengthToWidgets(Height, heightUnit, igp.height, defaultUnit);
702 bool const heightChecked = !Height->text().isEmpty()
703 && Height->text() != qt_(autostr);
704 HeightCB->blockSignals(true);
705 HeightCB->setChecked(heightChecked);
706 HeightCB->blockSignals(false);
707 Height->setEnabled(heightChecked);
708 heightUnit->setEnabled(heightChecked);
710 scaleCB->setEnabled(!widthChecked && !heightChecked);
711 WidthCB->setEnabled(!scaleChecked);
712 HeightCB->setEnabled(!scaleChecked);
715 updateAspectRatioStatus();
717 doubleToWidget(angle, igp.rotateAngle);
718 rotateOrderCB->setChecked(igp.scaleBeforeRotation);
720 rotateOrderCB->setEnabled( (widthChecked || heightChecked || scaleChecked)
721 && igp.rotateAngle != "0");
725 for (size_t i = 0; i < rorigin_size; i++) {
726 origin->addItem(qt_(rorigin_gui_strs[i]),
727 toqstr(rorigin_lyx_strs[i]));
730 if (!igp.rotateOrigin.empty())
731 origin->setCurrentIndex(origin->findData(toqstr(igp.rotateOrigin)));
733 origin->setCurrentIndex(0);
736 latexoptions->setText(toqstr(igp.special));
738 filename->setFocus();
742 void GuiGraphics::applyView()
744 InsetGraphicsParams & igp = params_;
746 igp.filename.set(fromqstr(filename->text()), fromqstr(bufferFilePath()));
749 igp.bbox = graphics::BoundingBox();
751 string lbXs = widgetToDoubleStr(lbX);
752 string lbYs = widgetToDoubleStr(lbY);
753 string rtXs = widgetToDoubleStr(rtX);
754 string rtYs = widgetToDoubleStr(rtY);
756 convert<int>(lbXs) + convert<int>(lbYs) +
757 convert<int>(rtXs) + convert<int>(rtXs);
761 igp.bbox.xl = Length(lbXs + fromqstr(lbXunit->currentText()));
764 igp.bbox.yb = Length(lbYs + fromqstr(lbYunit->currentText()));
767 igp.bbox.xr = Length(rtXs + fromqstr(rtXunit->currentText()));
770 igp.bbox.yt = Length(rtYs + fromqstr(rtYunit->currentText()));
774 igp.draft = draftCB->isChecked();
775 igp.clip = clip->isChecked();
776 igp.display = displayGB->isChecked();
778 //the graphics section
779 if (scaleCB->isChecked() && !Scale->text().isEmpty()) {
780 igp.scale = widgetToDoubleStr(Scale);
781 igp.width = Length("0pt");
782 igp.height = Length("0pt");
783 igp.keepAspectRatio = false;
785 igp.scale = string();
786 igp.width = WidthCB->isChecked() ?
787 //Note that this works even if Width is "auto", since in
788 //that case we get "0pt".
789 Length(widgetsToLength(Width, widthUnit)):
791 igp.height = HeightCB->isChecked() ?
792 Length(widgetsToLength(Height, heightUnit)) :
794 igp.keepAspectRatio = aspectratio->isChecked();
797 igp.lyxscale = displayscale->text().toInt();
798 igp.rotateAngle = widgetToDoubleStr(angle);
800 double rotAngle = widgetToDouble(angle);
801 if (abs(rotAngle) > 360.0) {
802 rotAngle -= 360.0 * floor(rotAngle / 360.0);
803 igp.rotateAngle = convert<string>(rotAngle);
806 // save the latex name for the origin. If it is the default
807 // then origin_ltx returns ""
809 fromqstr(origin->itemData(origin->currentIndex()).toString());
810 igp.scaleBeforeRotation = rotateOrderCB->isChecked();
812 // more latex options
813 igp.special = fromqstr(latexoptions->text());
815 igp.groupId = fromqstr(groupCO->itemData(
816 groupCO->currentIndex()).toString());
817 current_group_ = igp.groupId;
821 void GuiGraphics::getBB()
823 string const fn = fromqstr(filename->text());
826 string const bb = readBoundingBox(fn);
830 doubleToWidget(lbX, token(bb, ' ', 0));
831 doubleToWidget(lbY, token(bb, ' ', 1));
832 doubleToWidget(rtX, token(bb, ' ', 2));
833 doubleToWidget(rtY, token(bb, ' ', 3));
834 // the default units for the bb values when reading
836 lbXunit->setCurrentIndex(0);
837 lbYunit->setCurrentIndex(0);
838 rtXunit->setCurrentIndex(0);
839 rtYunit->setCurrentIndex(0);
843 bool GuiGraphics::isValid()
845 return !filename->text().isEmpty();
849 bool GuiGraphics::initialiseParams(string const & data)
851 InsetGraphics::string2params(data, buffer(), params_);
852 paramsToDialog(params_);
853 current_group_ = params_.groupId;
858 void GuiGraphics::clearParams()
860 params_ = InsetGraphicsParams();
864 void GuiGraphics::dispatchParams()
866 InsetGraphicsParams tmp_params(params_);
867 string const lfun = InsetGraphics::params2string(tmp_params, buffer());
868 dispatch(FuncRequest(getLfun(), lfun));
872 QString GuiGraphics::browse(QString const & in_name) const
874 QString const title = qt_("Select graphics file");
876 // Does user clipart directory exist?
877 string clipdir = addName(package().user_support().absFileName(), "clipart");
878 FileName clip(clipdir);
880 // bail out to system clipart directory
881 if (!clip.isDirectory())
882 clipdir = addName(package().system_support().absFileName(), "clipart");
884 return browseRelToParent(in_name, bufferFilePath(),
885 title, fileFilters(QString()), false,
886 qt_("Clipart|#C#c"), toqstr(clipdir),
887 qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
891 string GuiGraphics::readBoundingBox(string const & file)
893 FileName const abs_file = support::makeAbsPath(file, fromqstr(bufferFilePath()));
895 // try to get it from the file, if possible. Zipped files are
896 // unzipped in the readBB_from_PSFile-Function
897 string const bb = graphics::readBB_from_PSFile(abs_file);
901 // we don't, so ask the Graphics Cache if it has loaded the file
905 graphics::Cache & gc = graphics::Cache::get();
906 if (gc.inCache(abs_file)) {
907 graphics::Image const * image = gc.item(abs_file)->image();
910 width = image->width();
911 height = image->height();
915 return ("0 0 " + convert<string>(width) + ' ' + convert<string>(height));
919 bool GuiGraphics::isFileNameValid(string const & fname) const
921 // It may be that the filename is relative.
922 return support::makeAbsPath(fname, fromqstr(bufferFilePath())).isReadableFile();
926 Dialog * createGuiGraphics(GuiView & lv) { return new GuiGraphics(lv); }
929 } // namespace frontend
932 #include "moc_GuiGraphics.cpp"