/*
 *  This file is part of RawTherapee.
 *
 *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
 *  Copyright (c) 2010 Oliver Duis <www.oliverduis.de>
 *
 *  RawTherapee is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  RawTherapee is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <editorpanel.h>
#include <options.h>
#include <progressconnector.h>
#include <rtwindow.h>
#include <guiutils.h>
#include <procparamchangers.h>
#include <safegtk.h>
#include <imagesource.h>
#include <soundman.h>

using namespace rtengine::procparams;

EditorPanel::EditorPanel (FilePanel* filePanel) : beforePreviewHandler(NULL), beforeIarea(NULL), parent(NULL), beforeIpc(NULL), ipc(NULL), catalogPane(NULL) {

    epih = new EditorPanelIdleHelper;
    epih->epanel = this;
    epih->destroyed = false;
    epih->pending = 0;

    processingStartedTime = 0;

// construct toolpanelcoordinator
    tpc = new ToolPanelCoordinator ();

// build GUI
    // build left side panel
    leftbox = new Gtk::VBox ();
    leftbox->set_border_width (2);
    leftbox->set_size_request(100,250);

    histogramPanel = Gtk::manage (new HistogramPanel ());
    histogramPanel->set_size_request (-1, 150);
//    leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 4);

    profilep = Gtk::manage (new ProfilePanel ());
    Gtk::Frame* ppframe = Gtk::manage (new Gtk::Frame ());
    ppframe->add (*profilep);
    ppframe->set_label (M("PROFILEPANEL_LABEL"));
//    leftbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4);

    navigator = Gtk::manage (new Navigator ());
    navigator->previewWindow->set_size_request (-1, 150);
    leftbox->pack_start (*navigator, Gtk::PACK_SHRINK, 2);

    history = Gtk::manage (new History ());
    leftbox->pack_start (*history);

    leftbox->show_all ();

    // build the middle of the screen
    Gtk::VBox* editbox = Gtk::manage (new Gtk::VBox ());

    info = Gtk::manage (new Gtk::ToggleButton ());
    Gtk::Image* infoimg = Gtk::manage (new Gtk::Image (argv0+"/images/info.png"));
    info->add (*infoimg);
    info->set_relief(Gtk::RELIEF_NONE);
    info->set_tooltip_markup (M("MAIN_TOOLTIP_QINFO"));

    beforeAfter = Gtk::manage (new Gtk::ToggleButton ());
    Gtk::Image* beforeAfterIcon = Gtk::manage (new Gtk::Image (argv0+"/images/beforeafter.png"));
    beforeAfter->add(*beforeAfterIcon);
    beforeAfter->set_relief(Gtk::RELIEF_NONE);
    beforeAfter->set_tooltip_markup (M("MAIN_TOOLTIP_TOGGLE"));


    Gtk::VSeparator* vsept = Gtk::manage (new Gtk::VSeparator ());
    Gtk::VSeparator* vsepz = Gtk::manage (new Gtk::VSeparator ());
    Gtk::VSeparator* vsepi = Gtk::manage (new Gtk::VSeparator ());
    Gtk::VSeparator* vseph = Gtk::manage (new Gtk::VSeparator ());
    Gtk::VSeparator* vsep1 = Gtk::manage (new Gtk::VSeparator ());

    hidehp = Gtk::manage (new Gtk::ToggleButton ());

    iHistoryShow = new Gtk::Image(argv0+"/images/panel_to_right.png");
    iHistoryHide = new Gtk::Image(argv0+"/images/panel_to_left.png");

    hidehp->set_relief(Gtk::RELIEF_NONE);
    hidehp->set_active (options.showHistory);
    hidehp->set_tooltip_markup (M("MAIN_TOOLTIP_HIDEHP"));
    if (options.showHistory){
    	hidehp->set_image (*iHistoryHide);
    }
    else {
    	hidehp->set_image (*iHistoryShow);
    }

    tbTopPanel_1 = new Gtk::ToggleButton ();
    iTopPanel_1_Show = new Gtk::Image(argv0+"/images/panel_to_bottom.png");
    iTopPanel_1_Hide = new Gtk::Image(argv0+"/images/panel_to_top.png");
    tbTopPanel_1->set_relief(Gtk::RELIEF_NONE);
    tbTopPanel_1->set_active (true);
    tbTopPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDETP1"));
    tbTopPanel_1->set_image (*iTopPanel_1_Hide);

    tbRightPanel_1 = new Gtk::ToggleButton ();
    iRightPanel_1_Show = new Gtk::Image(argv0+"/images/panel_to_left.png");
    iRightPanel_1_Hide = new Gtk::Image(argv0+"/images/panel_to_right.png");
    tbRightPanel_1->set_relief(Gtk::RELIEF_NONE);
    tbRightPanel_1->set_active (true);
    tbRightPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDERP1"));
    tbRightPanel_1->set_image (*iRightPanel_1_Hide);

    Gtk::VSeparator* vsepcl = Gtk::manage (new Gtk::VSeparator ());
    Gtk::VSeparator* vsepz2 = Gtk::manage (new Gtk::VSeparator ());
    Gtk::VSeparator* vsepz3 = Gtk::manage (new Gtk::VSeparator ());

    iarea = new ImageAreaPanel ();

    Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ());
    toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1);
    toolBarPanel->pack_start (*vseph, Gtk::PACK_SHRINK, 2);
    toolBarPanel->pack_start (*info, Gtk::PACK_SHRINK, 1);
    toolBarPanel->pack_start (*beforeAfter, Gtk::PACK_SHRINK, 1);
    toolBarPanel->pack_start (*vsepi, Gtk::PACK_SHRINK, 2);
    toolBarPanel->pack_start (*tpc->getToolBar(), Gtk::PACK_SHRINK, 1);
    toolBarPanel->pack_start (*vsept, Gtk::PACK_SHRINK, 2);
    
    toolBarPanel->pack_end   (*tbTopPanel_1, Gtk::PACK_SHRINK, 1);
    toolBarPanel->pack_end   (*vsep1, Gtk::PACK_SHRINK, 2);
    toolBarPanel->pack_end   (*tpc->coarse, Gtk::PACK_SHRINK, 2);
    toolBarPanel->pack_end   (*vsepcl, Gtk::PACK_SHRINK, 2);
    toolBarPanel->pack_end   (*iarea->imageArea->indClippedPanel, Gtk::PACK_SHRINK, 0);
    toolBarPanel->pack_end   (*vsepz, Gtk::PACK_SHRINK, 2);

    afterBox = Gtk::manage (new Gtk::VBox ());
    afterBox->pack_start (*iarea);

    beforeAfterBox = Gtk::manage (new Gtk::HBox());
    beforeAfterBox->pack_start (*afterBox);

    editbox->pack_start (*toolBarPanel, Gtk::PACK_SHRINK,0);
    editbox->pack_start (*beforeAfterBox);

    // build right side panel
    vboxright = new Gtk::VBox (false, 0);
    vboxright->set_size_request(100,250);

    vboxright->set_border_width (2);
    vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2);
    vboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 2);
    // main notebook
    vboxright->pack_start (*tpc->toolPanelNotebook);

    // Save buttons
    Gtk::HBox* iops = Gtk::manage (new Gtk::HBox ());

    Gtk::Image *saveButtonImage = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON));
    saveimgas = Gtk::manage (new Gtk::Button ());
    saveimgas->add(*saveButtonImage);
    saveimgas->set_tooltip_markup(M("MAIN_BUTTON_SAVE_TOOLTIP"));

    Gtk::Image *queueButtonImage = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-execute"), Gtk::ICON_SIZE_BUTTON));
    queueimg = Gtk::manage (new Gtk::Button ());
    queueimg->add(*queueButtonImage);
    queueimg->set_tooltip_markup(M("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP"));

    Gtk::Image *sendToEditorButtonImage = Gtk::manage (new Gtk::Image (argv0+"/images/gimp.png"));
    sendtogimp = Gtk::manage (new Gtk::Button ());
    sendtogimp->add(*sendToEditorButtonImage);
    sendtogimp->set_tooltip_markup(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP"));

    iops->pack_start (*saveimgas, Gtk::PACK_SHRINK);
    if(!simpleEditor)
       iops->pack_start (*queueimg, Gtk::PACK_SHRINK);
    iops->pack_start (*sendtogimp, Gtk::PACK_SHRINK);

    // Status box
    statusBox = Gtk::manage (new Gtk::HBox ());
    progressLabel = Gtk::manage (new Gtk::ProgressBar());
    progressLabel->set_fraction(0.0);
    //progressLabel->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("grey") );  // Disable, because in single mode this is may be permanent red without processing

    statusBox->pack_start (*progressLabel);
    iops->pack_start(*statusBox, Gtk::PACK_SHRINK, 2);

    // tbRightPanel_1
    iops->pack_end (*tbRightPanel_1, Gtk::PACK_SHRINK,0);

	// ShowHideSidePanels
    tbShowHideSidePanels = new Gtk::ToggleButton ();
    iShowHideSidePanels = new Gtk::Image(argv0+"/images/crossed_arrows_out_45_02.png");
    tbShowHideSidePanels->set_relief(Gtk::RELIEF_NONE);
    tbShowHideSidePanels->set_active (false);
    tbShowHideSidePanels->set_tooltip_markup (M("MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP"));
    tbShowHideSidePanels->set_image (*iShowHideSidePanels);
    iops->pack_end (*tbShowHideSidePanels, Gtk::PACK_SHRINK,0);
	iops->pack_end (*vsepz2, Gtk::PACK_SHRINK,1);

    // Zoom panel
    iops->pack_end (*iarea->imageArea->zoomPanel, Gtk::PACK_SHRINK, 1);
    iops->pack_end (*vsepz3, Gtk::PACK_SHRINK, 2);

    editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0);
    editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0);
    editbox->show_all ();

    // build screen
    hpanedl = Gtk::manage (new Gtk::HPaned());
    hpanedr = Gtk::manage (new Gtk::HPaned());
    leftbox->reference ();
    vboxright->reference ();
    if (options.showHistory) {
       hpanedl->pack1(*leftbox, false, true);
       hpanedl->set_position (options.historyPanelWidth);
    }

  
    Gtk::VPaned * viewpaned = Gtk::manage (new Gtk::VPaned());
    fPanel = filePanel;
    if(filePanel)
    {
        catalogPane = new Gtk::Paned();
        viewpaned->pack1(*catalogPane, false, true);                    
    }
    viewpaned->pack2(*editbox, true, true);


    Gtk::Frame* vbfr = Gtk::manage (new Gtk::Frame ());    
    vbfr->add (*viewpaned);
    vbfr->set_size_request(100,250);
    hpanedl->pack2(*vbfr, true, true);

    hpanedr->pack1(*hpanedl, true, true);
    hpanedr->pack2(*vboxright, false, true);
	hpanedl->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &EditorPanel::leftPaneButtonReleased) );
	hpanedr->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &EditorPanel::rightPaneButtonReleased) );

    pack_start (*hpanedr);
    show_all ();

    // save as dialog
    if (safe_file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR))
        saveAsDialog = new SaveAsDialog (options.lastSaveAsPath);
    else
        saveAsDialog = new SaveAsDialog (Glib::get_user_special_dir (G_USER_DIRECTORY_PICTURES));

    saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight);

// connect listeners
    profilep->setProfileChangeListener (tpc);
    history->setProfileChangeListener (tpc);
    history->setHistoryBeforeLineListener (this);
    tpc->addPParamsChangeListener (profilep);
    tpc->addPParamsChangeListener (history);
    tpc->addPParamsChangeListener (this);
    iarea->imageArea->setCropGUIListener (tpc->getCropGUIListener());
    iarea->imageArea->setPointerMotionListener (navigator);
	iarea->imageArea->setImageAreaToolListener (tpc);

// initialize components
    info->set_active (options.showInfo);
    tpc->readOptions ();

// connect event handlers
    info->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::info_toggled) );
    beforeAfter->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::beforeAfterToggled) );
    hidehp->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::hideHistoryActivated) );
    tbTopPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbTopPanel_1_toggled) );
    tbRightPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbRightPanel_1_toggled) );
    saveimgas->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::saveAsPressed) );
    queueimg->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::queueImgPressed) );
    sendtogimp->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::sendToGimpPressed) );
    ShowHideSidePanelsconn = tbShowHideSidePanels->signal_toggled().connect ( sigc::mem_fun(*this, &EditorPanel::toggleSidePanels), true);
}

EditorPanel::~EditorPanel () {

    history->setHistoryBeforeLineListener (NULL);
    // the order is important!
    iarea->setBeforeAfterViews (NULL, iarea);
    delete iarea;
    iarea = NULL;

    if (beforeIpc)
        beforeIpc->stopProcessing ();

    delete beforeIarea;
    beforeIarea = NULL;
    if (beforeIpc)
        beforeIpc->setPreviewImageListener (NULL);

    if (beforeIpc)
        beforeIpc->setPreviewImageListener (NULL);

    delete beforePreviewHandler;
    beforePreviewHandler = NULL;
    if (beforeIpc)
        rtengine::StagedImageProcessor::destroy (beforeIpc);
    beforeIpc = NULL;

    close ();

    if (epih->pending)
        epih->destroyed = true;
    else
        delete epih;

    delete tpc;

    delete leftbox;
    delete vboxright;    
    delete saveAsDialog;
    if(catalogPane)
        delete catalogPane;
}

void EditorPanel::leftPaneButtonReleased(GdkEventButton *event) {
	if (event->button == 1) {
		// Button 1 released : it's a resize
		options.historyPanelWidth = hpanedl->get_position();
	}
	/*else if (event->button == 3) {
	}*/
}

