/***************************** LICENSE START ***********************************

 Copyright 2015 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "ViewEditor.h"

#include <QAction>
#include <QCloseEvent>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMouseEvent>
#include <QPushButton>
#include <QSpinBox>
#include <QSplitter>
#include <QStackedWidget>
#include <QToolBar>
#include <QToolButton>
#include <QUndoStack>
#include <QUndoView>

#include "EditorFactory.h"
#include "SimpleEditor.h"
#include "IconObject.h"
#include "IconClass.h"
#include "IconFactory.h"
#include "Language.h"
//#include "Log.h"
//#include "PageView.h"
//#include "Dropping.h"
//#include "EditorButton.h"
#include "Folder.h"

#include "MvQPageView.h"

vector<PaperSize*> PaperSizeHandler::std_;


//==============================================
//
// ViewEditor
//
//==============================================


ViewEditor::ViewEditor(const IconClass& name,const string& kind):
	MvQEditor(name,kind)
{  
	paper_=new PaperSizeHandler;
        snap_=new GridSnapHandler;
		
	undoStack_=new QUndoStack(this);
	
	//-----------------------
	// Toolbar
	//-----------------------
	
	QList<QToolButton*> tbLst;
	
	//redo
	QAction *redoAc = undoStack_->createRedoAction(this, tr("&Redo"));
    	redoAc->setShortcuts(QKeySequence::Redo);     
     	redoAc->setIcon(QPixmap(":/desktop/redo.svg"));     	
	
	//undo
	QAction *undoAc = undoStack_->createUndoAction(this, tr("&Undo"));
    	undoAc->setShortcuts(QKeySequence::Undo);     
     	undoAc->setIcon(QPixmap(":/desktop/undo.svg"));     	

	//Duplicate
	QAction *duplicateAc=new QAction(this);
	duplicateAc->setToolTip(tr("Duplicate selected frames"));
	duplicateAc->setIcon(QPixmap(":/desktop/duplicate.svg")); 
	
	connect(duplicateAc,SIGNAL(triggered(bool)),
		this,SLOT(slotDuplicateSelection(bool)));
		
	//page setup
	QAction *pageAc=new QAction(this);
	pageAc->setToolTip(tr("Page setup"));
	pageAc->setIcon(QPixmap(":/desktop/page_setup.svg")); 

	connect(pageAc,SIGNAL(triggered(bool)),
		this,SLOT(slotSetupPage(bool)));
			
	snapAc_=new QAction(this);
	snapAc_->setToolTip(tr("Snap to grid"));
	snapAc_->setCheckable(true);
	snapAc_->setChecked(true);
	snapAc_->setIcon(QPixmap(":/desktop/snap_to_grid.svg"));     
	
	connect(snapAc_,SIGNAL(toggled(bool)),
		this,SLOT(slotSnap(bool)));	
		
	gridAc_=new  QAction(this);
	gridAc_->setToolTip(tr("View grid"));
	gridAc_->setCheckable(true);
	gridAc_->setChecked(true);	
	gridAc_->setIcon(QPixmap(":/desktop/view_grid.svg"));
	
	connect(gridAc_,SIGNAL(toggled(bool)),
		this,SLOT(slotGrid(bool)));		

	QAction *selectAllAc=new QAction(this);
	selectAllAc->setToolTip(tr("Select all frames"));
	selectAllAc->setIcon(QPixmap(":/desktop/page_select_all.svg"));	
		
	connect(selectAllAc,SIGNAL(triggered(bool)),
		this,SLOT(slotSelectAll(bool)));	
		
	QAction *sep=new QAction(this);	
	sep->setSeparator(true);
	
	QAction *sep1=new QAction(this);	
	sep1->setSeparator(true);	
	
	QList<QAction*> acLst;
	acLst << pageAc << sep << undoAc  << redoAc << duplicateAc << selectAllAc << sep1 << snapAc_ << gridAc_ ;	
	addToToolBar(acLst);
		
	//--------------------------------------
	// Define view layout in the middle
	//--------------------------------------	
				
	QHBoxLayout *viewLayout=new QHBoxLayout();
	centralLayout_->addLayout(viewLayout);	
	
	//-----------------------
	// Sidebar on the right	
	//-----------------------
	
	//Sidebar on the right	
	QVBoxLayout* rightVb=new QVBoxLayout;
	rightVb->setSpacing(0); 
	rightVb->setContentsMargins(1,1,1,1);	
	viewLayout->addLayout(rightVb);
	
	QToolBar* sidebar_=new QToolBar(this);
	sidebar_->setIconSize(QSize(24,24));
	sidebar_->setOrientation(Qt::Vertical);
	rightVb->addWidget(sidebar_);	
	
	QAction *addAc=new QAction(this);
	addAc->setToolTip(tr("Add new frame"));
	addAc->setIcon(QPixmap(":/desktop/page_add.svg"));
	
	QAction *joinAc=new QAction(this);
	joinAc->setToolTip(tr("Join selected frames"));
	joinAc->setIcon(QPixmap(":/desktop/page_join.svg"));
	
	QAction *splitAc=new QAction(this);
	splitAc->setToolTip(tr("Split selected frames"));
	splitAc->setIcon(QPixmap(":/desktop/page_split.svg"));
	
	QAction *deleteAc=new QAction(this);
	deleteAc->setToolTip(tr("Delete selected frames"));
	deleteAc->setIcon(QPixmap(":/desktop/page_delete.svg"));
	
	QAction *expandAc=new QAction(this);
	expandAc->setToolTip(tr("Expand selected frames"));
	expandAc->setIcon(QPixmap(":/desktop/page_expand.svg"));
	
	QAction *connectAc=new QAction(this);
	connectAc->setToolTip(tr("Connect selected frames - NOT YET SUPPORTED"));	
	connectAc->setIcon(QPixmap(":/desktop/page_connect.svg"));
	connectAc->setEnabled(false);
		
	QAction *disconnectAc=new QAction(this);
	disconnectAc->setToolTip(tr("Disonnect selected frames"));
	disconnectAc->setIcon(QPixmap(":/desktop/page_disconnect.svg"));
		
	connect(addAc,SIGNAL(triggered(bool)),
		this,SLOT(slotAddPage(bool)));
		
	connect(joinAc,SIGNAL(triggered(bool)),
		this,SLOT(slotJoinSelection(bool)));
		
	connect(deleteAc,SIGNAL(triggered(bool)),
		this,SLOT(slotDeleteSelection(bool)));
	
	connect(splitAc,SIGNAL(triggered(bool)),
		this,SLOT(slotSplitSelection(bool)));
		
	connect(expandAc,SIGNAL(triggered(bool)),
		this,SLOT(slotExpandSelection(bool)));
				
	//connect(connectAc,SIGNAL(triggered(bool)),
		//this,SLOT(slotConnectSelection(bool)));
		
	connect(disconnectAc,SIGNAL(triggered(bool)),
		this,SLOT(slotDisconnectSelection(bool)));
		
	connect(selectAllAc,SIGNAL(triggered(bool)),
		this,SLOT(slotSelectAll(bool)));		
	
	sidebar_->addAction(addAc);
	sidebar_->addAction(deleteAc);
	sidebar_->addAction(joinAc);
	sidebar_->addAction(splitAc);
	sidebar_->addAction(expandAc);
	sidebar_->addSeparator();
	sidebar_->addAction(connectAc);
	sidebar_->addAction(disconnectAc);
			
	//--------------------
	// View
	//--------------------
	
	Language& lang=IconClass::find("PLOT_PAGE").language();
	Request interface=lang.interfaceRequest("VIEW");
	const vector<string>& classes=interface.get("class");
	
	view_=new MvQPageView(classes,undoStack_,this);
	viewLayout->addWidget(view_,1);
	
	connect(view_,SIGNAL(changed()),
		this,SLOT(slotViewChanged()));
		
	connect(view_,SIGNAL(selectionChanged(int)),
		this,SLOT(updateButtonStatus(int)));
		
	updateButtonStatus(0);

}

ViewEditor::~ViewEditor()
{
}

void ViewEditor::apply()
{
	savePaperSize(request_);
	savePages(current_,request_);
	current_->request(request_);
}

void ViewEditor::reset()
{
	//cache_.clear();
	//save_.clear();
	request_ = current_->request();
	request_.print();
	
	view_->clear();
	loadPaperSize(request_);
	loadPages(current_,request_);
	
	//PaperSetPages(paper_,loadPages(current_,request_));
	//updateDrawers();
	//PaperSelectFirst(paper_);
}

void ViewEditor::close()
{
	view_->clear();
	//save_.clear();
}

void ViewEditor::merge(IconObjectH /*o*/)
{
}

