]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GGraphics.C
Change glob() API to accept a dir parameter.
[lyx.git] / src / frontends / gtk / GGraphics.C
1 /**
2  * \file GGraphics.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Spray
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 // Too hard to make concept checks work with this file
14 #ifdef _GLIBCPP_CONCEPT_CHECKS
15 #undef _GLIBCPP_CONCEPT_CHECKS
16 #endif
17
18 #include "GGraphics.h"
19 #include "ControlGraphics.h"
20
21 #include "ghelpers.h"
22
23 #include "controllers/helper_funcs.h"
24
25 #include "insets/insetgraphicsParams.h"
26 #include "paper.h"
27 #include "lyxrc.h" // for lyxrc.default_papersize
28
29 #include "support/lyxlib.h"  // for float_equal
30 #include "support/lstrings.h"
31
32 #include "debug.h"
33
34 using std::vector;
35 using std::string;
36
37 namespace lyx {
38
39 using support::float_equal;
40 using support::token;
41
42 namespace frontend {
43
44 namespace {
45 string defaultUnit("cm");
46 } // namespace anon
47
48 GGraphics::GGraphics(Dialog & parent)
49         : GViewCB<ControlGraphics, GViewGladeB>(parent, _("Graphics"), false)
50 {}
51
52
53 void GGraphics::doBuild()
54 {
55         string const gladeName = findGladeFile("graphics");
56         xml_ = Gnome::Glade::Xml::create(gladeName);
57
58         Gtk::Button * button;
59         xml_->get_widget("Close", button);
60         setCancel(button);
61         xml_->get_widget("Ok", button);
62         setOK(button);
63         xml_->get_widget("Apply", button);
64         setApply(button);
65         xml_->get_widget("Restore", button);
66         setRestore(button);
67
68         xml_->get_widget("Notebook", notebook_);
69
70         // File Page
71         xml_->get_widget("File", fileentry_);
72         xml_->get_widget("DisplayScale", displayscalespin_);
73         xml_->get_widget("OutputScale", outputscalespin_);
74         xml_->get_widget("Browse", browsebutton_);
75         xml_->get_widget("Edit", editbutton_);
76         xml_->get_widget("Display", displaycombo_);
77         xml_->get_widget("Width", widthspin_);
78         xml_->get_widget("Height", heightspin_);
79         xml_->get_widget("MaintainAspectRatio", aspectcheck_);
80         xml_->get_widget("WidthUnits", widthunitscombo_);
81         xml_->get_widget("HeightUnits", heightunitscombo_);
82         xml_->get_widget("SetScaling", setscalingradio_);
83         xml_->get_widget("SetSize", setsizeradio_);
84
85         // Bounding Box Page
86         xml_->get_widget("ClipToBoundingBox", clipcheck_);
87         xml_->get_widget("RightTopX", righttopxspin_);
88         xml_->get_widget("RightTopY", righttopyspin_);
89         xml_->get_widget("LeftBottomX", leftbottomxspin_);
90         xml_->get_widget("LeftBottomY", leftbottomyspin_);
91         xml_->get_widget("BoundingUnits", bbunitscombo_);
92         xml_->get_widget("GetFromFile", bbfromfilebutton_);
93
94         // Extra Page
95         xml_->get_widget("Angle", anglespin_);
96         xml_->get_widget("Origin", origincombo_);
97         xml_->get_widget("UseSubfigure", subfigcheck_);
98         xml_->get_widget("SubfigureCaption", subfigentry_);
99         xml_->get_widget("LatexOptions", latexoptsentry_);
100         xml_->get_widget("DraftMode", draftcheck_);
101         xml_->get_widget("UnzipOnExport", unzipcheck_);
102
103         // Setup the columnrecord we use for combos
104         cols_.add(stringcol_);
105
106         // The file page
107
108         // Disable for read-only documents.
109         bcview().addReadOnly(browsebutton_);
110         bcview().addReadOnly(aspectcheck_);
111
112         fileentry_->signal_changed().connect(
113                 sigc::mem_fun(*this, &GGraphics::onInput));
114         displayscalespin_->signal_changed().connect(
115                 sigc::mem_fun(*this, &GGraphics::onInput));
116         displaycombo_->signal_changed().connect(
117                 sigc::mem_fun(*this, &GGraphics::onInput));
118         outputscalespin_->signal_changed().connect(
119                 sigc::mem_fun(*this, &GGraphics::onInput));
120         heightspin_->signal_changed().connect(
121                 sigc::mem_fun(*this, &GGraphics::onInput));
122         heightunitscombo_->signal_changed().connect(
123                 sigc::mem_fun(*this, &GGraphics::onInput));
124         widthspin_->signal_changed().connect(
125                 sigc::mem_fun(*this, &GGraphics::onInput));
126         widthunitscombo_->signal_changed().connect(
127                 sigc::mem_fun(*this, &GGraphics::onInput));
128         aspectcheck_->signal_toggled().connect(
129                 sigc::mem_fun(*this, &GGraphics::onInput));
130
131         setscalingradio_->signal_toggled().connect(
132                 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
133         setsizeradio_->signal_toggled().connect(
134                 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
135
136         browsebutton_->signal_clicked().connect(
137                 sigc::mem_fun(*this, &GGraphics::onBrowseClicked));
138
139         editbutton_->signal_clicked().connect(
140                 sigc::mem_fun(*this, &GGraphics::onEditClicked));
141
142         vector<string> const unit_list = buildLengthUnitList();
143         PopulateComboBox(heightunitscombo_, unit_list);
144         PopulateComboBox(widthunitscombo_, unit_list);
145
146         // the bounding box page
147         leftbottomxspin_->signal_changed().connect(
148                 sigc::mem_fun(*this, &GGraphics::onBBChange));
149         leftbottomyspin_->signal_changed().connect(
150                 sigc::mem_fun(*this, &GGraphics::onBBChange));
151         righttopxspin_->signal_changed().connect(
152                 sigc::mem_fun(*this, &GGraphics::onBBChange));
153         righttopyspin_->signal_changed().connect(
154                 sigc::mem_fun(*this, &GGraphics::onBBChange));
155         bbunitscombo_->signal_changed().connect(
156                 sigc::mem_fun(*this, &GGraphics::onBBChange));
157         clipcheck_->signal_toggled().connect(
158                 sigc::mem_fun(*this, &GGraphics::onBBChange));
159
160         bbfromfilebutton_->signal_clicked().connect(
161                 sigc::mem_fun(*this, &GGraphics::onBBFromFileClicked));
162
163         // disable for read-only documents
164         bcview().addReadOnly(bbfromfilebutton_);
165         bcview().addReadOnly(clipcheck_);
166         PopulateComboBox(bbunitscombo_, getBBUnits());
167
168
169         // the extra section
170
171         // disable for read-only documents
172         bcview().addReadOnly(anglespin_);
173         bcview().addReadOnly(origincombo_);
174         bcview().addReadOnly(subfigcheck_);
175         bcview().addReadOnly(latexoptsentry_);
176         bcview().addReadOnly(draftcheck_);
177         bcview().addReadOnly(unzipcheck_);
178
179         anglespin_->signal_changed().connect(
180                 sigc::mem_fun(*this, &GGraphics::onInput));
181         origincombo_->signal_changed().connect(
182                 sigc::mem_fun(*this, &GGraphics::onInput));
183         subfigentry_->signal_changed().connect(
184                 sigc::mem_fun(*this, &GGraphics::onInput));
185         latexoptsentry_->signal_changed().connect(
186                 sigc::mem_fun(*this, &GGraphics::onInput));
187         draftcheck_->signal_toggled().connect(
188                 sigc::mem_fun(*this, &GGraphics::onInput));
189         unzipcheck_->signal_toggled().connect(
190                 sigc::mem_fun(*this, &GGraphics::onInput));
191
192         subfigcheck_->signal_toggled().connect(
193                 sigc::mem_fun(*this, &GGraphics::onSubFigCheckToggled));
194
195         vector<RotationOriginPair> origindata = getRotationOriginData();
196
197         // Store the identifiers for later
198         origins_ = getSecond(origindata);
199         PopulateComboBox(origincombo_, getFirst(origindata));
200 }
201
202
203 void GGraphics::onSizingModeChange()
204 {
205         bool const scalingmode = setscalingradio_->get_active();
206
207         outputscalespin_->set_sensitive(scalingmode);
208         widthspin_->set_sensitive(!scalingmode);
209         heightspin_->set_sensitive(!scalingmode);
210         widthunitscombo_->set_sensitive(!scalingmode);
211         heightunitscombo_->set_sensitive(!scalingmode);
212         aspectcheck_->set_sensitive(!scalingmode);
213         bc().input(ButtonPolicy::SMI_VALID);
214 }
215
216
217 void GGraphics::PopulateComboBox(Gtk::ComboBox * combo,
218                                   vector<string> const & strings)
219 {
220         Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(cols_);
221         vector<string>::const_iterator it = strings.begin();
222         vector<string>::const_iterator end = strings.end();
223         for (int rowindex = 0; it != end; ++it, ++rowindex) {
224                 Gtk::TreeModel::iterator row = model->append();
225                 (*row)[stringcol_] = *it;
226         }
227
228         combo->set_model(model);
229         Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
230         combo->pack_start(*cell, true);
231         combo->add_attribute(*cell, "text", 0);
232 }
233
234
235 void GGraphics::apply()
236 {
237         // Create the parameters structure and fill the data from the dialog.
238         InsetGraphicsParams & igp = controller().params();
239
240         // the file section
241         igp.filename.set(fileentry_->get_text(),
242                          kernel().bufferFilepath());
243
244         igp.lyxscale =
245                 static_cast<int>(displayscalespin_->get_adjustment()->get_value());
246         if (igp.lyxscale == 0) {
247                 igp.lyxscale = 100;
248         }
249
250         switch (displaycombo_->get_active_row_number()) {
251         case 4:
252                 igp.display = graphics::NoDisplay;
253                 break;
254         case 3:
255                 igp.display = graphics::ColorDisplay;
256                 break;
257         case 2:
258                 igp.display = graphics::GrayscaleDisplay;
259                 break;
260         case 1:
261                 igp.display = graphics::MonochromeDisplay;
262                 break;
263         case 0:
264                 igp.display = graphics::DefaultDisplay;
265         }
266
267         if (setscalingradio_->get_active()) {
268                 igp.scale = outputscalespin_->get_adjustment()->get_value();
269                 if (float_equal(igp.scale, 0.0, 0.05))
270                         igp.scale = 100.0;
271                 igp.width = LyXLength();
272         } else {
273                 igp.scale = 0.0;
274                 Glib::ustring const widthunit =
275                         (*widthunitscombo_->get_active())[stringcol_];
276                 igp.width = LyXLength(widthspin_->get_text() + widthunit);
277         }
278
279
280         Glib::ustring const heightunit =
281                 (*heightunitscombo_->get_active())[stringcol_];
282         igp.height = LyXLength(heightspin_->get_text() + heightunit);
283
284         igp.keepAspectRatio = aspectcheck_->get_active();
285         igp.draft = draftcheck_->get_active();
286         igp.noUnzip = !unzipcheck_->get_active();
287
288         // the bb section
289
290         if (!controller().bbChanged) {
291                 // don't write anything
292                 igp.bb.erase();
293         } else {
294                 Glib::ustring const bbunit = (*bbunitscombo_->get_active())[stringcol_];
295                 string bb;
296
297                 if (leftbottomxspin_->get_text().empty())
298                         bb = "0";
299                 else
300                         bb = leftbottomxspin_->get_text() + bbunit;
301
302                 bb += ' ';
303
304                 if (leftbottomyspin_->get_text().empty())
305                         bb += "0";
306                 else
307                         bb += leftbottomyspin_->get_text() + bbunit;
308
309                 bb += ' ';
310
311                 if (righttopxspin_->get_text().empty())
312                         bb += "0";
313                 else
314                         bb += righttopxspin_->get_text() + bbunit;
315
316                 bb += ' ';
317
318                 if (righttopyspin_->get_text().empty())
319                         bb += "0";
320                 else
321                         bb += righttopyspin_->get_text() + bbunit;
322
323                 /// The bounding box with "xLB yLB yRT yRT ", divided by a space!
324                 igp.bb = bb;
325         }
326         igp.clip = clipcheck_->get_active();
327
328         // the extra section
329         igp.rotateAngle = anglespin_->get_adjustment()->get_value();
330
331         int const origin_pos = origincombo_->get_active_row_number();
332         igp.rotateOrigin = origins_[origin_pos];
333
334         igp.subcaption = subfigcheck_->get_active();
335         igp.subcaptionText = subfigentry_->get_text();
336
337         igp.special = latexoptsentry_->get_text();
338 }
339
340
341 void GGraphics::update() {
342         // set the right default unit
343         defaultUnit = getDefaultUnit();
344
345         // Update dialog with details from inset
346         InsetGraphicsParams & igp = controller().params();
347
348         // the file section
349         string const name =
350                 igp.filename.outputFilename(kernel().bufferFilepath());
351         fileentry_->set_text(name);
352         displayscalespin_->get_adjustment()->set_value(igp.lyxscale);
353
354
355         switch (igp.display) {
356         case graphics::NoDisplay:
357                 displaycombo_->set_active(4);
358                 break;
359         case graphics::ColorDisplay:
360                 displaycombo_->set_active(3);
361                 break;
362         case graphics::GrayscaleDisplay:
363                 displaycombo_->set_active(2);
364                 break;
365         case graphics::MonochromeDisplay:
366                 displaycombo_->set_active(1);
367                 break;
368         case graphics::DefaultDisplay:
369                 displaycombo_->set_active(0);
370         }
371
372         outputscalespin_->get_adjustment()->set_value(igp.scale);
373         widthspin_->get_adjustment()->set_value(igp.width.value());
374         unitsComboFromLength(widthunitscombo_, stringcol_,
375                              igp.width, defaultUnit);
376         heightspin_->get_adjustment()->set_value(igp.height.value());
377         unitsComboFromLength(heightunitscombo_, stringcol_,
378                              igp.height, defaultUnit);
379
380         if (!float_equal(igp.scale, 0.0, 0.05)) {
381                 // scaling sizing mode
382                 setscalingradio_->set_active(true);
383         } else {
384                 setsizeradio_->set_active(true);
385         }
386         onSizingModeChange();
387
388         aspectcheck_->set_active(igp.keepAspectRatio);
389         draftcheck_->set_active(igp.draft);
390         unzipcheck_->set_active(!igp.noUnzip);
391
392         // the bb section
393         // set the bounding box values, if exists. First we need the whole
394         // path, because the controller knows nothing about the doc-dir
395         updateBB(igp.filename.absFilename(), igp.bb);
396         clipcheck_->set_active(igp.clip);
397
398         // the extra section
399         anglespin_->get_adjustment()->set_value(igp.rotateAngle);
400
401         int origin_pos;
402         if (igp.rotateOrigin.empty()) {
403                 origin_pos = 0;
404         } else {
405                 origin_pos = findPos(origins_, igp.rotateOrigin);
406         }
407         origincombo_->set_active(origin_pos);
408
409
410         subfigcheck_->set_active(igp.subcaption);
411         subfigentry_->set_text(igp.subcaptionText);
412         subfigentry_->set_sensitive(subfigcheck_->get_active());
413         latexoptsentry_->set_text(igp.special);
414
415         // open dialog in the file-tab, whenever filename is empty
416         if (igp.filename.empty()) {
417                 notebook_->set_current_page(0);
418         }
419
420
421         bc().input(ButtonPolicy::SMI_INVALID);
422 }
423
424
425 void GGraphics::updateBB(string const & filename, string const & bb_inset)
426 {
427         // Update dialog with details from inset
428         // set the bounding box values, if exists. First we need the whole
429         // path, because the controller knows nothing about the doc-dir
430
431         if (bb_inset.empty()) {
432                 lyxerr[Debug::GRAPHICS]
433                         << "GGraphics::updateBB() [no BoundingBox]\n";
434                 string const bb = controller().readBB(filename);
435                 if (!bb.empty()) {
436                         // get the values from the file
437                         // in this case we always have the point-unit
438                         leftbottomxspin_->set_text(token(bb, ' ', 0));
439                         leftbottomyspin_->set_text(token(bb, ' ', 1));
440                         righttopxspin_->set_text(token(bb, ' ', 2));
441                         righttopyspin_->set_text(token(bb, ' ', 3));
442                 } else {
443                         // no bb from file
444                         leftbottomxspin_->set_text("");
445                         leftbottomyspin_->set_text("");
446                         righttopxspin_->set_text("");
447                         righttopyspin_->set_text("");
448                 }
449                 unitsComboFromLength(bbunitscombo_, stringcol_,
450                                      LyXLength("bp"), defaultUnit);
451         } else {
452                 // get the values from the inset
453                 lyxerr[Debug::GRAPHICS]
454                         << "FormGraphics::updateBB(): igp has BoundingBox"
455                         << " ["<< bb_inset << "]\n";
456
457                 LyXLength anyLength;
458                 anyLength = LyXLength(token(bb_inset, ' ', 0));
459
460                 unitsComboFromLength(bbunitscombo_, stringcol_, anyLength, defaultUnit);
461
462                 leftbottomxspin_->get_adjustment()->set_value(anyLength.value());
463
464                 anyLength = LyXLength(token(bb_inset, ' ', 1));
465                 leftbottomyspin_->get_adjustment()->set_value(anyLength.value());
466
467                 anyLength = LyXLength(token(bb_inset, ' ', 2));
468                 righttopxspin_->get_adjustment()->set_value(anyLength.value());
469
470                 anyLength = LyXLength(token(bb_inset, ' ', 3));
471                 righttopyspin_->get_adjustment()->set_value(anyLength.value());
472         }
473         controller().bbChanged = false;
474 }
475
476
477 void GGraphics::onBrowseClicked()
478 {
479         // Get the filename from the dialog
480         string const in_name = fileentry_->get_text();
481         string const out_name = controller().browse(in_name);
482         lyxerr[Debug::GRAPHICS]
483                 << "[FormGraphics]out_name: " << out_name << "\n";
484         if (out_name != in_name && !out_name.empty()) {
485                 fileentry_->set_text(out_name);
486         }
487         if (controller().isFilenameValid(out_name) &&
488             !controller().bbChanged) {
489                 updateBB(out_name, string());
490         }
491
492         bc().input(ButtonPolicy::SMI_VALID);
493 }
494
495
496 void GGraphics::onBBChange()
497 {
498         controller().bbChanged = true;
499         bc().input(ButtonPolicy::SMI_VALID);
500 }
501
502
503 void GGraphics::onBBFromFileClicked()
504 {
505         string const filename = fileentry_->get_text();
506         if (!filename.empty()) {
507                 string bb = controller().readBB(filename);
508                 if (!bb.empty()) {
509                         leftbottomxspin_->set_text(token(bb, ' ', 0));
510                         leftbottomyspin_->set_text(token(bb, ' ', 1));
511                         righttopxspin_->set_text(token(bb, ' ', 2));
512                         righttopyspin_->set_text(token(bb, ' ', 3));
513                         unitsComboFromLength(bbunitscombo_, stringcol_,
514                                              LyXLength("bp"), defaultUnit);
515                 }
516                 controller().bbChanged = false;
517         } else {
518                 leftbottomxspin_->set_text("");
519                 leftbottomyspin_->set_text("");
520                 righttopxspin_->set_text("");
521                 righttopyspin_->set_text("");
522                 unitsComboFromLength(bbunitscombo_, stringcol_,
523                                      LyXLength("bp"), defaultUnit);
524         }
525         bc().input(ButtonPolicy::SMI_VALID);
526 }
527
528
529 void GGraphics::onSubFigCheckToggled()
530 {
531         subfigentry_->set_sensitive(subfigcheck_->get_active());
532         bc().input(ButtonPolicy::SMI_VALID);
533 }
534
535
536 void GGraphics::onEditClicked()
537 {
538         controller().editGraphics();
539 }
540
541
542 void GGraphics::onInput()
543 {
544         bc().input(ButtonPolicy::SMI_VALID);
545 }
546
547 } // namespace frontend
548 } // namespace lyx