Proper check for rawzor libraries.
[rawtherapee-fixes.git] / rtgui / exifpanel.cc
blob4fc12672378f9f41cc3bbca817a569e3432d6ab0
1 /*
2 * This file is part of RawTherapee.
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
6 * RawTherapee is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * RawTherapee is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
19 #include <exifpanel.h>
20 #include "config.h"
22 using namespace rtengine;
23 using namespace rtengine::procparams;
24 using namespace rtexif;
25 extern Glib::ustring argv0;
27 ExifPanel::ExifPanel () : idata(NULL) {
29 recursiveOp = true;
31 exifTree = Gtk::manage(new Gtk::TreeView());
32 scrolledWindow = Gtk::manage(new Gtk::ScrolledWindow());
34 exifTree->set_headers_visible(false);
35 exifTree->set_rules_hint(false);
36 exifTree->set_reorderable(false);
37 exifTree->set_enable_search(true);
38 exifTree->get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
39 scrolledWindow->set_border_width(2);
40 scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE);
41 scrolledWindow->set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS);
42 scrolledWindow->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT);
43 scrolledWindow->add(*exifTree);
45 exifTreeModel = Gtk::TreeStore::create(exifColumns);
46 exifTree->set_model (exifTreeModel);
48 delicon = Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0)+"/images/deltags.png");
49 keepicon = Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0)+"/images/addtags.png");
50 editicon = Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0)+"/images/logoicon16.png");
52 Gtk::TreeView::Column *viewcol = Gtk::manage(new Gtk::TreeView::Column ("Field Name"));
53 Gtk::CellRendererPixbuf* render_pb = Gtk::manage(new Gtk::CellRendererPixbuf ());
54 Gtk::CellRendererText *render_txt = Gtk::manage(new Gtk::CellRendererText());
55 viewcol->pack_start (*render_pb, false);
56 viewcol->pack_start (*render_txt, true);
57 viewcol->add_attribute (*render_pb, "pixbuf", exifColumns.icon);
58 viewcol->add_attribute (*render_txt, "markup", exifColumns.field);
60 render_pb->property_ypad() = 0;
61 render_txt->property_ypad() = 0;
62 render_pb->property_yalign() = 0;
63 render_txt->property_yalign() = 0;
65 exifTree->append_column (*viewcol);
67 Gtk::TreeView::Column *viewcolv = Gtk::manage(new Gtk::TreeView::Column ("Value"));
68 Gtk::CellRendererText *render_txtv = Gtk::manage(new Gtk::CellRendererText());
69 viewcolv->pack_start (*render_txtv, true);
70 viewcolv->add_attribute (*render_txtv, "markup", exifColumns.value);
72 render_txtv->property_ypad() = 0;
74 exifTree->append_column (*viewcolv);
76 pack_start (*scrolledWindow);
78 Gtk::HBox* buttons1 = Gtk::manage(new Gtk::HBox ());
79 Gtk::HBox* buttons2 = Gtk::manage(new Gtk::HBox ());
81 remove = Gtk::manage(new Gtk::Button (M("EXIFPANEL_REMOVE")));
82 remove->set_image (*Gtk::manage(new Gtk::Image (delicon)));
83 remove->set_tooltip_text (M("EXIFPANEL_REMOVEHINT"));
84 buttons1->pack_start (*remove);
86 keep = Gtk::manage(new Gtk::Button (M("EXIFPANEL_KEEP")));
87 keep->set_image (*Gtk::manage(new Gtk::Image (keepicon)));
88 keep->set_tooltip_text (M("EXIFPANEL_KEEPHINT"));
89 buttons1->pack_start (*keep);
91 add = Gtk::manage(new Gtk::Button (M("EXIFPANEL_ADDEDIT")));
92 add->set_image (*Gtk::manage(new Gtk::Image (editicon)));
93 add->set_tooltip_text (M("EXIFPANEL_ADDEDITHINT"));
94 buttons1->pack_start (*add);
96 reset = Gtk::manage(new Gtk::Button (M("EXIFPANEL_RESET")));
97 reset->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID ("gtk-undo"), Gtk::IconSize (2))));
98 reset->set_tooltip_text (M("EXIFPANEL_RESETHINT"));
99 buttons2->pack_start (*reset);
101 resetAll = Gtk::manage(new Gtk::Button (M("EXIFPANEL_RESETALL")));
102 resetAll->set_image (*Gtk::manage(new Gtk::Image (GET_DATA_PATH(argv0)+"/images/gtk-undo-ltr.png")));
103 resetAll->set_tooltip_text (M("EXIFPANEL_RESETALLHINT"));
104 buttons2->pack_start (*resetAll);
106 pack_end (*buttons2, Gtk::PACK_SHRINK);
107 pack_end (*buttons1, Gtk::PACK_SHRINK);
109 exifTree->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &ExifPanel::exifSelectionChanged));
110 exifTree->signal_row_activated().connect(sigc::mem_fun(*this, &ExifPanel::row_activated));
112 remove->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::removePressed) );
113 keep->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::keepPressed) );
114 reset->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::resetPressed) );
115 resetAll->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::resetAllPressed) );
116 add->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::addPressed) );
118 show_all ();
121 ExifPanel::~ExifPanel () {
124 void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
126 disableListener ();
128 changeList = pp->exif;
129 setImageData (idata);
130 applyChangeList ();
131 exifSelectionChanged ();
133 enableListener ();
136 void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) {
138 // updateChangeList ();
139 pp->exif = changeList;
142 void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
144 defChangeList = defParams->exif;
147 void ExifPanel::setImageData (const ImageMetaData* id) {
149 idata = id;
150 exifTreeModel->clear ();
152 const std::vector<Tag*>& defTags = ExifManager::getDefaultTIFFTags (NULL);
153 for (int i=0; i<defTags.size(); i++)
154 if (defTags[i]->nameToString() == "ImageWidth" || defTags[i]->nameToString() == "ImageHeight" || defTags[i]->nameToString() == "BitsPerSample")
155 addTag (exifTreeModel->children(), defTags[i]->nameToString(), "?", SYSTEM, false);
156 else
157 addTag (exifTreeModel->children(), defTags[i]->nameToString(), defTags[i]->valueToString(), SYSTEM, false);
159 if (id && id->getExifData ()) {
160 // id->getExifData ()->printAll ();
161 addDirectory (id->getExifData (), exifTreeModel->children());
165 Gtk::TreeModel::Children ExifPanel::addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, int action, bool editable) {
167 Gtk::TreeModel::Row row = *(exifTreeModel->append(root));
168 row[exifColumns.action] = action;
169 row[exifColumns.editable] = editable;
170 row[exifColumns.edited] = false;
171 row[exifColumns.field_nopango] = field;
172 row[exifColumns.value_nopango] = value;
173 row[exifColumns.orig_value] = value;
175 if (action==WRITE)
176 row[exifColumns.icon] = keepicon;
177 else if (action==DONTWRITE)
178 row[exifColumns.icon] = delicon;
180 if (editable) {
181 row[exifColumns.field] = Glib::ustring("<b>") + field + "</b>";
182 row[exifColumns.value] = Glib::ustring("<b>") + value + "</b>";
184 else if (action==SYSTEM) {
185 row[exifColumns.field] = Glib::ustring("<i>") + field + "</i>";
186 row[exifColumns.value] = Glib::ustring("<i>") + value + "</i>";
188 else {
189 row[exifColumns.field] = field;
190 row[exifColumns.value] = value;
193 return row.children();
196 void ExifPanel::addDirectory (const TagDirectory* dir, Gtk::TreeModel::Children root) {
198 for (int i=0; i<dir->getCount(); i++) {
199 Tag* t = ((TagDirectory*)dir)->getTagByIndex (i);
200 if (t->getAttrib() && t->getAttrib()->action==SYSTEM)
201 continue;
202 if (t->isDirectory())
203 for (int j=0; t->getDirectory(j); j++) {
204 Gtk::TreeModel::Children ch = addTag (root, t->nameToString (j), M("EXIFPANEL_SUBDIRECTORY"), t->getAttrib() ? t->getAttrib()->action : 0, t->getAttrib() && t->getAttrib()->editable);
205 addDirectory (t->getDirectory(j), ch);
207 else
208 addTag (root, t->nameToString (), t->valueToString (), t->getAttrib() ? t->getAttrib()->action : 0, t->getAttrib() && t->getAttrib()->editable);
212 void ExifPanel::exifSelectionChanged () {
214 Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
215 std::vector<Gtk::TreeModel::Path> sel = selection->get_selected_rows();
216 if (sel.size()>1) {
217 remove->set_sensitive (1);
218 keep->set_sensitive (1);
219 reset->set_sensitive (1);
221 else if (sel.size()==1) {
222 Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (sel[0]);
223 if (iter->get_value (exifColumns.action)==SYSTEM) {
224 remove->set_sensitive (0);
225 keep->set_sensitive (0);
226 reset->set_sensitive (0);
228 else if (iter->children().size()>0) {
229 remove->set_sensitive (1);
230 keep->set_sensitive (1);
231 reset->set_sensitive (1);
233 else if (iter->get_value(exifColumns.icon)==delicon) {
234 remove->set_sensitive (0);
235 keep->set_sensitive (1);
236 reset->set_sensitive (1);
238 else if (iter->get_value(exifColumns.icon)==keepicon || iter->get_value(exifColumns.icon)==editicon) {
239 keep->set_sensitive (0);
240 remove->set_sensitive (1);
241 reset->set_sensitive (1);
244 else {
245 remove->set_sensitive (0);
246 keep->set_sensitive (0);
247 reset->set_sensitive (0);
251 void ExifPanel::delIt (Gtk::TreeModel::iterator iter) {
253 if (!iter)
254 return;
256 if (iter->get_value (exifColumns.action) != SYSTEM)
257 iter->set_value (exifColumns.icon, delicon);
258 if (recursiveOp)
259 for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
260 delIt (i);
263 void ExifPanel::removePressed () {
265 std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
266 for (int i=0; i<sel.size(); i++)
267 delIt (exifTreeModel->get_iter (sel[i]));
269 exifSelectionChanged ();
270 updateChangeList ();
271 notifyListener ();
274 void ExifPanel::keepIt (Gtk::TreeModel::iterator iter) {
276 if (!iter)
277 return;
279 if (iter->get_value (exifColumns.action) != SYSTEM)
280 iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon);
281 if (recursiveOp)
282 for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
283 keepIt (i);
286 void ExifPanel::keepPressed () {
288 std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
289 for (int i=0; i<sel.size(); i++)
290 keepIt (exifTreeModel->get_iter (sel[i]));
292 exifSelectionChanged ();
293 updateChangeList ();
294 notifyListener ();
297 /*void ExifPanel::resetIt (Gtk::TreeModel::iterator iter) {
299 if (!iter)
300 return;
302 if (iter->get_value (exifColumns.action)!=SYSTEM)
303 iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon);
304 if (iter->get_value (exifColumns.edited)) {
305 iter->set_value (exifColumns.value, Glib::ustring("<b>") + iter->get_value(exifColumns.orig_value) + "</b>");
306 iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value));
307 iter->set_value (exifColumns.edited, false);
309 if (iter->get_value (exifColumns.action)==100)
310 exifTreeModel->erase (iter);
311 else
312 if (recursiveOp)
313 for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
314 resetIt (i);
316 Gtk::TreeModel::iterator ExifPanel::resetIt (Gtk::TreeModel::iterator iter) {
318 if (!iter)
319 return iter;
321 if (iter->get_value (exifColumns.action)!=SYSTEM)
322 iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon);
323 if (iter->get_value (exifColumns.edited)) {
324 iter->set_value (exifColumns.value, Glib::ustring("<b>") + iter->get_value(exifColumns.orig_value) + "</b>");
325 iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value));
326 iter->set_value (exifColumns.edited, false);
328 if (iter->get_value (exifColumns.action)==100) {
329 return exifTreeModel->erase (iter);
331 else
332 if (recursiveOp) {
333 Gtk::TreeModel::iterator i = iter->children().begin();
334 while (i && i != iter->children().end())
335 i = resetIt (i);
337 return ++iter;
339 void ExifPanel::resetPressed () {
341 std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
342 for (int i=0; i<sel.size(); i++)
343 resetIt (exifTreeModel->get_iter (sel[i]));
345 exifSelectionChanged ();
346 updateChangeList ();
347 notifyListener ();
350 void ExifPanel::resetAllPressed () {
352 setImageData (idata);
353 changeList = defChangeList;
354 applyChangeList ();
355 exifSelectionChanged ();
356 notifyListener ();
359 void ExifPanel::addPressed () {
361 Gtk::Dialog* dialog = new Gtk::Dialog (M("EXIFPANEL_ADDTAGDLG_TITLE"), *((Gtk::Window*)get_toplevel()), true, true);
362 dialog->add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
363 dialog->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
365 Gtk::HBox* hb1 = new Gtk::HBox ();
366 Gtk::HBox* hb2 = new Gtk::HBox ();
368 Gtk::Label* tlabel = new Gtk::Label (M("EXIFPANEL_ADDTAGDLG_SELECTTAG")+":");
369 Gtk::ComboBoxText* tcombo = new Gtk::ComboBoxText ();
371 tcombo->append_text ("Artist");
372 tcombo->append_text ("Copyright");
373 tcombo->append_text ("ImageDescription");
374 tcombo->append_text ("Exif.UserComment");
376 hb1->pack_start (*tlabel, Gtk::PACK_SHRINK, 4);
377 hb1->pack_start (*tcombo);
379 Gtk::Label* vlabel = new Gtk::Label (M("EXIFPANEL_ADDTAGDLG_ENTERVALUE")+":");
380 Gtk::Entry* ventry = new Gtk::Entry ();
381 hb2->pack_start (*vlabel, Gtk::PACK_SHRINK, 4);
382 hb2->pack_start (*ventry);
384 Glib::ustring sel = getSelection (true);
385 if (sel=="")
386 tcombo->set_active_text ("Exif.UserComment");
387 else {
388 tcombo->set_active_text (sel);
389 if (tcombo->get_active ()<0) {
390 tcombo->append_text (sel);
391 tcombo->set_active_text (sel);
393 ventry->set_text (getSelectedValue ());
396 ventry->set_activates_default (true);
397 dialog->set_default_response (Gtk::RESPONSE_OK);
398 dialog->get_vbox()->pack_start (*hb1, Gtk::PACK_SHRINK);
399 dialog->get_vbox()->pack_start (*hb2, Gtk::PACK_SHRINK, 4);
400 tlabel->show ();
401 tcombo->show ();
402 vlabel->show ();
403 ventry->show ();
404 hb1->show ();
405 hb2->show ();
407 if (dialog->run ()== Gtk::RESPONSE_OK) {
408 editTag (exifTreeModel->children(), tcombo->get_active_text(), ventry->get_text());
409 updateChangeList ();
410 notifyListener ();
413 delete dialog;
414 delete tlabel;
415 delete tcombo;
416 delete vlabel;
417 delete ventry;
418 delete hb1;
419 delete hb2;
422 void ExifPanel::editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value) {
424 Glib::ustring::size_type dp = name.find_first_of ('.');
425 Glib::ustring fseg = name.substr (0,dp);
426 // look up first segment of the path
427 Gtk::TreeModel::iterator iter;
428 for (iter = root.begin(); iter!=root.end(); iter++)
429 if (iter->get_value (exifColumns.field_nopango) == fseg)
430 break;
432 if (iter==root.end() && value!="#keep" && value!="#delete") {
433 iter = exifTreeModel->append(root);
434 iter->set_value (exifColumns.field_nopango, fseg);
435 iter->set_value (exifColumns.action, 100);
436 if (dp==Glib::ustring::npos) {
437 iter->set_value (exifColumns.value, Glib::ustring("<b>") + value + "</b>");
438 iter->set_value (exifColumns.value_nopango, value);
439 iter->set_value (exifColumns.orig_value, value);
440 iter->set_value (exifColumns.field, Glib::ustring("<b>") + fseg + "</b>");
441 iter->set_value (exifColumns.edited, true);
442 iter->set_value (exifColumns.editable, true);
443 iter->set_value (exifColumns.icon, editicon);
445 else {
446 iter->set_value (exifColumns.value, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY")));
447 iter->set_value (exifColumns.value_nopango, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY")));
448 iter->set_value (exifColumns.field, fseg);
449 iter->set_value (exifColumns.icon, keepicon);
450 iter->set_value (exifColumns.orig_value, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY")));
454 if (dp==Glib::ustring::npos) {
455 if (value=="#keep" && iter->get_value (exifColumns.action)!=SYSTEM)
456 iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon);
457 else if (value=="#delete" && iter->get_value (exifColumns.action)!=SYSTEM)
458 iter->set_value (exifColumns.icon, delicon);
459 else {
460 iter->set_value (exifColumns.value, Glib::ustring("<b>") + value + "</b>");
461 iter->set_value (exifColumns.value_nopango, value);
462 iter->set_value (exifColumns.edited, true);
463 iter->set_value (exifColumns.icon, editicon);
466 else
467 editTag (iter->children(), name.substr (dp+1, Glib::ustring::npos), value);
470 Glib::ustring ExifPanel::getSelectedValue () {
472 Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
473 std::vector<Gtk::TreeModel::Path> rows = selection->get_selected_rows();
474 if (rows.size()!=1)
475 return "";
476 Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]);
477 if (iter)
478 return iter->get_value (exifColumns.value_nopango);
479 return "";
482 Glib::ustring ExifPanel::getSelection (bool onlyeditable) {
484 Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
485 std::vector<Gtk::TreeModel::Path> rows = selection->get_selected_rows();
487 if (rows.size()!=1)
488 return "";
489 Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]);
491 Glib::ustring ret = "";
492 bool first = true;
493 bool editable = false;
494 while (iter) {
495 if (first)
496 ret = iter->get_value (exifColumns.field_nopango);
497 else
498 ret = iter->get_value (exifColumns.field_nopango) + "." + ret;
499 editable = iter->get_value (exifColumns.editable);
500 iter = iter->parent ();
501 first = false;
503 if (!editable && onlyeditable)
504 return "";
505 return ret;
508 void ExifPanel::updateChangeList (Gtk::TreeModel::Children root, std::string prefix) {
510 if (prefix!="")
511 prefix = prefix + ".";
513 Gtk::TreeModel::iterator iter;
514 for (iter = root.begin(); iter!=root.end(); iter++) {
515 if (iter->get_value (exifColumns.edited) == true) {
516 ExifPair ec;
517 ec.field = prefix + iter->get_value (exifColumns.field_nopango);
518 ec.value = iter->get_value (exifColumns.value_nopango);
519 changeList.push_back (ec);
521 else if (iter->get_value (exifColumns.action) == WRITE && iter->get_value (exifColumns.icon) == delicon) {
522 ExifPair ec;
523 ec.field = prefix + iter->get_value (exifColumns.field_nopango);
524 ec.value = "#delete";
525 changeList.push_back (ec);
527 else if (iter->get_value (exifColumns.action) == DONTWRITE && iter->get_value (exifColumns.icon) == keepicon) {
528 ExifPair ec;
529 ec.field = prefix + iter->get_value (exifColumns.field_nopango);
530 ec.value = "#keep";
531 changeList.push_back (ec);
533 if (iter->get_value (exifColumns.icon) == keepicon)
534 updateChangeList (iter->children(), prefix + iter->get_value (exifColumns.field_nopango));
538 void ExifPanel::updateChangeList () {
540 changeList.clear ();
541 updateChangeList (exifTreeModel->children(), "");
544 void ExifPanel::applyChangeList () {
546 for (int i=0; i<changeList.size(); i++)
547 editTag (exifTreeModel->children(), changeList[i].field, changeList[i].value);
550 void ExifPanel::row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) {
552 Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (path);
553 if (iter) {
554 if (iter->children().size()>0)
555 if (exifTree->row_expanded (path))
556 exifTree->collapse_row (path);
557 else
558 exifTree->expand_row (path, false);
559 else if (iter->get_value (exifColumns.editable))
560 addPressed ();
565 void ExifPanel::notifyListener () {
567 if (listener)
568 listener->panelChanged (EvExif, M("HISTORY_CHANGED"));