void ViewEditor::replace(IconObjectH /*o*/)
{
}



void ViewEditor::loadPaperSize(const Request& r)
{	
  	paper_->set(r);
  
	double w=paper_->width();
	double h=paper_->height();
	
	setPaperSize(h,w);

	cout << "h = " << h << " w = " << w << endl;
	
/*	
  cout << "paperSize " << endl;
	r.print();

	// Set paper size...
	double w = r("CUSTOM_HEIGHT");
	double h = r("CUSTOM_WIDTH");

	const char* size  = r("LAYOUT_SIZE");
	const char* orien = r("LAYOUT_ORIENTATION");

	if(size && orien)
	{  	
		for(int i = 0; i < static_cast<int>(paperSizes_.size()) ; i++)
		{
			if(paperSizes_[i].name() == string(size))
			{
				if(strcmp(orien,"PORTRAIT") == 0)
				{
					h = paperSizes_[i].height();
					w = paperSizes_[i].width();
					break;
				}
				else
				{
					w = paperSizes_[i].height();
					h = paperSizes_[i].width();
					break;
				}	
			}
		}	
	}

	paperSizeReq_("LAYOUT_SIZE")=size;
	paperSizeReq_("LAYOUT_SIZE")=orien;
	paperSizeReq_("CUSTOM_HEIGHT")=h;
	paperSizeReq_("CUSTOM_WIDTH")=w;
	
	setPaperSize(h,w);

	cout << "h = " << h << " w = " << w << endl;
	*/
}