void EditorPanel::rightPaneButtonReleased(GdkEventButton *event) {
	if (event->button == 1) {
		int winW, winH;
		parent->get_size(winW, winH);
		// Button 1 released : it's a resize
		options.toolPanelWidth = winW - hpanedr->get_position();
	}
	/*else if (event->button == 3) {
	}*/
}

void EditorPanel::setAspect () {
	int winW, winH;
	parent->get_size(winW, winH);
	hpanedl->set_position(options.historyPanelWidth);
	hpanedr->set_position(winW - options.toolPanelWidth);
	// initialize components
	if (info->get_active() != options.showInfo)
		info->set_active (options.showInfo);
}

void EditorPanel::on_realize () {
    
    Gtk::VBox::on_realize ();
    // This line is needed to avoid autoexpansion of the window :-/
    vboxright->set_size_request (options.toolPanelWidth, -1);
}

void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) {

    close();
    // initialize everything
    openThm = tmb;
    openThm->increaseRef ();

    fname=openThm->getFileName();

    previewHandler = new PreviewHandler ();

    this->isrc = isrc;
    ipc = rtengine::StagedImageProcessor::create (isrc);
    ipc->setProgressListener (this);
    ipc->setPreviewImageListener (previewHandler);
    ipc->setPreviewScale (10);  // Important
    tpc->initImage (ipc, tmb->getType()==FT_Raw);
    ipc->setHistogramListener (this);

//    iarea->fitZoom ();   // tell to the editorPanel that the next image has to be fitted to the screen
    iarea->imageArea->setPreviewHandler (previewHandler);
    iarea->imageArea->setImProcCoordinator (ipc);
    navigator->previewWindow->setPreviewHandler (previewHandler);
    navigator->previewWindow->setImageArea (iarea->imageArea);

    // try to load the last saved parameters from the cache or from the paramfile file
    ProcParams* ldprof = NULL;

    Glib::ustring defProf = openThm->getType()==FT_Raw ? options.defProfRaw : options.defProfImg;

    const CacheImageData* cfs=openThm->getCacheImageData();
    if (!options.customProfileBuilder.empty() && !openThm->hasProcParams() && cfs && cfs->exifValid) {
        // For the filename etc. do NOT use streams, since they are not UTF8 safe
        Glib::ustring cmdLine=Glib::ustring("\"") + options.customProfileBuilder + Glib::ustring("\" \"") + fname + Glib::ustring("\" \"")
        + options.rtdir + Glib::ustring("/") + options.profilePath + Glib::ustring("/") + defProf + Glib::ustring(".pp3") + Glib::ustring("\" ");

        // ustring doesn't know int etc formatting, so take these via (unsafe) stream
        std::ostringstream strm;
        strm << cfs->fnumber << Glib::ustring(" ") << cfs->shutter << Glib::ustring(" ");
        strm << cfs->focalLen << Glib::ustring(" ") << cfs->iso << Glib::ustring(" \"");
        strm << cfs->lens << Glib::ustring("\" \"") << cfs->camera << Glib::ustring("\"");
 
        bool success = safe_spawn_command_line_sync (cmdLine + strm.str());

        // Now they SHOULD be there, so try to load them
        if (success) openThm->loadProcParams();
    }

    if (openThm->hasProcParams()) {
        ldprof = new ProcParams ();
        *ldprof = openThm->getProcParams ();
    }

    rtengine::ImageSource* is=isrc->getImageSource();
    is->setProgressListener( this );
    // initialize profile
    profilep->initProfile (defProf, ldprof, NULL);

    openThm->addThumbnailListener (this);
    info_toggled ();
    
    if (beforeIarea)
    {
        beforeAfterToggled();
        beforeAfterToggled();
    }

    // If in single tab mode, the main crop window is not constructed the very first time
    // since there was no resize event
    if (iarea->imageArea->mainCropWindow)
    {
    	iarea->imageArea->mainCropWindow->cropHandler.newImage(ipc);
        iarea->imageArea->mainCropWindow->initialImageArrived();

		// In single tab mode, the image is not always updated between switches
		// normal redraw don't work, so this is the hard way
		if (!options.tabbedUI) iarea->imageArea->mainCropWindow->cropHandler.update();
    } else {
        Gtk::Allocation alloc;
        iarea->imageArea->on_resized(alloc);
    }
}

