"Fossies" - the Fresh Open Source Software Archive

Member "rawtherapee-5.7/rtgui/exifpanel.cc" (10 Sep 2019, 24799 Bytes) of package /linux/misc/rawtherapee-5.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "exifpanel.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.6_vs_5.7.

    1 /*
    2  *  This file is part of RawTherapee.
    3  *
    4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
    5  *
    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.
   10  *
   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.
   15  *
   16  *  You should have received a copy of the GNU General Public License
   17  *  along with RawTherapee.  If not, see <https://www.gnu.org/licenses/>.
   18  */
   19 #include "exifpanel.h"
   20 
   21 #include "guiutils.h"
   22 #include "rtimage.h"
   23 #include "options.h"
   24 
   25 #include "../rtengine/procparams.h"
   26 
   27 using namespace rtengine;
   28 using namespace rtengine::procparams;
   29 using namespace rtexif;
   30 
   31 ExifPanel::ExifPanel() :
   32     idata(nullptr),
   33     changeList(new rtengine::procparams::ExifPairs),
   34     defChangeList(new rtengine::procparams::ExifPairs)
   35 {
   36     recursiveOp = true;
   37 
   38     exifTree = Gtk::manage (new Gtk::TreeView());
   39     scrolledWindow = Gtk::manage (new Gtk::ScrolledWindow());
   40 
   41     exifTree->set_headers_visible (false);
   42     exifTree->set_rules_hint (false);
   43     exifTree->set_reorderable (false);
   44     exifTree->set_enable_search (true);
   45     exifTree->get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
   46     scrolledWindow->set_shadow_type (Gtk::SHADOW_NONE);
   47     scrolledWindow->set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS);
   48     scrolledWindow->property_window_placement().set_value (Gtk::CORNER_TOP_LEFT);
   49     scrolledWindow->add (*exifTree);
   50 
   51     exifTreeModel = Gtk::TreeStore::create (exifColumns);
   52     exifTree->set_model (exifTreeModel);
   53     exifTree->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_NONE);
   54     exifTree->set_row_separator_func (sigc::mem_fun(*this, &ExifPanel::rowSeperatorFunc));
   55 
   56     delicon = RTImage::createPixbufFromFile ("cancel-small.png");
   57     keepicon = RTImage::createPixbufFromFile ("tick-small.png");
   58     editicon = RTImage::createPixbufFromFile ("add-small.png");
   59 
   60     Gtk::TreeView::Column *viewcol = Gtk::manage (new Gtk::TreeView::Column ("Field Name"));
   61     Gtk::CellRendererPixbuf* render_pb = Gtk::manage (new Gtk::CellRendererPixbuf ());
   62     Gtk::CellRendererText *render_txt = Gtk::manage (new Gtk::CellRendererText());
   63     render_txt->property_ellipsize() = Pango::ELLIPSIZE_END;
   64     viewcol->pack_start (*render_pb, false);
   65     viewcol->pack_start (*render_txt, true);
   66     viewcol->add_attribute (*render_pb, "pixbuf", exifColumns.icon);
   67     viewcol->add_attribute (*render_txt, "markup", exifColumns.field);
   68     viewcol->set_expand (true);
   69     viewcol->set_resizable (true);
   70     viewcol->set_fixed_width (35);
   71     viewcol->set_min_width (35);
   72     viewcol->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
   73 
   74     render_pb->property_ypad() = 0;
   75     render_txt->property_ypad() = 0;
   76     render_pb->property_yalign() = 0;
   77     render_txt->property_yalign() = 0;
   78 
   79     exifTree->append_column (*viewcol);
   80 
   81     Gtk::TreeView::Column *viewcolv = Gtk::manage (new Gtk::TreeView::Column ("Value"));
   82     Gtk::CellRendererText *render_txtv = Gtk::manage (new Gtk::CellRendererText());
   83     render_txtv->property_ellipsize() = Pango::ELLIPSIZE_END;
   84     viewcolv->pack_start (*render_txtv, true);
   85     viewcolv->add_attribute (*render_txtv, "markup", exifColumns.value);
   86     viewcolv->set_expand (true);
   87     viewcolv->set_resizable (true);
   88     viewcol->set_fixed_width (35);
   89     viewcolv->set_min_width (35);
   90     viewcolv->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
   91 
   92     render_txtv->property_ypad() = 0;
   93 
   94     exifTree->append_column (*viewcolv);
   95 
   96     pack_start (*scrolledWindow);
   97 
   98     Gtk::Grid* buttons1 = Gtk::manage (new Gtk::Grid());
   99     buttons1->set_row_homogeneous (true);
  100     buttons1->set_column_homogeneous (true);
  101     setExpandAlignProperties (buttons1, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
  102     Gtk::Grid* buttons2 = Gtk::manage (new Gtk::Grid());
  103     buttons2->set_row_homogeneous (true);
  104     buttons2->set_column_homogeneous (true);
  105     setExpandAlignProperties (buttons2, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
  106 
  107     remove = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_REMOVE")
  108     remove->set_image (*Gtk::manage (new RTImage(delicon)));
  109     remove->set_tooltip_text (M ("EXIFPANEL_REMOVEHINT"));
  110     remove->get_style_context()->add_class ("Left");
  111     setExpandAlignProperties (remove, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
  112     buttons1->attach_next_to (*remove, Gtk::POS_LEFT, 1, 1);
  113 
  114     keep = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_KEEP")
  115     keep->set_image (*Gtk::manage (new RTImage(keepicon)));
  116     keep->set_tooltip_text (M ("EXIFPANEL_KEEPHINT"));
  117     keep->get_style_context()->add_class ("MiddleH");
  118     setExpandAlignProperties (keep, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
  119     buttons1->attach_next_to (*keep, Gtk::POS_RIGHT, 1, 1);
  120 
  121     add = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_ADDEDIT")
  122     add->set_image (*Gtk::manage (new RTImage(editicon)));
  123     add->set_tooltip_text (M ("EXIFPANEL_ADDEDITHINT"));
  124     add->get_style_context()->add_class ("Right");
  125     setExpandAlignProperties (add, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
  126     buttons1->attach_next_to (*add, Gtk::POS_RIGHT, 1, 1);
  127 
  128     showAll = Gtk::manage (new Gtk::ToggleButton (M ("EXIFPANEL_SHOWALL")));
  129     //add->set_tooltip_text (M("EXIFPANEL_SHOWALL"));
  130     showAll->get_style_context()->add_class ("Left");
  131     setExpandAlignProperties (showAll, false, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
  132     showAll->set_active (options.lastShowAllExif);
  133     buttons2->attach_next_to (*showAll, Gtk::POS_LEFT, 1, 1);
  134 
  135     reset = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_RESET")
  136     reset->set_image (*Gtk::manage (new RTImage("undo.png", "redo.png")));
  137     reset->set_tooltip_text (M ("EXIFPANEL_RESETHINT"));
  138     reset->get_style_context()->add_class ("MiddleH");
  139     setExpandAlignProperties (reset, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
  140     buttons2->attach_next_to (*reset, Gtk::POS_RIGHT, 1, 1);
  141 
  142     resetAll = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_RESETALL")
  143     resetAll->set_image (*Gtk::manage (new RTImage ("undo-all.png", "redo-all.png")));
  144     resetAll->set_tooltip_text (M ("EXIFPANEL_RESETALLHINT"));
  145     resetAll->get_style_context()->add_class ("Right");
  146     setExpandAlignProperties (resetAll, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
  147     buttons2->attach_next_to (*resetAll, Gtk::POS_RIGHT, 1, 1);
  148 
  149     pack_end (*buttons2, Gtk::PACK_SHRINK);
  150     pack_end (*buttons1, Gtk::PACK_SHRINK);
  151 
  152     exifTree->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ExifPanel::exifSelectionChanged));
  153     exifTree->signal_row_activated().connect (sigc::mem_fun (*this, &ExifPanel::row_activated));
  154 
  155     remove->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::removePressed) );
  156     keep->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::keepPressed) );
  157     reset->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetPressed) );
  158     resetAll->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetAllPressed) );
  159     add->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::addPressed) );
  160     showAll->signal_toggled().connect ( sigc::mem_fun (*this, &ExifPanel::showAlltoggled) );
  161 
  162     show_all ();
  163 }
  164 
  165 ExifPanel::~ExifPanel ()
  166 {
  167 }
  168 
  169 void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited)
  170 {
  171 
  172     disableListener ();
  173 
  174     *changeList = pp->exif;
  175     setImageData (idata);
  176     applyChangeList ();
  177     exifSelectionChanged ();
  178 
  179     enableListener ();
  180 }
  181 
  182 void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited)
  183 {
  184 
  185 //    updateChangeList ();
  186     pp->exif = *changeList;
  187 }
  188 
  189 void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited)
  190 {
  191 
  192     *defChangeList = defParams->exif;
  193 }
  194 
  195 void ExifPanel::setImageData (const FramesMetaData* id)
  196 {
  197 
  198     idata = id;
  199     exifTreeModel->clear ();
  200 
  201     if (idata) {
  202         for (unsigned int rootNum = 0; rootNum < id->getRootCount (); ++rootNum) {
  203             if ( id->getRootExifData (rootNum)) {
  204                 addDirectory (id->getRootExifData (rootNum), exifTreeModel->children(), rootNum > 0);
  205             }
  206         }
  207     }
  208 }
  209 
  210 Gtk::TreeModel::Children ExifPanel::addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, rtexif::ActionCode action, bool editable)
  211 {
  212 
  213     Gtk::TreeModel::Row row = * (exifTreeModel->append (root));
  214     row[exifColumns.action]   = action;
  215     row[exifColumns.editable] = editable;
  216     row[exifColumns.edited]   = false;
  217     row[exifColumns.field_nopango] = field;
  218     row[exifColumns.value_nopango] = value;
  219     row[exifColumns.orig_value]    = value;
  220 
  221     if (action == AC_WRITE) {
  222         row[exifColumns.icon] = keepicon;
  223     } else if (action == AC_DONTWRITE) {
  224         row[exifColumns.icon] = delicon;
  225     }
  226 
  227     if (editable) {
  228         row[exifColumns.field] = Glib::ustring ("<b>") + escapeHtmlChars (field) + "</b>";
  229         row[exifColumns.value] = Glib::ustring ("<b>") + escapeHtmlChars (value) + "</b>";
  230     } else if (action == AC_SYSTEM) {
  231         row[exifColumns.field] = Glib::ustring ("<i>") + escapeHtmlChars (field) + "</i>";
  232         row[exifColumns.value] = Glib::ustring ("<i>") + escapeHtmlChars (value) + "</i>";
  233     } else {
  234         row[exifColumns.field] = escapeHtmlChars (field);
  235         row[exifColumns.value] = escapeHtmlChars (value);
  236     }
  237 
  238     return row.children();
  239 }
  240 
  241 Gtk::TreeModel::Children ExifPanel::addSeparator ()
  242 {
  243 
  244     Gtk::TreeModel::Row row = * (exifTreeModel->append (exifTreeModel->children()));
  245     row[exifColumns.action] = rtexif::ActionCode::AC_INVALID;
  246     row[exifColumns.editable] = false;
  247     row[exifColumns.edited] = false;
  248     row[exifColumns.field_nopango] = "";
  249     row[exifColumns.value_nopango] = "";
  250     row[exifColumns.orig_value] = "";
  251     row[exifColumns.isSeparator] = true;
  252 
  253     return row.children();
  254 }
  255 
  256 void ExifPanel::addDirectory (const TagDirectory* dir, Gtk::TreeModel::Children root, bool checkForSeparator)
  257 {
  258 
  259     for (int i = 0; i < dir->getCount(); ++i) {
  260         Tag* t = (const_cast<TagDirectory*> (dir))->getTagByIndex (i);
  261 
  262         bool hasContent = false;
  263 
  264         if (checkForSeparator && i == 0) {
  265             for (int j = 0; j < dir->getCount(); ++j) {
  266                 Tag* t2 = (const_cast<TagDirectory*> (dir))->getTagByIndex (j);
  267                 const TagAttrib* currAttrib = t2->getAttrib();
  268 
  269                 if (currAttrib && (options.lastShowAllExif || currAttrib->action != AC_SYSTEM)) {
  270                     addSeparator();
  271                     hasContent = true;
  272                     break;
  273                 }
  274             }
  275         } else {
  276             hasContent = true;
  277         }
  278 
  279         if (!hasContent) {
  280             return;
  281         }
  282 
  283         const TagAttrib* currAttrib = t->getAttrib();
  284 
  285         if (!options.lastShowAllExif && currAttrib && currAttrib->action == AC_SYSTEM) {
  286             continue;
  287         }
  288 
  289         if (t->isDirectory()) {
  290             for (int j = 0; t->getDirectory (j); j++) {
  291                 Gtk::TreeModel::Children ch = addTag (root, t->nameToString (j), M ("EXIFPANEL_SUBDIRECTORY"), currAttrib ? currAttrib->action : AC_DONTWRITE, currAttrib && currAttrib->editable);
  292                 addDirectory (t->getDirectory (j), ch);
  293             }
  294         } else {
  295             addTag (root, t->nameToString (), t->valueToString (), currAttrib ? (t->getOwnMemory() ? currAttrib->action : AC_SYSTEM) : AC_DONTWRITE, currAttrib && currAttrib->editable);
  296         }
  297     }
  298 }
  299 
  300 void ExifPanel::exifSelectionChanged ()
  301 {
  302 
  303     Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
  304     std::vector<Gtk::TreeModel::Path> sel = selection->get_selected_rows();
  305 
  306     if (sel.size() > 1) {
  307         remove->set_sensitive (1);
  308         keep->set_sensitive (1);
  309         reset->set_sensitive (1);
  310     } else if (sel.size() == 1) {
  311         Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (sel[0]);
  312 
  313         if (iter->get_value (exifColumns.action) == AC_SYSTEM) {
  314             remove->set_sensitive (0);
  315             keep->set_sensitive (0);
  316             reset->set_sensitive (0);
  317         } else if (!iter->children().empty()) {
  318             remove->set_sensitive (1);
  319             keep->set_sensitive (1);
  320             reset->set_sensitive (1);
  321         } else if (iter->get_value (exifColumns.icon) == delicon) {
  322             remove->set_sensitive (0);
  323             keep->set_sensitive (1);
  324             reset->set_sensitive (1);
  325         } else if (iter->get_value (exifColumns.icon) == keepicon || iter->get_value (exifColumns.icon) == editicon) {
  326             keep->set_sensitive (0);
  327             remove->set_sensitive (1);
  328             reset->set_sensitive (1);
  329         }
  330     } else {
  331         remove->set_sensitive (0);
  332         keep->set_sensitive (0);
  333         reset->set_sensitive (0);
  334     }
  335 }
  336 
  337 void ExifPanel::delIt (Gtk::TreeModel::iterator iter)
  338 {
  339 
  340     if (!iter) {
  341         return;
  342     }
  343 
  344     if (iter->get_value (exifColumns.action) != AC_SYSTEM) {
  345         iter->set_value (exifColumns.icon, delicon);
  346     }
  347 
  348     if (recursiveOp)
  349         for (Gtk::TreeModel::iterator i = iter->children().begin(); i != iter->children().end(); ++i) {
  350             delIt (i);
  351         }
  352 }
  353 
  354 void ExifPanel::removePressed ()
  355 {
  356 
  357     std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
  358 
  359     for (size_t i = 0; i < sel.size(); i++) {
  360         delIt (exifTreeModel->get_iter (sel[i]));
  361     }
  362 
  363     exifSelectionChanged ();
  364     updateChangeList ();
  365     notifyListener ();
  366 }
  367 
  368 void ExifPanel::keepIt (Gtk::TreeModel::iterator iter)
  369 {
  370 
  371     if (!iter) {
  372         return;
  373     }
  374 
  375     if (iter->get_value (exifColumns.action) != AC_SYSTEM) {
  376         iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon);
  377     }
  378 
  379     if (recursiveOp)
  380         for (Gtk::TreeModel::iterator i = iter->children().begin(); i != iter->children().end(); ++i) {
  381             keepIt (i);
  382         }
  383 }
  384 
  385 void ExifPanel::keepPressed ()
  386 {
  387 
  388     std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
  389 
  390     for (size_t i = 0; i < sel.size(); i++) {
  391         keepIt (exifTreeModel->get_iter (sel[i]));
  392     }
  393 
  394     exifSelectionChanged ();
  395     updateChangeList ();
  396     notifyListener ();
  397 }
  398 
  399 /*void ExifPanel::resetIt (Gtk::TreeModel::iterator  iter) {
  400 
  401     if (!iter)
  402         return;
  403 
  404     if (iter->get_value (exifColumns.action)!=AC_SYSTEM)
  405         iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon);
  406     if (iter->get_value (exifColumns.edited)) {
  407         iter->set_value (exifColumns.value, Glib::ustring("<b>") + iter->get_value(exifColumns.orig_value) + "</b>");
  408         iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value));
  409         iter->set_value (exifColumns.edited, false);
  410     }
  411     if (iter->get_value (exifColumns.action)==AC_INVALID)
  412         exifTreeModel->erase (iter);
  413     else
  414     if (recursiveOp)
  415         for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
  416             resetIt (i);
  417 }*/
  418 Gtk::TreeModel::iterator ExifPanel::resetIt (Gtk::TreeModel::iterator  iter)
  419 {
  420 
  421     if (!iter) {
  422         return iter;
  423     }
  424 
  425     if (iter->get_value (exifColumns.action) != AC_SYSTEM) {
  426         iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon);
  427     }
  428 
  429     if (iter->get_value (exifColumns.edited)) {
  430         iter->set_value (exifColumns.value, Glib::ustring ("<b>") + iter->get_value (exifColumns.orig_value) + "</b>");
  431         iter->set_value (exifColumns.value_nopango, iter->get_value (exifColumns.orig_value));
  432         iter->set_value (exifColumns.edited, false);
  433     }
  434 
  435     if (iter->get_value (exifColumns.action) == AC_INVALID) {
  436         return exifTreeModel->erase (iter);
  437     } else if (recursiveOp) {
  438         Gtk::TreeModel::iterator i = iter->children().begin();
  439 
  440         while (i && i != iter->children().end()) {
  441             i = resetIt (i);
  442         }
  443     }
  444 
  445     return ++iter;
  446 }
  447 void ExifPanel::resetPressed ()
  448 {
  449 
  450     std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
  451 
  452     for (size_t i = 0; i < sel.size(); i++) {
  453         resetIt (exifTreeModel->get_iter (sel[i]));
  454     }
  455 
  456     exifSelectionChanged ();
  457     updateChangeList ();
  458     notifyListener ();
  459 }
  460 
  461 void ExifPanel::resetAllPressed ()
  462 {
  463 
  464     setImageData (idata);
  465     *changeList = *defChangeList;
  466     applyChangeList ();
  467     exifSelectionChanged ();
  468     notifyListener ();
  469 }
  470 
  471 void ExifPanel::addPressed ()
  472 {
  473 
  474     Gtk::Dialog* dialog = new Gtk::Dialog (M ("EXIFPANEL_ADDTAGDLG_TITLE"), * ((Gtk::Window*)get_toplevel()), true);
  475     dialog->add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
  476     dialog->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  477 
  478     Gtk::HBox* hb1 = new Gtk::HBox ();
  479     Gtk::HBox* hb2 = new Gtk::HBox ();
  480 
  481     Gtk::Label* tlabel = new Gtk::Label (M ("EXIFPANEL_ADDTAGDLG_SELECTTAG") + ":");
  482     MyComboBoxText* tcombo = new MyComboBoxText ();
  483 
  484     tcombo->append ("Artist");
  485     tcombo->append ("Copyright");
  486     tcombo->append ("ImageDescription");
  487     tcombo->append ("Exif.UserComment");
  488 
  489     hb1->pack_start (*tlabel, Gtk::PACK_SHRINK, 4);
  490     hb1->pack_start (*tcombo);
  491 
  492     Gtk::Label* vlabel = new Gtk::Label (M ("EXIFPANEL_ADDTAGDLG_ENTERVALUE") + ":");
  493     Gtk::Entry* ventry = new Gtk::Entry ();
  494     hb2->pack_start (*vlabel, Gtk::PACK_SHRINK, 4);
  495     hb2->pack_start (*ventry);
  496 
  497     Glib::ustring sel = getSelection (true);
  498 
  499     if (sel.empty()) {
  500         tcombo->set_active_text ("Exif.UserComment");
  501     } else {
  502         tcombo->set_active_text (sel);
  503 
  504         if (!tcombo->get_active ()) {
  505             tcombo->append (sel);
  506             tcombo->set_active_text (sel);
  507         }
  508 
  509         ventry->set_text (getSelectedValue ());
  510     }
  511 
  512     ventry->set_activates_default (true);
  513     dialog->set_default_response (Gtk::RESPONSE_OK);
  514     dialog->get_content_area()->pack_start (*hb1, Gtk::PACK_SHRINK);
  515     dialog->get_content_area()->pack_start (*hb2, Gtk::PACK_SHRINK, 4);
  516     tlabel->show ();
  517     tcombo->show ();
  518     vlabel->show ();
  519     ventry->show ();
  520     hb1->show ();
  521     hb2->show ();
  522 
  523     if (dialog->run () == Gtk::RESPONSE_OK) {
  524         editTag (exifTreeModel->children(), tcombo->get_active_text(), ventry->get_text());
  525         updateChangeList ();
  526         notifyListener ();
  527     }
  528 
  529     delete dialog;
  530     delete tlabel;
  531     delete tcombo;
  532     delete vlabel;
  533     delete ventry;
  534     delete hb1;
  535     delete hb2;
  536 }
  537 
  538 void ExifPanel::showAlltoggled ()
  539 {
  540     options.lastShowAllExif = showAll->get_active();
  541     setImageData (idata);
  542 }
  543 
  544 bool ExifPanel::rowSeperatorFunc(const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::iterator& iter)
  545 {
  546     return iter->get_value(exifColumns.isSeparator);
  547 }
  548 
  549 void ExifPanel::editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value)
  550 {
  551 
  552     Glib::ustring::size_type dp = name.find_first_of ('.');
  553     Glib::ustring fseg = name.substr (0, dp);
  554     // look up first segment of the path
  555     Gtk::TreeModel::iterator iter;
  556 
  557     for (iter = root.begin(); iter != root.end(); ++iter)
  558         if (iter->get_value (exifColumns.field_nopango) == fseg) {
  559             break;
  560         }
  561 
  562     if (iter == root.end() && value != "#keep" && value != "#delete") {
  563         iter = exifTreeModel->append (root);
  564         iter->set_value (exifColumns.field_nopango, fseg);
  565         iter->set_value (exifColumns.action, AC_INVALID);
  566 
  567         if (dp == Glib::ustring::npos) {
  568             iter->set_value (exifColumns.value, Glib::ustring ("<b>") + value + "</b>");
  569             iter->set_value (exifColumns.value_nopango, value);
  570             iter->set_value (exifColumns.orig_value, value);
  571             iter->set_value (exifColumns.field, Glib::ustring ("<b>") + fseg + "</b>");
  572             iter->set_value (exifColumns.edited, true);
  573             iter->set_value (exifColumns.editable, true);
  574             iter->set_value (exifColumns.icon, editicon);
  575         } else {
  576             iter->set_value (exifColumns.value, Glib::ustring (M ("EXIFPANEL_SUBDIRECTORY")));
  577             iter->set_value (exifColumns.value_nopango, Glib::ustring (M ("EXIFPANEL_SUBDIRECTORY")));
  578             iter->set_value (exifColumns.field, fseg);
  579             iter->set_value (exifColumns.icon, keepicon);
  580             iter->set_value (exifColumns.orig_value, Glib::ustring (M ("EXIFPANEL_SUBDIRECTORY")));
  581         }
  582     }
  583 
  584     if (iter == root.end()) {
  585         return;
  586     }
  587 
  588     if (dp == Glib::ustring::npos) {
  589         if (value == "#keep" && iter->get_value (exifColumns.action) != AC_SYSTEM) {
  590             iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon);
  591         } else if (value == "#delete" && iter->get_value (exifColumns.action) != AC_SYSTEM) {
  592             iter->set_value (exifColumns.icon, delicon);
  593         } else {
  594             iter->set_value (exifColumns.value, Glib::ustring ("<b>") + value + "</b>");
  595             iter->set_value (exifColumns.value_nopango, value);
  596             iter->set_value (exifColumns.edited, true);
  597             iter->set_value (exifColumns.icon, editicon);
  598         }
  599     } else {
  600         editTag (iter->children(), name.substr (dp + 1, Glib::ustring::npos), value);
  601     }
  602 }
  603 
  604 Glib::ustring ExifPanel::getSelectedValue ()
  605 {
  606 
  607     Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
  608     std::vector<Gtk::TreeModel::Path> rows = selection->get_selected_rows();
  609 
  610     if (rows.size() != 1) {
  611         return "";
  612     }
  613 
  614     Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]);
  615 
  616     if (iter) {
  617         return iter->get_value (exifColumns.value_nopango);
  618     }
  619 
  620     return "";
  621 }
  622 
  623 Glib::ustring ExifPanel::getSelection (bool onlyeditable)
  624 {
  625 
  626     Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
  627     std::vector<Gtk::TreeModel::Path> rows = selection->get_selected_rows();
  628 
  629     if (rows.size() != 1) {
  630         return "";
  631     }
  632 
  633     Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]);
  634 
  635     Glib::ustring ret;
  636     bool first = true;
  637     bool editable = false;
  638 
  639     while (iter) {
  640         if (first) {
  641             ret = iter->get_value (exifColumns.field_nopango);
  642             editable = iter->get_value (exifColumns.editable);
  643         } else {
  644             ret = iter->get_value (exifColumns.field_nopango) + "." + ret;
  645         }
  646 
  647         iter = iter->parent ();
  648         first = false;
  649     }
  650 
  651     if (!editable && onlyeditable) {
  652         return "";
  653     }
  654 
  655     return ret;
  656 }
  657 
  658 void ExifPanel::updateChangeList (Gtk::TreeModel::Children root, std::string prefix)
  659 {
  660 
  661     if (!prefix.empty()) {
  662         prefix = prefix + ".";
  663     }
  664 
  665     Gtk::TreeModel::iterator iter;
  666 
  667     for (iter = root.begin(); iter != root.end(); ++iter)  {
  668         if (iter->get_value (exifColumns.edited)) {
  669             (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = iter->get_value (exifColumns.value_nopango);
  670         } else if (iter->get_value (exifColumns.action) == AC_WRITE && iter->get_value (exifColumns.icon) == delicon) {
  671             (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#delete";
  672         } else if (iter->get_value (exifColumns.action) == AC_DONTWRITE && iter->get_value (exifColumns.icon) == keepicon) {
  673             (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#keep";
  674         }
  675 
  676         if (iter->get_value (exifColumns.icon) == keepicon) {
  677             updateChangeList (iter->children(), prefix + iter->get_value (exifColumns.field_nopango));
  678         }
  679     }
  680 }
  681 
  682 void ExifPanel::updateChangeList ()
  683 {
  684 
  685     changeList->clear ();
  686     updateChangeList (exifTreeModel->children(), "");
  687 }
  688 
  689 void ExifPanel::applyChangeList ()
  690 {
  691 
  692     for (rtengine::procparams::ExifPairs::const_iterator i = changeList->begin(); i != changeList->end(); ++i) {
  693         editTag (exifTreeModel->children(), i->first, i->second);
  694     }
  695 }
  696 
  697 void ExifPanel::row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column)
  698 {
  699 
  700     Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (path);
  701 
  702     if (iter) {
  703         if (!iter->children().empty())
  704             if (exifTree->row_expanded (path)) {
  705                 exifTree->collapse_row (path);
  706             } else {
  707                 exifTree->expand_row (path, false);
  708             } else if (iter->get_value (exifColumns.editable)) {
  709             addPressed ();
  710         }
  711     }
  712 }
  713 
  714 
  715 void ExifPanel::notifyListener ()
  716 {
  717 
  718     if (listener) {
  719         listener->panelChanged (EvExif, M ("HISTORY_CHANGED"));
  720     }
  721 }