void ViewEditor::savePaperSize(Request& r)
{
	paper_->save(r);
}

#if 0
PageView* ViewEditor::pageView(IconObject* o)
{
	map<IconObjectH,PageViewH>::iterator j = cache_.find(o);
	if(j == cache_.end())
		cache_[o] = new PageView(o);
	return cache_[o];
}
#endif

void ViewEditor::loadPages(IconObject* o,const Request& r)
{	
	//Clear the view
    
  	vector<IconObjectH> sub = o->subObjects("PAGES", r );

	for(vector<IconObjectH>::iterator itPage = sub.begin(); itPage != sub.end(); ++itPage)
	{
	    	MvRequest pageReq = (*itPage)->request();
	    
	    	pageReq.print();
	    
		double top    = pageReq("TOP");
		double left   = pageReq("LEFT");
		double right  = pageReq("RIGHT");
		double bottom = pageReq("BOTTOM");
		MvQPageItem *pageItem=view_->addPage(left,top,right-left,bottom-top); 
	
	    	vector<IconObjectH> viewVec = (*itPage)->subObjects("VIEW",pageReq);
	    
	    	IconObject* viewObj = viewVec.size() ? static_cast<IconObject*>(viewVec[0]) : defaultView();
	    	pageItem->setViewIcon(viewObj);
		
		loadSubPages(pageItem,*itPage,pageReq);
	  }
}

void ViewEditor::loadSubPages(MvQPageItem* p,IconObject* o,const Request& r)
{
	// Old style

	/*int rows = r("ROWS");
	int cols = r("COLUMNS");

	if(rows * cols > 1)
	{
		double height = 1.0 / rows;pageItem
		double width  = 1.0 / cols;
		double x = 0;

		for(int i = 0; i < cols; i++) 
		{
			double y = 0;
			for(int j = 0; j < rows; j++)
			{
				PaperRectangle* s = PaperNewPage(
					paper_,
					y, 
					x, 
					(j == rows - 1) ? 1.0 : y + height, 
					(i == cols - 1) ? 1.0 : x + width
					);

				s->next = pages;
				pages = s;
				y += height;
			}
			x +=  width;
		}
	}*/

	// New Style
	vector<IconObjectH> sub = o->subObjects("SUB_PAGES", r );
	for(vector<IconObjectH>::iterator ii = sub.begin(); ii != sub.end(); ++ii)
	{
	    	MvRequest subR = (*ii)->request();
		
		subR.print();
		
		double top    = subR("TOP");
		double left   = subR("LEFT");
		double right  = subR("RIGHT");
		double bottom = subR("BOTTOM");
		
		p->addSubPaperRectInPageCoords(left,top,right-left,bottom-top);		
	}
}


void ViewEditor::savePages(IconObject* o,Request& r)
{
	r.print();
	
  	FolderH pageFolder = o->embeddedFolder("Pages",true);

	// Clean up old stuff
	pageFolder->destroy();
	pageFolder = o->embeddedFolder("Pages",true);

	vector<IconObjectH> pages;

	foreach(MvQPageItem* p,view_->pages()) 
	{
		Request pageReq("PLOT_PAGE"); 
		
		saveRectToRequest(p->paperRect(),pageReq);
		
		pageReq.print();
		
		IconObjectH page      = IconFactory::create(pageFolder,pageReq,0,0);
		FolderH subPageFolder = page->embeddedFolder("Sub Pages",true);
		pages.push_back(page);
		
		vector<IconObjectH> subpages;
		
		foreach(QRectF subRect,p->subPaperRects())
		{
		  	Request subReq("PLOT_SUBPAGE");
			saveRectToRequest(subRect,subReq);
			subReq.print();
			subpages.push_back(IconFactory::create(subPageFolder,subReq,0,0));
		}
		
		page->setSubObjects("SUB_PAGES",subpages,pageReq);
		
		IconObjectH view = p->viewIcon();
		if(view) 
		     	page->setSubObjects("VIEW",vector<IconObjectH>(1,view),pageReq);	
		
		page->request(pageReq);
	}
	
	r.print();
	
	current_->setSubObjects("PAGES",pages,r);
	current_->request(r);
}	
		
void ViewEditor::saveRectToRequest(QRectF rect,Request& r)
{
	double top=rect.y();
	double left=rect.x() ;
	double bottom=rect.bottomLeft().y(); 
	double right=rect.topRight().x() ;	
	
  	r("TOP")    = top ;
	r("LEFT")   = left ;
	r("BOTTOM") = bottom; 
	r("RIGHT")  = right ;
}
	
IconObject *ViewEditor::defaultView()
{
	return IconClass::find("GEOVIEW").defaultObject();
}

//-----------------------------------------------------------