void EditorPanel::close () {
    if (ipc)
    {
        saveProfile ();
        // close image processor and the current thumbnail
        tpc->closeImage ();    // this call stops image processing
        tpc->writeOptions ();
        rtengine::ImageSource* is=isrc->getImageSource();
        is->setProgressListener( NULL );

        if (ipc)
            ipc->setPreviewImageListener (NULL);

        if (beforeIpc)
            beforeIpc->setPreviewImageListener (NULL);

        delete previewHandler;
        previewHandler= NULL;

        if(iarea)
        {
            iarea->imageArea->setPreviewHandler (NULL);
            iarea->imageArea->setImProcCoordinator (NULL);
        }
        rtengine::StagedImageProcessor::destroy (ipc);
        ipc = NULL;
        navigator->previewWindow->setPreviewHandler (NULL);

        // If the file was deleted somewhere, the openThm.descreaseRef delete the object, but we don't know here
        if (safe_file_test(fname, Glib::FILE_TEST_EXISTS)) {
        openThm->removeThumbnailListener (this);
        openThm->decreaseRef ();
        }
    }
}

void EditorPanel::saveProfile () {
    if (!ipc || !openThm) return;

    // If the file was deleted, do not generate ghost entries
    if (safe_file_test(fname, Glib::FILE_TEST_EXISTS)) {
    ProcParams params;
    ipc->getParams (&params);

    if (options.saveParamsFile)
        params.save (openThm->getFileName() + paramFileExtension);
    if (options.saveParamsCache)
        openThm->setProcParams (params, EDITOR);
}
}

