3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Bernhard Reiter
8 * Full author contact details are available in file CREDITS.
13 // Too hard to make concept checks work with this file
14 #ifdef _GLIBCXX_CONCEPT_CHECKS
15 #undef _GLIBCXX_CONCEPT_CHECKS
17 #ifdef _GLIBCPP_CONCEPT_CHECKS
18 #undef _GLIBCPP_CONCEPT_CHECKS
21 #include "GExternal.h"
22 #include "ControlExternal.h"
24 #include "GtkLengthEntry.h"
28 #include "support/lstrings.h"
29 #include "support/convert.h"
30 #include "support/filefilterlist.h"
32 #include <libglademm.h>
38 using lyx::support::token;
39 using lyx::support::FileFilterList;
40 using lyx::support::trim;
50 class formatModelColumns : public Gtk::TreeModel::ColumnRecord
54 formatModelColumns() { add(name); add(extra); }
56 Gtk::TreeModelColumn<Glib::ustring> name;
57 Gtk::TreeModelColumn<Glib::ustring> extra;
61 class displayModelColumns : public Gtk::TreeModel::ColumnRecord
65 displayModelColumns() { add(name); add(type); }
67 Gtk::TreeModelColumn<Glib::ustring> name;
68 Gtk::TreeModelColumn<external::DisplayType> type;
72 class templateModelColumns : public Gtk::TreeModel::ColumnRecord
76 templateModelColumns() { add(name); add(info); add(filters);}
78 Gtk::TreeModelColumn<Glib::ustring> name;
79 Gtk::TreeModelColumn<Glib::ustring> info;
80 Gtk::TreeModelColumn<std::vector<Gtk::FileFilter* > > filters;
85 formatModelColumns formatColumns;
88 /* ...ModelColumns singletons, cf. Scott Meyers, Effective C++, Item 47
89 * Needed for proper initialization of the displayModelColumns::type member
90 * which in turn needs to be Glib::Value<>::init'ed in time
92 displayModelColumns& displayColumns() {
93 static displayModelColumns dC;
98 templateModelColumns& templateColumns() {
99 static templateModelColumns tC;
104 /// Produces a vector of Gtk::FileFilter*s out of the controller's filterstring
105 /// providing sensible descriptions (with alttitle as a fallback)
106 std::vector<Gtk::FileFilter* > get_filters(docstring const & filterstring, docstring const & alttitle)
108 FileFilterList filterlist(filterstring);
109 std::vector<Gtk::FileFilter* > filters(filterlist.size());
111 for (unsigned int i=0; i < filterlist.size(); ++i) {
112 FileFilterList::Filter ff = filterlist[i];
114 filters[i] = new Gtk::FileFilter();
115 docstring const description = ff.description();
117 if (description.empty())
118 filters[i]->set_name(lyx::to_utf8(alttitle + ' ' + _("files")));
120 filters[i]->set_name(lyx::to_utf8(description));
122 for (FileFilterList::Filter::glob_iterator git = ff.begin();
123 git!=ff.end(); ++git)
124 filters[i]->add_pattern(*git);
130 void set_display(Gtk::CheckButton * show_check, Gtk::ComboBox * display_combo,
131 Gtk::Label * display_label, GtkLengthEntry * scale_length,
132 Gtk::Label * scale_label,
133 external::DisplayType display, unsigned int scale)
136 typedef Gtk::TreeModel::const_iterator gcit;
137 Glib::RefPtr<const Gtk::TreeModel> const display_store =
138 display_combo->get_model();
139 bool const no_display = display == external::NoDisplay;
142 display_combo->set_active(
143 *(display_store->children().begin())); //Default
145 for (gcit it = display_store->children().begin();
146 it != display_store->children().end(); ++it) {
147 if ((*it)[displayColumns().type] == display) {
148 display_combo->set_active(*it);
153 scale_length->get_spin()->set_value(scale);
154 show_check->set_active(!no_display);
156 display_label->set_sensitive(!no_display);
157 display_combo->set_sensitive(!no_display);
158 scale_label->set_sensitive(!no_display);
159 scale_length->set_sensitive(!no_display);
163 void get_display(external::DisplayType & display,
164 unsigned int & scale,
165 Gtk::CheckButton const * show_check,
166 Gtk::ComboBox const * display_combo,
167 GtkLengthEntry const * scale_length)
169 display = (*(display_combo->get_active()))[displayColumns().type];
170 if (!show_check->get_active())
171 display = external::NoDisplay;
172 scale = scale_length->get_spin()->get_value_as_int();
176 void set_rotation(Gtk::Entry * angle_entry, Gtk::ComboBox * origin_combo,
177 external::RotationData const & data)
179 origin_combo->set_active(int(data.origin()));
180 angle_entry->set_text(Glib::locale_to_utf8(data.angle));
184 void get_rotation(external::RotationData & data,
185 Gtk::Entry const * angle_entry,
186 Gtk::ComboBox const * origin_combo)
188 typedef external::RotationData::OriginType OriginType;
190 data.origin(static_cast<OriginType>(
191 origin_combo->get_active_row_number()));
192 data.angle = Glib::locale_from_utf8(angle_entry->get_text());
196 void set_size(GtkLengthEntry * width_length,
197 GtkLengthEntry * height_length,
198 Gtk::CheckButton * ar_check,
199 external::ResizeData const & data)
201 bool using_scale = data.usingScale();
202 double scale = convert<double>(data.scale);
203 if (data.no_resize()) {
204 // Everything is zero, so default to this!
210 width_length->get_spin()->set_value(scale);
211 width_length->get_combo()->set_active_text(
212 lyx::to_utf8(_("Scale%")));
214 width_length->set_length(data.width);
217 height_length->set_length(data.height);
218 if (!data.width.zero())
219 height_length->get_combo()->set_active(data.width.unit());
221 height_length->set_sensitive(!using_scale);
223 ar_check->set_active(data.keepAspectRatio);
225 bool const disable_aspectRatio = using_scale ||
226 data.width.zero() || data.height.zero();
227 ar_check->set_sensitive(!disable_aspectRatio);
231 void get_size(external::ResizeData & data,
232 GtkLengthEntry * width_length,
233 GtkLengthEntry * height_length,
234 Gtk::CheckButton * ar_check)
236 if (width_length->get_combo()->get_active_text() !=
237 lyx::to_utf8(_("Scale%"))) {
239 data.width = width_length->get_length();
240 data.scale = string();
242 // scaling instead of a width
243 data.scale = convert<string>(width_length->get_spin()->get_value());
244 data.width = LyXLength();
247 data.height = height_length->get_length();
249 data.keepAspectRatio = ar_check->get_active();
253 void set_crop(Gtk::CheckButton * clip_check,
254 Gtk::Entry * xl_entry, Gtk::Entry * yb_entry,
255 Gtk::Entry * xr_entry, Gtk::Entry * yt_entry,
256 external::ClipData const & data)
258 clip_check->set_active(data.clip);
259 graphics::BoundingBox const & bbox = data.bbox;
260 xl_entry->set_text(Glib::locale_to_utf8(convert<string>(bbox.xl)));
261 yb_entry->set_text(Glib::locale_to_utf8(convert<string>(bbox.yb)));
262 xr_entry->set_text(Glib::locale_to_utf8(convert<string>(bbox.xr)));
263 yt_entry->set_text(Glib::locale_to_utf8(convert<string>(bbox.yt)));
268 void get_crop(external::ClipData & data,
269 Gtk::CheckButton const * clip_check,
270 Gtk::Entry const * xl_entry, Gtk::Entry const * yb_entry,
271 Gtk::Entry const * xr_entry, Gtk::Entry const * yt_entry,
274 data.clip = clip_check->get_active();
279 data.bbox.xl = convert<int>(Glib::locale_from_utf8(xl_entry->get_text()));
280 data.bbox.yb = convert<int>(Glib::locale_from_utf8(yb_entry->get_text()));
281 data.bbox.xr = convert<int>(Glib::locale_from_utf8(xr_entry->get_text()));
282 data.bbox.yt = convert<int>(Glib::locale_from_utf8(yt_entry->get_text()));
286 void get_extra(external::ExtraData & data,
287 Glib::RefPtr<Gtk::ListStore> format_store)
289 Gtk::TreeModel::iterator it = format_store->children().begin();
290 Gtk::TreeModel::iterator end = format_store->children().end();
291 for (; it != end; ++it)
292 data.set(Glib::locale_from_utf8((*it)[formatColumns.name]),
293 trim(Glib::locale_from_utf8((*it)[formatColumns.extra])));
299 GExternal::GExternal(Dialog & parent)
300 : GViewCB<ControlExternal, GViewGladeB>(parent, _("External Settings"), false)
304 void GExternal::doBuild()
306 string const gladeName = findGladeFile("external");
307 xml_ = Gnome::Glade::Xml::create(gladeName);
309 xml_->get_widget("Cancel", cancelbutton_);
310 setCancel(cancelbutton_);
311 xml_->get_widget("Apply", applybutton_);
312 setApply(applybutton_);
313 xml_->get_widget("OK", okbutton_);
316 xml_->get_widget("notebook", notebook_);
318 templatestore_ = Gtk::ListStore::create(templateColumns());
320 std::vector<string> templates(controller().getTemplates());
323 std::vector<std::vector<Gtk::FileFilter> > myfilterlist;
325 // Fill the templates combo
326 for (std::vector<string>::const_iterator cit = templates.begin();
327 cit != templates.end(); ++cit, ++count) {
328 external::Template templ = controller().getTemplate(count);
330 Gtk::TreeModel::iterator iter = templatestore_->append();
331 (*iter)[templateColumns().name] = *cit;
332 (*iter)[templateColumns().info] = templ.helpText;
333 (*iter)[templateColumns().filters] = get_filters(
334 lyx::from_utf8(controller().getTemplateFilters(*cit)),
335 lyx::from_utf8(*cit));
339 xml_->get_widget("Template", templatecombo_);
340 templatecombo_->pack_start(templateColumns().name);
341 templatecombo_->set_model(templatestore_);
342 templatecombo_->signal_changed().connect(
343 sigc::mem_fun(*this, &GExternal::template_changed));
345 xml_->get_widget("TemplateView", templateview_);
347 templatebuffer_ = Gtk::TextBuffer::create();
348 templateview_->set_buffer(templatebuffer_);
350 // *** Start "File" Page ***
351 xml_->get_widget("TemplateFile", templatefcbutton_);
352 templatefcbutton_->set_title(lyx::to_utf8(_("Select external file")));
353 templatefcbutton_->signal_file_activated().connect(
354 sigc::mem_fun(*this, &GExternal::file_changed));
356 xml_->get_widget("FileLabel", filelabel_);
357 filelabel_->set_mnemonic_widget(*templatefcbutton_);
359 xml_->get_widget("Draft", draftcheck_);
360 xml_->get_widget("EditFile", editfilebutton_);
361 editfilebutton_->signal_clicked().connect(
362 sigc::mem_fun(*this, &GExternal::edit_clicked));
363 // *** End "File" Page ***
365 // *** Start "LyX View" Page ***
366 xml_->get_widget("ShowInLyX", showcheck_);
367 showcheck_->signal_toggled().connect(
368 sigc::mem_fun(*this, &GExternal::showcheck_toggled));
370 xml_->get_widget("DisplayLabel", displaylabel_);
372 displaystore_ = Gtk::ListStore::create(displayColumns());
374 // Fill the display combo
375 Gtk::TreeModel::iterator iter = displaystore_->append();
376 (*iter)[displayColumns().name] = lyx::to_utf8(_("Default"));
377 (*iter)[displayColumns().type] = external::DefaultDisplay;
378 iter = displaystore_->append();
379 (*iter)[displayColumns().name] = lyx::to_utf8(_("Monochrome"));
380 (*iter)[displayColumns().type] = external::MonochromeDisplay;
381 iter = displaystore_->append();
382 (*iter)[displayColumns().name] = lyx::to_utf8(_("Grayscale"));
383 (*iter)[displayColumns().type] = external::GrayscaleDisplay;
384 iter = displaystore_->append();
385 (*iter)[displayColumns().name] = lyx::to_utf8(_("Color"));
386 (*iter)[displayColumns().type] = external::ColorDisplay;
387 iter = displaystore_->append();
388 (*iter)[displayColumns().name] = lyx::to_utf8(_("Preview"));
389 (*iter)[displayColumns().type] = external::PreviewDisplay;
391 xml_->get_widget("Display", displaycombo_);
392 displaycombo_->set_model(displaystore_);
393 displaycombo_->pack_start(displayColumns().name);
395 xml_->get_widget_derived ("Scale", scalelength_);
396 scalespin_ = scalelength_->get_spin();
397 scalespin_->set_digits(0);
398 scalespin_->set_range(0,100);
399 scalespin_->set_increments(1,10);
400 scalecombo_ = scalelength_->get_combo();
401 scalecombo_->clear();
402 scalecombo_->append_text(lyx::to_utf8(_("Scale%")));
403 scalecombo_->set_active_text(lyx::to_utf8(_("Scale%")));
405 xml_->get_widget("ScaleLabel", scalelabel_);
406 scalelabel_->set_mnemonic_widget(*scalespin_);
407 // *** End "LyX View" Page ***
409 // *** Start "Rotate" Page ***
410 xml_->get_widget("Angle", angleentry_);
412 Gtk::Box * box = NULL;
413 xml_->get_widget("OriginBox", box);
414 box->pack_start(origincombo_, true, true, 0);
417 // Fill the origins combo
418 typedef std::vector<external::RotationDataType> Origins;
419 Origins const & all_origins = external::all_origins();
420 for (Origins::size_type i = 0; i != all_origins.size(); ++i)
421 origincombo_.append_text(
422 external::origin_gui_str(i));
424 xml_->get_widget("OriginLabel", originlabel_);
425 originlabel_->set_mnemonic_widget(origincombo_);
426 // *** End "Rotate" Page ***
428 // *** Start "Scale" Page ***
429 xml_->get_widget_derived ("Width", widthlength_);
430 widthcombo_ = widthlength_->get_combo();
431 widthcombo_->prepend_text(lyx::to_utf8(_("Scale%")));
432 widthcombo_->set_active_text(lyx::to_utf8(_("Scale%")));
434 xml_->get_widget("WidthLabel", widthlabel_);
435 widthlabel_->set_mnemonic_widget(*(widthlength_->get_spin()));
437 xml_->get_widget_derived ("Height", heightlength_);
439 widthlength_->signal_changed().connect(
440 sigc::mem_fun(*this, &GExternal::size_changed));
441 heightlength_->signal_changed().connect(
442 sigc::mem_fun(*this, &GExternal::size_changed));
444 xml_->get_widget("HeightLabel", heightlabel_);
445 heightlabel_->set_mnemonic_widget(*(heightlength_->get_spin()));
447 xml_->get_widget ("AspectRatio", archeck_);
448 // *** End "Scale" Page ***
450 // *** Start "Crop" Page ***
451 xml_->get_widget("Clip", clipcheck_);
452 clipcheck_->signal_toggled().connect(
453 sigc::mem_fun(*this, &GExternal::clipcheck_toggled));
455 xml_->get_widget("GetFromFile", bbfromfilebutton_);
457 bbfromfilebutton_->signal_clicked().connect(
458 sigc::mem_fun(*this, &GExternal::get_bb));
460 xml_->get_widget("xLabel", xlabel_);
461 xml_->get_widget("yLabel", ylabel_);
462 xml_->get_widget("RightTopLabel", rtlabel_);
463 xml_->get_widget("LeftBottomLabel", lblabel_);
465 xml_->get_widget("xLeft", xlentry_);
466 xlentry_->signal_editing_done().connect(
467 sigc::mem_fun(*this, &GExternal::bb_changed));
469 xml_->get_widget("yBottom", ybentry_);
470 ybentry_->signal_editing_done().connect(
471 sigc::mem_fun(*this, &GExternal::bb_changed));
473 xml_->get_widget("xRight", xrentry_);
474 xrentry_->signal_editing_done().connect(
475 sigc::mem_fun(*this, &GExternal::bb_changed));
477 xml_->get_widget("yTop", ytentry_);
478 ytentry_->signal_editing_done().connect(
479 sigc::mem_fun(*this, &GExternal::bb_changed));
481 // *** End "Crop" Page ***
483 // *** Start "Options" Page ***
484 formatstore_ = Gtk::ListStore::create(formatColumns);
486 xml_->get_widget("Options", optionsview_);
487 optionsview_->set_model(formatstore_);
488 optionsview_->append_column(lyx::to_utf8(_("Forma_t")), formatColumns.name);
489 optionsview_->append_column_editable(lyx::to_utf8(_("O_ption")), formatColumns.extra);
490 // *** End "Options" Page ***
494 void GExternal::update()
496 InsetExternalParams const & params = controller().params();
498 std::string const name = params.filename.outputFilename();
499 templatefcbutton_->set_filename(name);
501 if (name != Glib::ustring()) {
503 editfilebutton_->set_sensitive(true);
504 bbfromfilebutton_->set_sensitive(true);
507 editfilebutton_->set_sensitive(false);
508 bbfromfilebutton_->set_sensitive(false);
511 templatecombo_->set_active(
512 controller().getTemplateNumber(params.templatename()));
515 draftcheck_->set_active(params.draft);
517 set_display(showcheck_, displaycombo_, displaylabel_, scalelength_, scalelabel_, params.display, params.lyxscale);
519 set_rotation(angleentry_, &origincombo_, params.rotationdata);
521 set_size(widthlength_, heightlength_, archeck_, params.resizedata);
528 controller().bbChanged(!params.clipdata.bbox.empty());
532 void GExternal::update_template()
534 external::Template templ =
535 controller().getTemplate(
536 templatecombo_->get_active_row_number());
538 // Remove file stale filters, if present
539 // Keep the current file selected even after a template change
540 Glib::ustring currentfilename;
542 typedef std::vector<Gtk::FileFilter* >::iterator ffit;
543 std::vector<Gtk::FileFilter* > templatefilters;
545 if (currenttemplate_) {
546 currentfilename = templatefcbutton_->get_filename();
548 (*currenttemplate_)[templateColumns().filters];
550 for (ffit it = templatefilters.begin();
551 it != templatefilters.end(); ++it)
552 templatefcbutton_->remove_filter(**it);
555 currenttemplate_ = templatecombo_->get_active();
557 templatebuffer_->set_text((*currenttemplate_)[templateColumns().info]);
559 // Ascertain which (if any) transformations the template supports
560 // and disable tabs hosting unsupported transforms.
561 typedef std::vector<external::TransformID> TransformIDs;
562 TransformIDs const transformIds = templ.transformIds;
563 TransformIDs::const_iterator tr_begin = transformIds.begin();
564 TransformIDs::const_iterator const tr_end = transformIds.end();
566 bool found = find(tr_begin, tr_end, external::Rotate) != tr_end;
567 Gtk::Widget * widget = notebook_->get_nth_page(2);
568 widget->set_sensitive(found);
569 notebook_->get_tab_label(*widget)->set_sensitive(found);
571 found = find(tr_begin, tr_end, external::Resize) != tr_end;
572 widget = notebook_->get_nth_page(3);
573 widget->set_sensitive(found);
574 notebook_->get_tab_label(*widget)->set_sensitive(found);
576 found = find(tr_begin, tr_end, external::Clip) != tr_end;
577 widget = notebook_->get_nth_page(4);
578 widget->set_sensitive(found);
579 notebook_->get_tab_label(*widget)->set_sensitive(found);
581 found = find(tr_begin, tr_end, external::Extra) != tr_end;
582 widget = notebook_->get_nth_page(5);
583 widget->set_sensitive(found);
584 notebook_->get_tab_label(*widget)->set_sensitive(found);
586 // Add new filters; set the "All files" filter
587 // in order to allow the previously selected file to remain selected
588 templatefilters = (*currenttemplate_)[templateColumns().filters];
589 for (ffit it = templatefilters.begin();
590 it != templatefilters.end(); ++it)
591 templatefcbutton_->add_filter(**it);
593 templatefcbutton_->set_filter(*templatefilters.back()); // "All files"
595 if (currentfilename != Glib::ustring())
596 templatefcbutton_->set_filename(currentfilename);
601 // Ascertain whether the template has any formats supporting
602 // the 'Extra' option
603 Glib::ustring templatename =
604 (*currenttemplate_)[templateColumns().name];
605 formatstore_->clear();
606 external::Template::Formats::const_iterator it = templ.formats.begin();
607 external::Template::Formats::const_iterator end = templ.formats.end();
609 bool const enabled = (it != end);
611 for (; it != end; ++it) {
612 if (it->second.option_transformers.find(external::Extra) ==
613 it->second.option_transformers.end())
615 string const format = it->first;
616 string const opt = controller().params().extradata.get(format);
618 Gtk::TreeModel::iterator iter = formatstore_->append();
619 (*iter)[formatColumns.name] = Glib::locale_to_utf8(format);
620 (*iter)[formatColumns.extra] = Glib::locale_to_utf8(opt);
623 // widget is still the 'Options' tab
624 notebook_->get_tab_label(*widget)->set_sensitive(enabled);
628 void GExternal::apply()
630 InsetExternalParams params = controller().params();
632 params.filename.set(templatefcbutton_->get_filename(),
633 kernel().bufferFilepath());
636 Glib::locale_from_utf8((*(templatecombo_->get_active()))[templateColumns().name]));
638 params.draft = draftcheck_->get_active();
640 get_display(params.display, params.lyxscale,
641 showcheck_, displaycombo_, scalelength_);
643 if (notebook_->get_nth_page(2)->is_sensitive())
644 get_rotation(params.rotationdata,
645 angleentry_, &origincombo_);
647 if (notebook_->get_nth_page(3)->is_sensitive())
648 get_size(params.resizedata,
649 widthlength_, heightlength_, archeck_);
651 if (notebook_->get_nth_page(4)->is_sensitive())
652 get_crop(params.clipdata,
656 controller().bbChanged());
658 if (notebook_->get_nth_page(5)->is_sensitive())
659 get_extra(params.extradata, formatstore_);
661 controller().setParams(params);
665 void GExternal::get_bb()
667 xlentry_->set_text("0");
668 ybentry_->set_text("0");
669 xrentry_->set_text("0");
670 ytentry_->set_text("0");
672 string const filename = templatefcbutton_->get_filename();
673 if (filename.empty())
676 string const bb = controller().readBB(filename);
680 xlentry_->set_text(Glib::locale_to_utf8(token(bb, ' ', 0)));
681 ybentry_->set_text(Glib::locale_to_utf8(token(bb, ' ', 1)));
682 xrentry_->set_text(Glib::locale_to_utf8(token(bb, ' ', 2)));
683 ytentry_->set_text(Glib::locale_to_utf8(token(bb, ' ', 3)));
685 controller().bbChanged(false);
690 bool GExternal::activate_ar() const
692 if (widthlength_->get_combo()->get_active_text() ==
693 lyx::to_utf8(_("Scale%")))
696 if (widthlength_->get_spin()->get_value() < 0.05)
699 if (heightlength_->get_spin()->get_value() < 0.05)
706 void GExternal::bb_changed()
708 controller().bbChanged(true);
713 void GExternal::edit_clicked()
715 controller().editExternal();
719 void GExternal::size_changed()
721 archeck_->set_sensitive(activate_ar());
723 bool useHeight = widthlength_->get_combo()->get_active_text() !=
724 lyx::to_utf8(_("Scale%"));
726 heightlength_->set_sensitive(useHeight);
730 void GExternal::template_changed()
737 void GExternal::showcheck_toggled()
739 bool checked = showcheck_->get_active();
740 displaylabel_->set_sensitive(checked);
741 displaycombo_->set_sensitive(checked);
742 scalelabel_->set_sensitive(checked);
743 scalelength_->set_sensitive(checked);
749 void GExternal::clipcheck_toggled()
751 bool checked = clipcheck_->get_active();
753 xlabel_->set_sensitive(checked);
754 ylabel_->set_sensitive(checked);
755 rtlabel_->set_sensitive(checked);
756 lblabel_->set_sensitive(checked);
758 xlentry_->set_sensitive(checked);
759 ybentry_->set_sensitive(checked);
760 xrentry_->set_sensitive(checked);
761 ytentry_->set_sensitive(checked);
767 void GExternal::file_changed()
769 if (templatefcbutton_->get_filename() != Glib::ustring()) {
771 editfilebutton_->set_sensitive(true);
772 bbfromfilebutton_->set_sensitive(true);
775 editfilebutton_->set_sensitive(false);
776 bbfromfilebutton_->set_sensitive(false);
782 } // namespace frontend