void ViewEditor::updateButtonStatus(int /*selected*/)
{
 	return;
	
	/*if(selected ==0)
	{
	  	joinAc->setEnabled(false);
		splitAc->setEnabled(false);
  		deleteAc->setEnabled(false);
		expandAc->setEnabled(false);
	}
	
	else
	{
		splitAc->setEnabled(true);
  		deleteAc->setEnabled(true);
		expandAc->setEnabled(true);
		
		if(selected > 1)
		  	joinAc->setEnabled(true);
		else
		  	joinAc->setEnabled(false);
	}*/		
}	


void ViewEditor::setPaperSize(double height,double width)
{
	view_->setSuperPage(width,height,snapAc_->isChecked(),snap_->x(),snap_->y(),gridAc_->isChecked());
}

string ViewEditor::alternateEditor()
{
	return "SimpleEditor";
}

void ViewEditor::slotSnap(bool on)
{
	view_->enableSnap(on);
}

void ViewEditor::slotGrid(bool on)
{
  	view_->enableGrid(on);
}	

void ViewEditor::slotAddPage(bool)
{
	MvQPageItem *pageItem=view_->addPage(0,0,25,25); 
	pageItem->setViewIcon(defaultView());
	changed();
}

void ViewEditor::slotDuplicateSelection(bool)
{
	view_->duplicateSelection(); 
	changed();
}

void ViewEditor::slotDeleteSelection(bool)
{
	view_->deleteSelection(); 
	changed();
}

void ViewEditor::slotJoinSelection(bool)
{
	view_->joinSelection(); 
	changed();
}

void ViewEditor::slotSplitSelection(bool)
{
	MvQSplitDialog dialog(this);
	if(dialog.exec() == QDialog::Accepted)
	{
	  	view_->splitSelection(dialog.row()+1,dialog.column()+1);
		changed();
	}	
}	

void ViewEditor::slotExpandSelection(bool)
{
	view_->expandSelection(); 
	changed();
}

void ViewEditor::slotSelectAll(bool)
{
	view_->selectAll(); 
	changed();
}	

void ViewEditor::slotConnectSelection(bool)
{
	view_->connectSelection(); 
	changed();
}		

void ViewEditor::slotDisconnectSelection(bool)
{
	view_->disconnectSelection(); 
	changed();
}		

void ViewEditor::slotSetupPage(bool)
{
	MvQPageSetupDialog dialog(paper_,snap_,this);
	if(dialog.exec()  == QDialog::Accepted)
	{
		setPaperSize(paper_->height(),paper_->width());
		view_->setSnap(snap_->x(),snap_->y());
		changed();  
	}		
}

void ViewEditor::slotViewChanged()
{
  	changed();
}	
void ViewEditor::readSettings(QSettings& settings)
{  
  	settings.beginGroup("layout_editor");
	
	QVariant v=settings.value("grid");
	if(!v.isNull()) gridAc_->setChecked(v.toBool());
	
	v=settings.value("grid_x");
	QVariant v1=settings.value("grid_y");
	
	if(!v.isNull() && !v1.isNull()) 
	{
	  	snap_->setCurrentValues(v.toFloat(),v1.toFloat());
		view_->setSnap(snap_->x(),snap_->y());
	}
	
	v=settings.value("snap");
	if(!v.isNull()) snapAc_->setChecked(v.toBool());
	
	settings.endGroup();
}
	
void ViewEditor::writeSettings(QSettings& settings)
{	  
  	settings.beginGroup("layout_editor");
	
	settings.setValue("grid",gridAc_->isChecked());
	settings.setValue("grid_x",snap_->x());
	settings.setValue("grid_y",snap_->y());
	settings.setValue("snap",snapAc_->isChecked());
	
	settings.endGroup();
}  
		
//==================================================================================
//==================================================================================


//==============================================
//
// PaperSizeHandler
//
//==============================================

PaperSizeHandler::PaperSizeHandler() :
   orientation_("Landscape"),
   current_(0)
{
	if(std_.size() == 0)
	{
	  	std_.push_back(new PaperSize("A4",21,29.7,"PORTRAIT"));
		std_.push_back(new PaperSize("A4",29.7,21,"LANDSCAPE"));
		std_.push_back(new PaperSize("A3",29.7,42,"PORTRAIT"));
		std_.push_back(new PaperSize("A3",42,29.7,"LANDSCAPE"));
	}
   
        custom_=new PaperSize("CUSTOM",29.7,21,"");
   
        current_=std_[0];
}


void PaperSizeHandler::set(const Request& r)
{
	double h = r("CUSTOM_HEIGHT");
	double w = r("CUSTOM_WIDTH");

	const char* size  = r("LAYOUT_SIZE");
	const char* orien = r("LAYOUT_ORIENTATION");

	string sizeStr="A4";
	if(size) sizeStr=string(size);

	orientation_="LANDSCAPE";
	if(orien) orientation_=string(orien);
			
	bool found=false;
	for(int i = 0; i < static_cast<int>(std_.size()) ; i++)
	{
		if(std_.at(i)->name() == sizeStr && std_.at(i)->orientation() == orientation_)
		{
			current_=std_[i];
			found=true;
			break;
		}
	}
	
	if(!found)
	{
	  	custom_->setWidth(w);
		custom_->setHeight(h);
		current_=custom_;
	}		
}