Glib::ustring EditorPanel::getShortName () {

    return Glib::path_get_basename (openThm->getFileName ());
}

Glib::ustring EditorPanel::getFileName () {

    return openThm->getFileName ();
}

// TODO!!!
void EditorPanel::procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) {

//    if (ev!=EvPhotoLoaded)
//        saveLabel->set_markup (Glib::ustring("<span foreground=\"#AA0000\" weight=\"bold\">") + M("MAIN_BUTTON_SAVE") + "</span>");
}

struct spsparams {
    bool inProcessing;
    EditorPanelIdleHelper* epih;
};

int setProgressStateUIThread (void* data) {

    gdk_threads_enter ();
    spsparams* p = (spsparams*)data;

    if (p->epih->destroyed) {
        if (p->epih->pending == 1)
            delete p->epih;
        else
            p->epih->pending--;
        delete p;
        gdk_threads_leave ();
        return 0;
    }

    p->epih->epanel->refreshProcessingState (p->inProcessing);
    p->epih->pending--;
    delete p;
    gdk_threads_leave ();
    return 0;
}

void EditorPanel::setProgressState (bool inProcessing) {

    epih->pending++;

    spsparams* p = new spsparams;
    p->inProcessing = inProcessing;
    p->epih = epih;
    g_idle_add (setProgressStateUIThread, p);
}

struct spparams {
    double val;
    Glib::ustring str;
    Gtk::ProgressBar *pProgress;
	bool gtkEnter;
};

int _setprogressStr( void *p )
{
	spparams *s= (spparams*)p;
	if (s->gtkEnter) gdk_threads_enter ();

	if( ! s->str.empty() )
	   s->pProgress->set_text( M(s->str) );
	if( s->val >=0 ){
	   s->pProgress->set_fraction( s->val );
		if( s->val <1.0 )
			s->pProgress->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("red") );
		else
			s->pProgress->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("grey") );
	}
	
	if (s->gtkEnter) gdk_threads_leave ();

	delete s;
	return 0;
}

void EditorPanel::setProgress (double p)
{
	spparams *s=new spparams;
	s->val = p;
	s->pProgress = progressLabel;
	s->gtkEnter = true;
	g_idle_add (_setprogressStr, s);
}

void EditorPanel::setProgressStr (Glib::ustring str)
{
	spparams *s=new spparams;
	s->str = str;
	s->val = -1;
	s->pProgress = progressLabel;
	s->gtkEnter = true;
	g_idle_add (_setprogressStr, s);
}

// This is only called from the ThreadUI, so within the gtk thread
void EditorPanel::refreshProcessingState (bool inProcessing) {
	spparams *s=new spparams;
    s->pProgress = progressLabel;
	s->gtkEnter = false;

    if (inProcessing) {
        if (processingStartedTime==0) processingStartedTime = ::time(NULL);

    	s->str = "PROGRESSBAR_PROCESSING";
    	s->val = 0.0;
    } else {
    // Set proc params of thumbnail. It saves it into the cache and updates the file browser.
			if (ipc && openThm && tpc->getChangedState()) {
        rtengine::procparams::ProcParams pparams;
        ipc->getParams (&pparams);
        openThm->setProcParams (pparams, EDITOR, false);
    }

		// Ring a sound if it was a long event
        if (processingStartedTime!=0) {
            time_t curTime= ::time(NULL);
            if (::difftime(curTime, processingStartedTime) > options.sndLngEditProcDoneSecs) 
                SoundManager::playSoundAsync(options.sndLngEditProcDone);

            processingStartedTime = 0;
        }

		// Set progress bar "done"
    	s->str = "PROGRESSBAR_READY";
    	s->val = 1.0;
}

	_setprogressStr(s);
}

struct errparams {
    Glib::ustring descr;
    EditorPanelIdleHelper* epih;
};

void EditorPanel::displayError (Glib::ustring descr) {

    if (parent) {
        Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, descr, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        msgd->set_title (M("MAIN_MSG_CANNOTSAVE"));
        msgd->run ();
        delete msgd;
    }
}

int disperror (void* data) {

    gdk_threads_enter ();
    errparams* p = (errparams*)data;

    if (p->epih->destroyed) {
        if (p->epih->pending == 1)
            delete p->epih;
        else
            p->epih->pending--;
        delete p;
        gdk_threads_leave ();
        return 0;
    }

    p->epih->epanel->displayError (p->descr);
    p->epih->pending--;
    delete p;
    gdk_threads_leave ();
    return 0;
}