void PaperSizeHandler::set(const string& sizeStr,const string& orien,double w, double h)
{
	orientation_=orien;

	bool found=false;
	for(int i = 0; i < static_cast<int>(std_.size()) ; i++)
	{
		if(std_.at(i)->name() == sizeStr && std_.at(i)->orientation() == orien)
		{
			current_=std_[i];
			found=true;
			break;
		}
	}
	
	if(!found)
	{
	  	custom_->setWidth(w);
		custom_->setHeight(h);
		current_=custom_;
	}		
}

void PaperSizeHandler::save(Request& r)
{
	r("LAYOUT_SIZE")= current_->name().c_str();
	r("CUSTOM_WIDTH")  = current_->width();
	r("CUSTOM_HEIGHT") = current_->height();
  	
  	if(current_ != custom_)
	{
		r("LAYOUT_ORIENTATION") = current_->orientation().c_str();
		r.unsetParam("CUSTOM_WIDTH");
		r.unsetParam("CUSTOM_HEIGHT");	
	}
	else
	{
		r.unsetParam("LAYOUT_ORIENTATION");	  	  
	}  
}


double PaperSizeHandler::width()
{
	return (current_)?current_->width():0;
}

double PaperSizeHandler::height()
{
 	return (current_)?current_->height():0;
}	

//================================================
// 
//  GridSnapHandler
//
//================================================

GridSnapHandler::GridSnapHandler()
{
  	units_= "%";
  	
	float v []={1,2,4,5,10,12,5,20,25,50}; 	
	vals_.assign(v,v+sizeof(v)/sizeof(v[0]));

	//vals_ << 1 << 2 << 4 << 5 << 10 << 12.5 << 20 << 25 << 50; 
	xIndex_=3;
	yIndex_=3;
}

void GridSnapHandler::setCurrent(int xi,int yi)
{
	if(xi>=0 && xi < static_cast<int>(vals_.size()))
	{
		xIndex_=xi;
	}
	if(yi>=0 && yi < static_cast<int>(vals_.size()))
	{
		yIndex_=yi;
	} 
}  

void GridSnapHandler::setCurrentValues(float x,float y)
{
	for(unsigned int i=0; i < vals_.size(); i++)
	{
	  	if(x == vals_[i])  xIndex_=i;
		if(y == vals_[i]) yIndex_=i;
	}	
}  

float GridSnapHandler::x() const 
{
  	return vals_[xIndex_];
}	  
	  
float GridSnapHandler::y() const 
{
  	return vals_[yIndex_];
}	  
	  
//================================================
// 
//  MvQPaperSizeWidget
//
//================================================


MvQPaperSizeWidget::MvQPaperSizeWidget(PaperSizeHandler *paper,QWidget *parent) : 
    QWidget(parent),
    paper_(paper)
    
{ 	
	QGridLayout* grid=new QGridLayout;
	setLayout(grid);
	
	QLabel *label;
	
	int row=0;
	
	//Size
	label=new QLabel(tr("&Size:"));
	sizeCb_=new QComboBox;
	label->setBuddy(sizeCb_);
	
	std::set<std::string> nameSet;
	for(vector<PaperSize*>::const_iterator it=paper_->stdSizes().begin(); it != paper_->stdSizes().end(); it++)
	{
	  	//We do not allow duplicated names
	  	if(nameSet.find((*it)->name()) == nameSet.end())
		{  
	  		sizeCb_->addItem(QString::fromStdString((*it)->name()));
			sizeCb_->setItemData(sizeCb_->count()-1,QString::fromStdString((*it)->name()));
			nameSet.insert((*it)->name());
		}	
	}
	
	sizeCb_->addItem(tr("Custom"));
	sizeCb_->setItemData(sizeCb_->count()-1,"CUSTOM");
	
	grid->addWidget(label,row,0);
	grid->addWidget(sizeCb_,row,1);
	row++;
	
	//orientation
	oriLabel_=new QLabel(tr("&Orientation:"));
	oriCb_=new QComboBox;
	oriLabel_->setBuddy(oriCb_);
	
	oriCb_->addItem(tr("Portrait"));
	oriCb_->setItemData(0,"PORTRAIT");
	
	oriCb_->addItem(tr("Landscape"));
	oriCb_->setItemData(1,"LANDSCAPE");
	
	grid->addWidget(oriLabel_,row,0);
	grid->addWidget(oriCb_,row,1);
	row++;
	
	//width
	widthLabel_=new QLabel(tr("&Width:"));
	widthEdit_=new QLineEdit;
	widthLabel_->setBuddy(widthEdit_);
	
	grid->addWidget(widthLabel_,row,0);
	grid->addWidget(widthEdit_,row,1);
	row++;
	
	//height
	heightLabel_=new QLabel(tr("&Height:"));
	heightEdit_=new QLineEdit;
	heightLabel_->setBuddy(heightEdit_);
	
	grid->addWidget(heightLabel_,row,0);
	grid->addWidget(heightEdit_,row,1);
	row++;
			
	//----------------------------------
	// Init
	//----------------------------------
	
	//Size
	if(paper_->isCustom())
	{
	  	sizeCb_->setCurrentIndex(sizeCb_->count()-1);
	}
	else
	{
		for(int i=0; i < sizeCb_->count(); i++)
		{
			if(sizeCb_->itemText(i).toStdString() == paper_->current()->name())
			{  
				sizeCb_->setCurrentIndex(i);
				break;
			}
		}	
	}
	
	//Orientation
	if(paper_->orientation() == "PORTRAIT")
		oriCb_->setCurrentIndex(0);
	else	  
		oriCb_->setCurrentIndex(1);
	
	//Width and height
	widthEdit_->setText(QString::number(paper_->width()));
	heightEdit_->setText(QString::number(paper_->height()));

	//State
	updateState();
	
	//Combo box signals
	connect(sizeCb_,SIGNAL(currentIndexChanged(int)),
		this,SLOT(slotSize(int)));

}  

void MvQPaperSizeWidget::updateState()
{
  	int  index=sizeCb_->currentIndex();
  	
  	//A4, A3, ... 
	if(sizeCb_->itemData(index).toString() != "CUSTOM")  
	{
	  	oriLabel_->setEnabled(true);
	  	oriCb_->setEnabled(true);
		widthLabel_->setEnabled(false);
		widthEdit_->setEnabled(false);
		heightLabel_->setEnabled(false);
		heightEdit_->setEnabled(false);
	}
	else
	{
		oriLabel_->setEnabled(false);
	  	oriCb_->setEnabled(false);
		widthLabel_->setEnabled(true);
		widthEdit_->setEnabled(true);
		heightLabel_->setEnabled(true);
		heightEdit_->setEnabled(true);	  
	}
}	

void MvQPaperSizeWidget::slotSize(int)
{
	updateState();	
}	

void MvQPaperSizeWidget::accept()
{
	int  sizeIndex=sizeCb_->currentIndex();
	int  oriIndex=oriCb_->currentIndex();
	
	if(sizeIndex>=0 && sizeIndex < sizeCb_->count() &&
	   oriIndex>=0 && oriIndex < oriCb_->count())
	{
		paper_->set(sizeCb_->itemData(sizeIndex).toString().toStdString(),
		            oriCb_->itemData(oriIndex).toString().toStdString(),
  		            widthEdit_->text().toDouble(),
		            heightEdit_->text().toDouble()); 	
	}
}	


//================================================
// 
//  MvQSnapWidget
//
//================================================

MvQGridSnapWidget::MvQGridSnapWidget(GridSnapHandler *snap,QWidget *parent) : 
    QWidget(parent),
    snap_(snap)
    
{ 	
	QGridLayout* grid=new QGridLayout;
	setLayout(grid);
	
	QLabel *label;
	
	int row=0;
	
	//x
	label=new QLabel(tr("&X grid step:"),this);
	xCb_=new QComboBox(this);
	label->setBuddy(xCb_);
	grid->addWidget(label,row,0);
	grid->addWidget(xCb_,row,1);
	row++;
	
	//y
	label=new QLabel(tr("&Y grid step:"),this);
	yCb_=new QComboBox(this);
	label->setBuddy(yCb_);
	grid->addWidget(label,row,0);
	grid->addWidget(yCb_,row,1);
	row++;
	
	grid->setColumnStretch(1,1);
	
	//----------------------------------
	// Init
	//----------------------------------
	
	for(unsigned int i=0; i < snap_->values().size(); i++)
	{
	  	xCb_->addItem(QString::number(snap_->values().at(i)) + " " + QString::fromStdString(snap_->units()));
		yCb_->addItem(QString::number(snap_->values().at(i)) + " " + QString::fromStdString(snap_->units()));
	}
	
	xCb_->setCurrentIndex((snap_->xIndex() != -1)?snap_->xIndex():3);	
	yCb_->setCurrentIndex((snap_->yIndex() != -1)?snap_->yIndex():3);
}  


void MvQGridSnapWidget::accept()
{
	int  xIndex=xCb_->currentIndex();
	int  yIndex=yCb_->currentIndex();
	
	if(xIndex>=0 && yIndex>=0)
	{
		snap_->setCurrent(xIndex,yIndex);
	}
}	

//================================================
// 
//  MvQSnapWidget
//
//================================================

MvQPageSetupDialog::MvQPageSetupDialog(PaperSizeHandler *paperH,GridSnapHandler *snapH,QWidget *parent) : 
    QDialog(parent)   
{
	setWindowTitle(tr("Page setup"));
  	
  	QVBoxLayout* vb=new QVBoxLayout;
	setLayout(vb);

	QTabWidget *tab=new QTabWidget(this);
	vb->addWidget(tab);
	
	paper_=new MvQPaperSizeWidget(paperH,this);
	tab->addTab(paper_,tr("Paper size"));
	
	snap_=new MvQGridSnapWidget(snapH,this);
	tab->addTab(snap_,tr("Grid"));
	
	// Buttonbox
	QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
                                      | QDialogButtonBox::Cancel);
 
	connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
     	connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
		
	//Try to find the optimal dialog width
	QFont font;
	QFontMetrics fm(font);
	//setMinimumWidth(fm.width(tr("Orientation:  landscape"))+100);
	
	vb->addWidget(buttonBox);
}  