void EditorPanel::error (Glib::ustring descr) {

    epih->pending++;
    errparams* p = new errparams;
    p->descr = descr;
    p->epih = epih;
    g_idle_add (disperror, p);
}

void EditorPanel::info_toggled () {

    Glib::ustring infoString;
    if (!ipc || !openThm) return;
    const rtengine::ImageMetaData* idata = ipc->getInitialImage()->getMetaData();
    if (idata && idata->hasExif())
//        infoString = Glib::ustring::compose ("%1 %2\nF/%3 %4 sec\n%5: %6\n%7: %8 mm\n",
//            Glib::ustring(idata->getMake()), Glib::ustring(idata->getModel()),
//            Glib::ustring(idata->apertureToString(idata->getFNumber())), Glib::ustring(idata->shutterToString(idata->getShutterSpeed())),
//            M("QINFO_ISO"), idata->getISOSpeed(),
//            M("QINFO_FOCALLENGTH"), idata->getFocalLen())
//            + Glib::ustring::compose ("%1: %2", M("QINFO_LENS"), Glib::ustring(idata->getLens()));
infoString = Glib::ustring::compose (
            "%1 + %2\n<span size=\"small\">f/</span><span size=\"large\">%3</span>  <span size=\"large\">%4</span><span size=\"small\">s</span>  <span size=\"small\">%5</span><span size=\"large\">%6</span>  <span size=\"large\">%7</span><span size=\"small\">mm</span>\n<span size=\"small\">%8</span>",
            Glib::ustring(idata->getMake()+" "+idata->getModel()),
            Glib::ustring(idata->getLens()),
            Glib::ustring(idata->apertureToString(idata->getFNumber())),
            Glib::ustring(idata->shutterToString(idata->getShutterSpeed())),
            M("QINFO_ISO"), idata->getISOSpeed(),
            idata->getFocalLen(),
            openThm->getFileName ()
            );
    else
        infoString = M("QINFO_NOEXIF");

    iarea->imageArea->setInfoText (infoString);
    iarea->imageArea->infoEnabled (info->get_active ());
}

void EditorPanel::hideHistoryActivated () {

    removeIfThere (hpanedl, leftbox, false);
    if (hidehp->get_active())
        hpanedl->pack1 (*leftbox, false, true);
    options.showHistory = hidehp->get_active();

    if (options.showHistory){
    	hidehp->set_image (*iHistoryHide);
    }
    else {
    	hidehp->set_image (*iHistoryShow);
    }

    tbShowHideSidePanels_managestate();
}


void EditorPanel::tbRightPanel_1_toggled () {
/*
    removeIfThere (hpanedr, vboxright, false);
    if (tbRightPanel_1->get_active()){
        hpanedr->pack2(*vboxright, false, true);
    	tbRightPanel_1->set_image (*iRightPanel_1_Hide);
    }
    else {
    	tbRightPanel_1->set_image (*iRightPanel_1_Show);
    }
    tbShowHideSidePanels_managestate();
    */
	if (vboxright){
		if (tbRightPanel_1->get_active()){
			vboxright->show();
			tbRightPanel_1->set_image (*iRightPanel_1_Hide);
		}
		else{
			vboxright->hide();
			tbRightPanel_1->set_image (*iRightPanel_1_Show);
		}
		tbShowHideSidePanels_managestate();
	}
}

void EditorPanel::tbTopPanel_1_visible (bool visible){
	if (visible)
		tbTopPanel_1->show();
	else
		tbTopPanel_1->hide();
}

void EditorPanel::tbTopPanel_1_toggled () {

	if (catalogPane){ // catalogPane does not exist in multitab mode
		tbTopPanel_1_Active = tbTopPanel_1->get_active();

		if (tbTopPanel_1_Active){
			catalogPane->show();
			tbTopPanel_1->set_image (*iTopPanel_1_Hide);
		}
		else {
			catalogPane->hide();
			tbTopPanel_1->set_image (*iTopPanel_1_Show);
		}

		tbShowHideSidePanels_managestate();
	}
}

bool EditorPanel::handleShortcutKey (GdkEventKey* event) {

    bool ctrl = event->state & GDK_CONTROL_MASK;
    bool shift = event->state & GDK_SHIFT_MASK;
    bool alt = event->state & GDK_MOD1_MASK;


    // Editor Layout
    switch(event->keyval) {
        case GDK_L:
		    tbTopPanel_1->set_active (!tbTopPanel_1->get_active()); // toggle top panel
		    if (ctrl) hidehp->set_active (!hidehp->get_active()); // toggle History (left panel)
			if (alt) tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); // toggle right panel
			return true;
    	case GDK_l:
    		if (!shift && !alt /*&& !ctrl*/){
    			hidehp->set_active (!hidehp->get_active()); // toggle History (left panel)
    		    return true;
    		}
			if (alt && !ctrl){ // toggle right panel
				tbRightPanel_1->set_active (!tbRightPanel_1->get_active());
				return true;
			}
			if (alt && ctrl){ // toggle left and right panels
				hidehp->set_active (!hidehp->get_active());
				tbRightPanel_1->set_active (!tbRightPanel_1->get_active());
				return true;
			}
        case GDK_m: // Maximize preview panel: hide top AND right AND history panels
        	if (!ctrl && !alt) {
        		toggleSidePanels();
        		return true;
        	}
        case GDK_M: // Maximize preview panel: hide top AND right AND history panels AND (fit image preview)
        	if (!ctrl && !alt) {
        		toggleSidePanelsZoomFit();
        		return true;
        	}
    }

    if (!alt){
		if (!ctrl) {
			// Normal
			switch(event->keyval) {
				case GDK_bracketright:
					tpc->coarse->rotateRight();
					return true;
				case GDK_bracketleft:
					tpc->coarse->rotateLeft();
					return true;

				case GDK_i:
				case GDK_I:
					info->set_active (!info->get_active());
					return true;
				case GDK_b:
				case GDK_B:
					beforeAfter->set_active (!beforeAfter->get_active());
					return true;
				case GDK_plus:
				case GDK_equal:
					iarea->imageArea->zoomPanel->zoomInClicked();
					return true;
				case GDK_minus:
				case GDK_underscore:
					iarea->imageArea->zoomPanel->zoomOutClicked();
					return true;
				case GDK_1:
					iarea->imageArea->zoomPanel->zoom11Clicked();
					return true;

				case GDK_f:
					iarea->imageArea->zoomPanel->zoomFitClicked();
					return true;
				case GDK_less:
					iarea->imageArea->indClippedPanel->toggleClipped(true);
					return true;
				case GDK_greater:
					iarea->imageArea->indClippedPanel->toggleClipped(false);
					return true;

				case GDK_F5:
					openThm->openDefaultViewer(event->state & GDK_SHIFT_MASK ? 2 : 1);
					return true;
			}
		}
		else {
			// With control
			switch (event->keyval) {
				case GDK_s:
					saveAsPressed();
					return true;
				case GDK_q:
					queueImgPressed();
					return true;
				case GDK_e:
					sendToGimpPressed();
					return true;
				case GDK_z:
					history->undo ();
					return true;
				case GDK_Z:
					history->redo ();
					return true;
				case GDK_F5:
					openThm->openDefaultViewer(3);
					return true;
			}
		} //if (!ctrl)
    } //if (!alt)

    if(tpc->getToolBar()->handleShortcutKey(event))
        return true;
    if(tpc->handleShortcutKey(event))
        return true;

    return false;
}