void MvQPageSetupDialog::accept()
{
	paper_->accept();
	snap_->accept();

	QDialog::accept();
}	


//================================================
// 
//  MvQSplitDialog
//
//================================================

MvQSplitDialog::MvQSplitDialog(QWidget *parent) : 
    QDialog(parent),
    row_(0),
    column_(0),
    maxRow_(100),
    maxColumn_(100),
    maxGrRow_(10),
    maxGrColumn_(10)
{
	setWindowTitle(tr("Split"));
  	
  	QVBoxLayout* vb=new QVBoxLayout;
	setLayout(vb);

	//Mode selector
	QFrame *modeFrame=new QFrame(this);
	modeFrame->setFrameShape(QFrame::StyledPanel);
  
  	QHBoxLayout *hb=new QHBoxLayout(this);
	modeFrame->setLayout(hb);
	vb->addWidget(modeFrame);
	vb->addSpacing(4);
	
	QLabel *label=new QLabel(tr("Selection mode:"));
	modeCb_=new QComboBox(this);
	modeCb_->addItem(tr("Manual"));
	modeCb_->addItem(tr("Graphical"));
	hb->addWidget(label);
	hb->addWidget(modeCb_);
	hb->addStretch(1);
	
	stacked_=new QStackedWidget(this);
	vb->addWidget(stacked_);
	
	//---------------------------
	// Manual mode
	//---------------------------
	
	QWidget *w=new QWidget(this);
	QVBoxLayout *mLayout=new QVBoxLayout();
	w->setLayout(mLayout);
	QGridLayout *mgLayout=new QGridLayout();
	mLayout->addLayout(mgLayout);
	mLayout->addStretch(1);
	
	//rows
	label=new QLabel(tr("Number of rows:"),this);
	mgLayout->addWidget(label,0,0);
	rowSpin_=new QSpinBox(this);
	rowSpin_->setRange(1,maxRow_);
	mgLayout->addWidget(rowSpin_,0,1);
	
	//columns
	label=new QLabel(tr("Number of columns:"),this);
	mgLayout->addWidget(label,1,0);
	colSpin_=new QSpinBox(this);
	colSpin_->setRange(1,maxColumn_);
	mgLayout->addWidget(colSpin_,1,1);
	
	stacked_->addWidget(w);
	
	//---------------------------
	// Graphical mode
	//---------------------------
	
	w=new QWidget(this);
	QVBoxLayout* gLayout=new QVBoxLayout;
	w->setLayout(gLayout);
		
	label_=new QLabel(this);
	gLayout->addWidget(label_);
		
	selector_=new MvQGridSelector(row_,column_,maxGrRow_,maxGrColumn_,this);
				      
	gLayout->addWidget(selector_,1);
	
	stacked_->addWidget(w);

	//Initialise combo and stacked
	//The default is the graphical mode
	modeCb_->setCurrentIndex(1);
	stacked_->setCurrentIndex(1);
	updateLabel();	
	
	//Signals and slots
	
	//Connect the combobox and the stacked widget to change the mode
	connect(modeCb_,SIGNAL(currentIndexChanged(int)),
			this,SLOT(slotChangeMode(int)));
	
	connect(rowSpin_,SIGNAL(valueChanged(int)),
			this,SLOT(slotRowChanged(int)));
	
	connect(colSpin_,SIGNAL(valueChanged(int)),
			this,SLOT(slotColumnChanged(int)));
	
	connect(selector_,SIGNAL(changed(int,int)),
		this,SLOT(slotSelectionChanged(int,int)));
	
	// Buttonbox
	QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
                                      | QDialogButtonBox::Cancel);
 
	connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
	
	//Try to find the optimal dialog width
	QFont font;
	QFontMetrics fm(font);
	setMinimumWidth(fm.width(tr("Columns"))+100);
	
	vb->addWidget(buttonBox);
	
	//Read in the settings
	readSettings();
	
	//This will properly initialise everything
	slotChangeMode(modeCb_->currentIndex());
}

void MvQSplitDialog::closeEvent(QCloseEvent* event)
{
	reject();
	event->accept();
}

void MvQSplitDialog::accept()
{	
	writeSettings();
	QDialog::accept();
}	

void MvQSplitDialog::reject()
{	
	writeSettings();
	QDialog::reject();
}	

void MvQSplitDialog::slotChangeMode(int mode)
{
	if(mode==0)
	{
		rowSpin_->setValue(row_+1);
		colSpin_->setValue(column_+1);
	}
	else if(mode==1)
	{
		selector_->setSelection(row_,column_);
		updateLabel();		
	}
	else
		return;
	
	stacked_->setCurrentIndex(mode);
	
}	