void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) {

    if (whoChangedIt!=EDITOR)
      tpc->profileChange (&openThm->getProcParams(), rtengine::EvProfileChangeNotification, M("PROGRESSDLG_PROFILECHANGEDINBROWSER"));
}

bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImage16*> *pc, Glib::ustring fname, SaveFormat sf, bool findNewNameIfNeeded){
	rtengine::IImage16* img = pc->returnValue();
	delete pc;
	if( img )
	   saveImage( img, fname, sf, findNewNameIfNeeded);
	else{
		Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": Error during image processing\n</b>";
		Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
		msgd.run ();

        saveimgas->set_sensitive(true);
        sendtogimp->set_sensitive(true);

	}
	rtengine::ImageSource* imgsrc = isrc->getImageSource ();
    imgsrc->setProgressListener(this);
	return false;
}

BatchQueueEntry* EditorPanel::createBatchQueueEntry () {

    rtengine::procparams::ProcParams pparams;
    ipc->getParams (&pparams);
    //rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
    rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (openThm->getFileName (), openThm->getType()==FT_Raw, pparams);
    int prevh = options.maxThumbnailHeight;
    int prevw = prevh;
    guint8* prev = NULL;//(guint8*) previewHandler->getImagePreview (prevw, prevh);
    double tmpscale;
    rtengine::IImage8* img = openThm->processThumbImage (pparams, options.maxThumbnailHeight, tmpscale);
    if (img) {
    	prevw = img->getWidth ();
    	prevh = img->getHeight ();
        prev = new guint8 [prevw*prevh*3];
        memcpy (prev, img->getData (), prevw*prevh*3);
        img->free();
    }
    return new BatchQueueEntry (job, pparams, openThm->getFileName(), prev, prevw, prevh, openThm);
}

int EditorPanel::saveImage (rtengine::IImage16* img, Glib::ustring& fname, SaveFormat sf, bool findNewNameIfNeeded) {

    Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format);
    if (findNewNameIfNeeded) {
        int tries = 1;
        while (safe_file_test (fileName, Glib::FILE_TEST_EXISTS) && tries<1000) {
            fileName = Glib::ustring::compose("%1-%2.%3", fname, tries, sf.format);
            tries++;
        }
        if (tries==1000)
            return -1000;
    }
    ProgressConnector<int> *ld = new ProgressConnector<int>();
    img->setSaveProgressListener (parent->getProgressListener());
    if (sf.format=="tif")
    	ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
    			       sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fileName,sf));
    else if (sf.format=="png")
    	ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsPNG), fileName, sf.pngCompression, sf.pngBits),
    			       sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fileName,sf));
    else if (sf.format=="jpg")
    	ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsJPEG), fileName, sf.jpegQuality),
    			       sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fileName,sf));
    return 0;
}

bool EditorPanel::idle_imageSaved(ProgressConnector<int> *pc,rtengine::IImage16* img,Glib::ustring fname, SaveFormat sf){
	img->free ();
	if (! pc->returnValue() ) {
		openThm->imageDeveloped ();
		// save processing parameters, if needed
		if (sf.saveParams) {
			rtengine::procparams::ProcParams pparams;
			ipc->getParams (&pparams);
			// We keep the extension to avoid overwriting the profile when we have
			// the same output filename with different extension
			//pparams.save (removeExtension (fname) + ".out" + paramFileExtension);
			pparams.save (fname + ".out" + paramFileExtension);
		}
	}else{
		Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": Error during image saving\n</b>";
		Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
		msgd.run ();
    }
    saveimgas->set_sensitive(true);
    sendtogimp->set_sensitive(true);
	parent->setProgressStr("");
	parent->setProgress(0.);
	delete pc;
    return false;
}

void EditorPanel::saveAsPressed () {
	if (!ipc || !openThm) return;
	bool fnameOK = false;
	Glib::ustring fname;

	saveAsDialog->setInitialFileName (removeExtension (Glib::path_get_basename (openThm->getFileName())));
	do {
		saveAsDialog->run ();
		fname = saveAsDialog->getFileName ();
		if (fname=="")
			return;

		options.lastSaveAsPath = saveAsDialog->getDirectory ();
		options.saveAsDialogWidth = saveAsDialog->get_width();
		options.saveAsDialogHeight = saveAsDialog->get_height();

		SaveFormat sf = saveAsDialog->getFormat ();

		options.saveFormat = sf;
		options.autoSuffix = saveAsDialog->getAutoSuffix();

		if (saveAsDialog->getImmediately ()) {
			// separate filename and the path to the destination directory
			Glib::ustring dstdir = Glib::path_get_dirname (fname);
			Glib::ustring dstfname = Glib::path_get_basename (removeExtension(fname));

			if (saveAsDialog->getAutoSuffix()) {

				Glib::ustring fnameTemp;
				for (int tries=0; tries<100; tries++) {
					if (tries==0)
						fnameTemp = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir,  dstfname), sf.format);
					else
						fnameTemp = Glib::ustring::compose ("%1-%2.%3", Glib::build_filename (dstdir,  dstfname), tries, sf.format);

					if (!safe_file_test (fnameTemp, Glib::FILE_TEST_EXISTS)) {
						fname = fnameTemp;
						fnameOK = true;
						break;
					}
				}
			}
			// check if it exists
			if (!fnameOK) {
				fname = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir,  dstfname), sf.format);
				if (safe_file_test (fname, Glib::FILE_TEST_EXISTS)) {
					Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + "</b>";
					Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
					int response = msgd.run ();
					if (response==Gtk::RESPONSE_YES)
						fnameOK = true;
				}
				else fnameOK = true;
			}

			if (fnameOK) {
				// save image
				rtengine::procparams::ProcParams pparams;
				ipc->getParams (&pparams);
				rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
				fname = removeExtension (fname);
				ProgressConnector<rtengine::IImage16*> *ld = new ProgressConnector<rtengine::IImage16*>();
				ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData ),
							  sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_saveImage ),ld,fname,sf,false ));
				saveimgas->set_sensitive(false);
				sendtogimp->set_sensitive(false);
			}
		}
		else {
			BatchQueueEntry* bqe = createBatchQueueEntry ();
			bqe->outFileName = fname;
			bqe->saveFormat = saveAsDialog->getFormat ();
			parent->addBatchQueueJob (bqe, saveAsDialog->getToHeadOfQueue ());
			fnameOK = true;
		}
		// ask parent to redraw file browser
		// ... or does it automatically when the tab is switched to it
	} while (!fnameOK);
}

void EditorPanel::queueImgPressed () {
	if (!ipc || !openThm) return;
    saveProfile ();
    parent->addBatchQueueJob (createBatchQueueEntry ());
}

void EditorPanel::sendToGimpPressed () {
	if (!ipc || !openThm) return;
    // develop image
    rtengine::procparams::ProcParams pparams;
    ipc->getParams (&pparams);
    rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
    ProgressConnector<rtengine::IImage16*> *ld = new ProgressConnector<rtengine::IImage16*>();
    ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData ),
    		      sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_sendToGimp ),ld ));
    saveimgas->set_sensitive(false);
    sendtogimp->set_sensitive(false);
}

bool EditorPanel::idle_sendToGimp( ProgressConnector<rtengine::IImage16*> *pc){

	rtengine::IImage16* img = pc->returnValue();
	delete pc;
    if (img) {
        // get file name base
        Glib::ustring shortname = removeExtension (Glib::path_get_basename (openThm->getFileName()));
        Glib::ustring dirname = Glib::get_tmp_dir ();
        Glib::ustring fname = Glib::build_filename (dirname, shortname);

        SaveFormat sf;
        sf.format = "tif";
        sf.tiffBits = 16;
        sf.tiffUncompressed = true;
        sf.saveParams = true;

        Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format);

				int tries = 1;
				while (safe_file_test (fileName, Glib::FILE_TEST_EXISTS) && tries<1000) {
					fileName = Glib::ustring::compose("%1-%2.%3", fname, tries, sf.format);
					tries++;
				}
				if (tries==1000){
					img->free ();
					return false;
				}

        ProgressConnector<int> *ld = new ProgressConnector<int>();
        img->setSaveProgressListener (parent->getProgressListener());
       	ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
        			   sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_sentToGimp), ld, img, fileName));
    }else{
				Glib::ustring msg_ = Glib::ustring("<b> Error during image processing\n</b>");
				Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
				msgd.run ();
        saveimgas->set_sensitive(true);
        sendtogimp->set_sensitive(true);
    }
    return false;
}

bool EditorPanel::idle_sentToGimp(ProgressConnector<int> *pc,rtengine::IImage16* img,Glib::ustring filename){
    img->free ();
    int errore = pc->returnValue();
    delete pc;
    if (!errore) {
                        saveimgas->set_sensitive(true);
                        sendtogimp->set_sensitive(true);
    	                parent->setProgressStr("");
    	                parent->setProgress(0.);
						bool success=false;
						Glib::ustring cmdLine;
						Glib::ustring executable;
						// start gimp
						if (options.editorToSendTo==1) {
#ifdef _WIN32
								executable = Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), "gimp-win-remote");
								cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" gimp-2.4.exe ") + Glib::ustring("\"") + filename + Glib::ustring("\"");
								if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) {
									success = safe_spawn_command_line_async (cmdLine);
								}
#else
								cmdLine = Glib::ustring("gimp-remote ") + Glib::ustring(" \"") + filename + Glib::ustring("\"");
								success = safe_spawn_command_line_async (cmdLine);
#endif
								if (!success){
#ifdef _WIN32
										int ver = 12;
										while (!success && ver) {
												executable = Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"),ver));
												if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) {
													cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" \"") + filename + Glib::ustring("\"");
													success = safe_spawn_command_line_async (cmdLine);
												}
												ver--;
										}
#elif defined __APPLE__
										cmdLine = Glib::ustring("gimp \"") + filename + Glib::ustring("\"");
										success = safe_spawn_command_line_async (cmdLine);
#else
										cmdLine = Glib::ustring("gimp \"") + filename + Glib::ustring("\"");
										success = safe_spawn_command_line_async (cmdLine);