void MvQSplitDialog::slotRowChanged(int row)
{
	row_=row-1;	
}

void MvQSplitDialog::slotColumnChanged(int column)
{
	column_=column-1;
}

//From the grid selector
void MvQSplitDialog::slotSelectionChanged(int row,int column)
{
  	row_=row;
	column_=column;
	updateLabel();
}	

void MvQSplitDialog::updateLabel()
{
  	label_->setText(tr("Split selected frames: <b>") + QString::number(row_+1) + "x" +QString::number(column_+1) + "</b>");
}	

void MvQSplitDialog::writeSettings()
{
	QSettings settings("ECMWF","MV4-Desktop-SplitDialog");
	
	//We have to clear it so that should not remember all the previous values 
	settings.clear();
	
	settings.beginGroup("main");
	settings.setValue("size",size());
	settings.setValue("mode",modeCb_->currentIndex());
	settings.setValue("row",row_);
	settings.setValue("column",column_);
	settings.endGroup();
}

void MvQSplitDialog::readSettings()
{
	QSettings settings("ECMWF","MV4-Desktop-SplitDialog");
  	
	settings.beginGroup("main");
	if(settings.contains("size"))
	{  
		resize(settings.value("size").toSize());
	}
	else
	{
		resize(QSize(260,260));
	}
	
	if(settings.contains("row"))
	{  
		int r=settings.value("row").toInt();
		if(r > 0 && r < maxRow_)
			row_=r;
	}
	
	if(settings.contains("column"))
	{  
		int c=settings.value("column").toInt();
		if(c > 0 && c < maxColumn_)
			column_=c;
	}
	
	if(settings.contains("mode"))
	{  
		int m=settings.value("mode").toInt();
		if(m == 0 || m == 1)
		{
			modeCb_->setCurrentIndex(m);
		}
	}
	
	
	settings.endGroup(); 
}


//================================================
// 
//  MvQGridSelector
//
//================================================

MvQGridSelector::MvQGridSelector(int row, int column, int rowNum, int colNum, QWidget *parent) : 
    QWidget(parent),
    row_(row),
    column_(column),
    rowNum_(rowNum),
    columnNum_(colNum),
    offset_(1),
    dx_(5),
    dy_(5)
{
  	selectedColour_=QColor(151,193,219);
	rectColour_=QColor(210,210,210);
    frameColour_=rectColour_.darker(120);
	
	setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
	setMinimumSize(QSize(128,128));
	
	setMouseTracking(true);
    
}

void MvQGridSelector::setGridSize(int row, int col)
{
 	rowNum_=row;
	columnNum_=col;
	row_=0;
	column_=0;
	update();
}  

void MvQGridSelector::setSelection(int row, int col)
{
	row_=row;
	column_=col;
	
	if(row_ >= rowNum_)
	{
		row_=rowNum_-1;
	}
	
	if(column_ >= columnNum_)
	{
		column_=columnNum_-1;
	}
	
	emit changed(row_,column_);
	update();
}

void MvQGridSelector::resizeEvent(QResizeEvent */*event*/) 
{
	int w=width();
    int h=height(); 
	//gridSize_=(w<h)?w:h;
	//cellSize_=gridSize_/cellsPerRow_;	
	dx_=(w-2*offset_)/columnNum_;
	dy_=(h-2*offset_)/rowNum_;
}


void MvQGridSelector::paintEvent(QPaintEvent*)
{
  	QPainter painter(this);

	painter.setPen(Qt::black);
	
  	for(int i=0; i < rowNum_; i++)
	{
	  	for(int j=0; j < columnNum_; j++)
		{
			QColor col;
			if(i <= row_ && j <= column_)
				col=selectedColour_;
			else
			  	col=rectColour_;
		  
		  	painter.fillRect(QRectF(offset_+j*dx_,offset_+i*dy_,dx_,dy_),col);
			painter.drawRect(QRectF(offset_+j*dx_,offset_+i*dy_,dx_,dy_));
		}  
	}	
}  

bool MvQGridSelector::select(QPoint pos)
{
	int col=(pos.x()-offset_)/dx_;
	int row=(pos.y()-offset_)/dy_;
	
	if(row >=0 && row < rowNum_ && 
	   col >=0 && col < columnNum_ && 
	   (row != row_  || col != column_))
	{
	  	row_=row;
		column_=col;
		emit changed(row_,column_);
		return true;
	}
	
	return false;
}

void MvQGridSelector::mousePressEvent(QMouseEvent *event)
{	
	if(select(event->pos()))
	  	update(); 		 
}

void MvQGridSelector::mouseMoveEvent(QMouseEvent *event)
{ 
  	if(event->buttons() & Qt::LeftButton &&
	   select(event->pos()))
	  	update(); 	
}

void MvQGridSelector::mouseReleaseEvent(QMouseEvent* /*event*/)
{
}



static EditorMaker<ViewEditor> editorMaker("ViewEditor");