#endif
								}
						}
						else if (options.editorToSendTo==2) {
#ifdef _WIN32
								executable = Glib::build_filename(options.psDir,"Photoshop.exe");
								if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) {
										cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" \"") + filename + Glib::ustring("\"");
										success = safe_spawn_command_line_async (cmdLine);
								}
#else
		#ifdef __APPLE__
								cmdLine = Glib::ustring("open -a \'") + Glib::build_filename(options.psDir,"Photoshop.app\' ")  + Glib::ustring("\'") + filename + Glib::ustring("\'");
		#else
								cmdLine = Glib::ustring("\"") + Glib::build_filename(options.psDir,"Photoshop.exe") + Glib::ustring("\" \"") + filename + Glib::ustring("\"");
		#endif
								success = safe_spawn_command_line_async (cmdLine);
#endif
						}
						else if (options.editorToSendTo==3) {
#ifdef _WIN32
								if ( safe_file_test(options.customEditorProg, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) {
										cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\" \"") + filename + Glib::ustring("\"");
										success = safe_spawn_command_line_async (cmdLine);
								}
#else
		#ifdef __APPLE__
								cmdLine = options.customEditorProg + filename;
		#else
								cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\" \"") + filename + Glib::ustring("\"");
		#endif
								success = safe_spawn_command_line_async (cmdLine);
#endif
						}

						if (!success) {
								Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, M("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
								msgd->set_secondary_text (M("MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY"));
								msgd->set_title (M("MAIN_BUTTON_SENDTOEDITOR"));
								msgd->run ();
								delete msgd;
						}

    }

    return false;
}

void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) {

    if (beforeIpc) {
        ProcParams* pparams = beforeIpc->getParamsForUpdate (rtengine::EvProfileChanged);
        *pparams = params;
        beforeIpc->paramsUpdateReady ();
    }
}

void EditorPanel::beforeAfterToggled () {

    if(!ipc)
        return;

    removeIfThere (beforeAfterBox,  beforeBox, false);
    removeIfThere (afterBox,  afterLabel, false);

    if (beforeIarea) {
        if (beforeIpc)
            beforeIpc->stopProcessing ();
        iarea->setBeforeAfterViews (NULL, iarea);
        delete beforeIarea;
        beforeIarea = NULL;
        if (beforeIpc)
            beforeIpc->setPreviewImageListener (NULL);
        delete beforePreviewHandler;
        beforePreviewHandler = NULL;
        if (beforeIpc)
            rtengine::StagedImageProcessor::destroy (beforeIpc);
        beforeIpc = NULL;
    }

    if (beforeAfter->get_active ()) {
        int errorCode=0;
        rtengine::InitialImage *beforeImg = rtengine::InitialImage::load ( isrc->getImageSource ()->getFileName(),  openThm->getType()==FT_Raw , &errorCode, NULL);
        if( !beforeImg || errorCode )
        	return;

        beforeIarea = new ImageAreaPanel ();

        beforeLabel = Gtk::manage (new Gtk::Label ());
        beforeLabel->set_markup (Glib::ustring("<b>") + M("GENERAL_BEFORE") + "</b>");
        beforeBox = Gtk::manage (new Gtk::VBox ());
        beforeBox->pack_start (*beforeLabel, Gtk::PACK_SHRINK, 2);
        beforeBox->pack_start (*beforeIarea);

        afterLabel = Gtk::manage (new Gtk::Label ());
        afterLabel->set_markup (Glib::ustring("<b>") + M("GENERAL_AFTER") + "</b>");
        afterBox->pack_start (*afterLabel, Gtk::PACK_SHRINK, 2);
        afterBox->reorder_child (*afterLabel, 0);

        beforeAfterBox->pack_start (*beforeBox);
        beforeAfterBox->reorder_child (*beforeBox, 0);
        beforeAfterBox->show_all ();

        beforePreviewHandler = new PreviewHandler ();

        beforeIpc = rtengine::StagedImageProcessor::create (beforeImg);
        beforeIpc->setPreviewScale (10);
        beforeIpc->setPreviewImageListener (beforePreviewHandler);
        beforeIarea->imageArea->setPreviewHandler (beforePreviewHandler);
        beforeIarea->imageArea->setImProcCoordinator (beforeIpc);

        iarea->setBeforeAfterViews (beforeIarea, iarea);
        beforeIarea->setBeforeAfterViews (beforeIarea, iarea);

        rtengine::procparams::ProcParams params;
        if (history->getBeforeLineParams (params))
            historyBeforeLineChanged (params);
    }
}

void EditorPanel::histogramChanged (LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histToneCurve, LUTu & histLCurve,
    LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) {

    histogramPanel->histogramChanged (histRed, histGreen, histBlue, histLuma, histRedRaw, histGreenRaw, histBlueRaw);
    tpc->updateCurveBackgroundHistogram (histToneCurve, histLCurve);
}

bool EditorPanel::CheckSidePanelsVisibility(){
	if(tbTopPanel_1->get_active()==false && tbRightPanel_1->get_active()==false && hidehp->get_active()==false)
		return false;
	else
		return true;
}
void EditorPanel::toggleSidePanels(){
	// Maximize preview panel:
	// toggle top AND right AND history panels

	bool bAllSidePanelsVisible;
	bAllSidePanelsVisible= CheckSidePanelsVisibility();

	tbTopPanel_1->set_active (!bAllSidePanelsVisible);
	tbRightPanel_1->set_active (!bAllSidePanelsVisible);
	hidehp->set_active (!bAllSidePanelsVisible);
}

void EditorPanel::toggleSidePanelsZoomFit(){
	toggleSidePanels();

	// fit image preview
	// !!! TODO this does not want to work... seems to have an effect on a subsequent key press
	// iarea->imageArea->zoomPanel->zoomFitClicked();
}

void EditorPanel::tbShowHideSidePanels_managestate(){
	bool bAllSidePanelsVisible;
	bAllSidePanelsVisible = CheckSidePanelsVisibility();
	ShowHideSidePanelsconn.block (true);

	tbShowHideSidePanels->set_active (!bAllSidePanelsVisible);

	ShowHideSidePanelsconn.block (false);
}
