/*************************************************************************
 * This file is part of Graphic des EDitor project
 *
 * Project created in conformity with the requirements for the Degree of
 * Master of Engineering in Software Engineering, Computing and Software
 * Department, McMaster University 2004 - 2008
 *
 * Author:	Xiao Ma
 * Supervisor: Dr. Ryan Leduc
*************************************************************************/

/*
 NAME
   GedDesWorkspace.cpp - Ged DES diagram information.
 FUNCTION
   The class tracks the graphic information of the DES in editor. i.e, the
   position, shape, color of states and transition function in DES diagram
   scene. The class keeps pointer of class Des and the pointer of diagram
   items of its component.  Note the class does not save any proerties of
   graphic items. These information is availe on the item classes.
 NOTES
 MODIFIED
   xma	    09/01/07 - CREATION. Inital version adopted from DESpot by Magdin Stoica
*/

#include <qevent.h>

#include "CommonDefinitions.h"
#include "GedDesWorkspace.h"
#include "GedDesEditor.h"
#include "MainForm.h"
#include "GedStateEditorUiPart.h"
#include "GedStateQuickLookUiPart.h"
#include "GedEventEditorUiPart.h"
#include "GedTransitionEditorUiPart.h"
#include "GedDesEditorOutputUiPart.h"
#include "Des.h"
#include "TransRecorder.h"
#include "ProgressWidget.h"
#include "GedDesScene.h"
#include "GedTextItem.h"
#include "DesProject.h" //for export all only
#include "ProjectEditor.h"
#include "DesSerializer.h"

// For static jpeg plugin support only
//#include<QtPlugin>
//Q_IMPORT_PLUGIN(qjpeg)

// for debug
// #include <iostream>

namespace DESpot
{

//These type is used to uncheck button when the item is inserted into the scene
//must be the same as defined in the item class
//For example, in GedDesTrans we define enum { Type = UserType + 4 };
const int InsertTextButton = QGraphicsItem::UserType + 3;
const int InsertEventButton = QGraphicsItem::UserType + 20;  //we don't use this anyway
const int InsertTransButton = QGraphicsItem::UserType + 4;

GedDesWorkspace::GedDesWorkspace(GedDesEditor* pGedDesEditor, Des* pDes) :
			Workspace(pGedDesEditor),myDes(pDes),newScale(1)
{
	//configure the form to use the GedDesEditor.ui
	setupUi(pGedDesEditor);

	// Create tabular editor UI parts
	m_pGedStateQuickLookUiPart = new GedStateQuickLookUiPart(this, pDes);
	m_pStateEdUiPart = new GedStateEditorUiPart(this, this, pDes,
		m_pGedStateQuickLookUiPart, pGedDesEditor->getTransRecorder());
	m_pEventEdUiPart = new GedEventEditorUiPart(this, this,
		pDes, pGedDesEditor->getTransRecorder());
	m_pTransEdUiPart = new GedTransitionEditorUiPart(this,pDes);
	m_pOutputUiPart	= new GedDesEditorOutputUiPart(this);

	//Initialize the transition recorder with the output ui
	//pGedDesEditor->getTransRecorder().initOutputUi(m_pOutputUiPart);

	//create menu, toolbar and status bar
	createActions();
	createMenus();
	setupStatusBar();
    createToolBox();

	//Create Graphic Scene
    scene = new  GedDesScene(this,stateContextMenu,transContextMenu,myDes);
    scene->setSceneRect(QRectF(0, 0, 640, 480));

    connect(scene, SIGNAL(stateInserted(GedDesState *)),
            this, SLOT(stateInserted(GedDesState *)));
    connect(scene, SIGNAL(transInserted(GedDesTrans *)),
            this, SLOT(transInserted(GedDesTrans *)));
    connect(scene, SIGNAL(textInserted(QGraphicsTextItem *)),
        this, SLOT(textInserted(QGraphicsTextItem *)));

	connect(editAction, SIGNAL(triggered()),
        scene, SLOT(editItem()));
    connect(deleteAction, SIGNAL(triggered()),
        scene, SLOT(deleteItem()));
	connect(restoreDefaultShapeAction, SIGNAL(triggered()),
        scene, SLOT(restoreTransShape()));

	createToolbars();

	// Create QGraphicView
	view = this->m_desGraphicView;

	// uncomment next line to allow rubberband selection for 
	// ged editor.
	view->setDragMode(QGraphicsView::RubberBandDrag);

    view->setScene(scene);

	// Layout widget manually
	createLayout();

	// Get the handlers of Widgets
	// We will do layout manually so need the handles of these Widgets
	m_pStateViewWidg = m_pStateEdUiPart->getStateViewerWidget();
	m_pStateQuickLookWidg = m_pGedStateQuickLookUiPart->getQuickLookForWidg();
	m_pEventViewWidg = m_pEventEdUiPart->getEventViewerWidget();
	m_pTransViewWidg = m_pTransEdUiPart->getTransViewWidg();
	m_pSelfTransViewWidg = m_pTransEdUiPart->getSelfTransViewWidg();

	//set the title of the window
	QString desName = QString::fromStdWString(pDes->getName());
	desEditor()->setWindowTitle(desName.isEmpty() ?
		STR_UNNAMED_DES : desName);

	//setup connections between widgets
	setupConnections();

	desEditor()->resize(1024,768);

	scene->open();

	// want to make sure scene is big enough for entire DES
	QRectF itemsSize = scene->itemsBoundingRect();
	qreal x1, y1, x2, y2;
	itemsSize.getCoords(&x1,&y1,&x2,&y2);
	
	// deafult size is (0,0) x (640,480).  Dont want to be smaller
	x1 = 0.0;
	y1 = 0.0;

	//  add some padding to the lower point.
	x2 = x2 + 100.0;
	y2 = y2 + 50.0;

	if (x2 < 640)
	  x2 = 640.0;

	if (y2 < 480)
	  y2 = 480.0;

	scene->setSceneRect(QRectF(x1,y1,x2,y2));

}


GedDesWorkspace::~GedDesWorkspace(void)
{
	if (m_pStateEdUiPart)
	{
		delete m_pStateEdUiPart;
		m_pStateEdUiPart = null;
	}

	if (m_pGedStateQuickLookUiPart)
	{
		delete m_pGedStateQuickLookUiPart;
		m_pGedStateQuickLookUiPart = null;
	}

	if (m_pEventEdUiPart)
	{
		delete m_pEventEdUiPart;
		m_pEventEdUiPart = null;
	}

	if (m_pTransEdUiPart)
	{
		delete m_pTransEdUiPart;
		m_pTransEdUiPart = null;
	}

	if (m_pOutputUiPart)
	{
		delete m_pOutputUiPart;
		m_pOutputUiPart = null;
	}
	if (scene)
	{
		delete scene;
		scene = null;
	}

}

void GedDesWorkspace::createLayout()
{
	//Move des viewer to right
	m_mainSplitterWidg->insertWidget(1,m_desSplitterWidg);

	//Toolbox in the left
	m_mainSplitterWidg->insertWidget(0,toolBox);

	//Size and position of state quick look
	//Hard to adjust layout in Qt designer so code it here
	stateQuickLookLayout = new QVBoxLayout;
	stateQuickLookLayout->addWidget(m_stateQuickLookWidg);
	stateQuickLookLayout->addStretch(1);
	m_stateQuickLookGroupBox->setLayout(stateQuickLookLayout);

	//Size and position of event editor
	//Hard to adjust layout in Qt designer so code it here
	QVBoxLayout *eventBoxLayout = new QVBoxLayout;
	eventBoxLayout->addWidget(m_eventViewWidg);
	eventBoxLayout->addStretch(1);
	m_eventGroupBox->setLayout(eventBoxLayout);

	//Size and position of output
	outputLayout = new QVBoxLayout;
	outputLayout->addWidget(m_outputWidg);
	//outputLayout->addStretch(1);
	m_desEditorOutputGBox->setLayout(outputLayout);

	centralLayout = new QVBoxLayout;
	centralLayout->addWidget(m_mainSplitterWidg);
	centralLayout->addWidget(m_progressWidget);
	centralLayout->addStretch(1);
	centralWidget->setLayout(centralLayout);

	//set the spliter position
	positionSplitters();
}

void GedDesWorkspace::resize(QResizeEvent* /*event*/)
{
	//rezize the main layout to fit the editor content area
	QSize centralWidgSize = centralWidget->size();
	m_mainSplitterWidg->resize(centralWidgSize - QSize(20, 16));
	positionSplitters();

	// need to reset scene to new viewport size
	QRect rectView = view->geometry();
	int gx1,gy1,gx2,gy2;
	rectView.getCoords(&gx1,&gy1,&gx2,&gy2);

        // don't need next line anymore
	//	scene->setSceneRect((QRectF)rectView);

	// want to make sure scene is big enough for entire DES
	QRectF itemsSize = scene->itemsBoundingRect();
	qreal x1, y1, x2, y2;
	itemsSize.getCoords(&x1,&y1,&x2,&y2);
	
	// Dont want to be smaller than view size
	x1 = 0.0;
	y1 = 0.0;

	//  add some padding to the lower point.
	x2 = x2 + 100.0;
	y2 = y2 + 50.0;

	if (x2 < gx2)
	  x2 = gx2;

	if (y2 < gy2)
	  y2 = gy2;

	scene->setSceneRect(QRectF(x1,y1,x2,y2));

}


GedStateEditorUiPart& GedDesWorkspace::stateEditorUiPart()
{
	return *m_pStateEdUiPart;
}


GedStateQuickLookUiPart&	GedDesWorkspace::stateQuickLookUiPart()
{
	return *m_pGedStateQuickLookUiPart;
}


GedEventEditorUiPart& GedDesWorkspace::eventEditorUiPart()
{
	return *m_pEventEdUiPart;
}


GedTransitionEditorUiPart& GedDesWorkspace::transEditorUiPart()
{
	return *m_pTransEdUiPart;
}

GedDesEditorOutputUiPart&  GedDesWorkspace::outputUiPart()
{
	return *m_pOutputUiPart;
}


QAction* GedDesWorkspace::recordTransAct()
{
	return m_recordTransAct;
}


ProgressWidget* GedDesWorkspace::progressWidget()
{
	return m_progressWidget;
}


void GedDesWorkspace::onChangedCurrentState(
    const DesState* pNewCurrentState, const DesState* pOldCurrentState)
{
	if (pNewCurrentState)
	{
		//a current state was established so configure the actions related with the current state
		m_changeStateAct->setEnabled(true);
		if (pOldCurrentState == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_stateViewWidg, SIGNAL(itemActivated(QTreeWidgetItem*, int)), desEditor(), SLOT(onChangeState()));
		}

		m_deleteStateAct->setEnabled(true);
		if (pOldCurrentState == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_stateViewWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteState()));
		}

		m_toggleInitialStateAct->setEnabled(true);
		m_toggleInitialStateAct->setChecked(pNewCurrentState->isInit());

		m_toggleMarkedStateAct->setEnabled(true);
		m_toggleMarkedStateAct->setChecked(pNewCurrentState->isMarked());
	}
	else
	{
		//the current state doesn't exist so disable any actions related to it
		m_changeStateAct->setEnabled(false);
		disconnect(m_stateViewWidg, SIGNAL(itemActivated(QTreeWidgetItem*, int)), desEditor(), SLOT(onChangeState()));

		m_deleteStateAct->setEnabled(false);
		disconnect(m_stateViewWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteState()));

		m_toggleInitialStateAct->setEnabled(false);
		m_toggleInitialStateAct->setChecked(false);

		m_toggleMarkedStateAct->setEnabled(false);
		m_toggleMarkedStateAct->setChecked(false);
	}
}


void GedDesWorkspace::updateCurrentStateUi(const DesState& crtState)
{
	m_toggleInitialStateAct->setChecked(crtState.isInit());
	m_toggleMarkedStateAct->setChecked(crtState.isMarked());
}


void GedDesWorkspace::onChangedCurrentEvent(const DesEvent* pNewCurrentEvent, const DesEvent* pOldCurrentEvent)
{
	if (pNewCurrentEvent)
	{
		//a current event was established so configure the actions related with the current event
		m_changeEventAct->setEnabled(true);
		if (pOldCurrentEvent == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_eventViewWidg, SIGNAL(itemActivated(QTreeWidgetItem*, int)), desEditor(), SLOT(onChangeEvent()));
		}

		m_deleteEventAct->setEnabled(true);
		if (pOldCurrentEvent == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_eventViewWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteEvent()));
		}

		m_toggleEventCtrlAct->setEnabled(true);
		m_toggleEventCtrlAct->setChecked(pNewCurrentEvent->isControllable());

		m_eventTypeSubMenu->menuAction()->setEnabled(true);
		m_pEventEdUiPart->getEventTypeContextSubMenu().menuAction()->setEnabled(true);
		getActionForEventType(pNewCurrentEvent->getType())->setChecked(true);
	}
	else
	{
		//the current event doesn't exist so disable any actions related to it
		m_changeEventAct->setEnabled(false);
		disconnect(m_eventViewWidg, SIGNAL(itemActivated(QTreeWidgetItem*, int)), desEditor(), SLOT(onChangeEvent()));

		m_deleteEventAct->setEnabled(false);
		disconnect(m_eventViewWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteEvent()));

		m_toggleEventCtrlAct->setEnabled(false);
		m_toggleEventCtrlAct->setChecked(false);

		m_eventTypeSubMenu->menuAction()->setEnabled(false);
		m_pEventEdUiPart->getEventTypeContextSubMenu().menuAction()->setEnabled(false);
	}
}


void GedDesWorkspace::updateCurrentEventUi(const DesEvent& crtEvent)
{
	assert(m_toggleEventCtrlAct->isEnabled());
	m_toggleEventCtrlAct->setChecked(crtEvent.isControllable());

	assert(m_eventTypeSubMenu->menuAction()->isEnabled());
	assert(m_pEventEdUiPart->getEventTypeContextSubMenu().menuAction()->isEnabled());
	getActionForEventType(crtEvent.getType())->setChecked(true);

}



void GedDesWorkspace::onChangedCurrentTrans(const DesTransition* pNewCurrentTrans, const DesTransition* pOldCurrentTrans)
{
	if (pNewCurrentTrans)
	{
		//a current transition was established so configure the actions related with the current transition
		m_changeTransAct->setEnabled(true);
		if (pOldCurrentTrans == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_transitionViewWidg, SIGNAL(itemActivated(QTreeWidgetItem*, int)), desEditor(), SLOT(onChangeTransition()));
		}

		m_deleteTransAct->setEnabled(true);
		if (pOldCurrentTrans == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_transitionViewWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteTransition()));
		}
	}
	else
	{
		//the current transition doesn't exist so disable any actions related to it
		m_changeTransAct->setEnabled(false);
		disconnect(m_transitionViewWidg, SIGNAL(itemActivated(QTreeWidgetItem*, int)), desEditor(), SLOT(onChangeTransition()));

		m_deleteTransAct->setEnabled(false);
		disconnect(m_transitionViewWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteTransition()));
	}
}

//_________________________________________________________________________________________________

void GedDesWorkspace::updateCurrentTransUi(const DesTransition& /*crtTrans*/)
{
	//the current transition doesn't have any UI associated with it.
}

//_________________________________________________________________________________________________

void GedDesWorkspace::onChangedCurrentSelfTrans(const DesEvent* pNewCrtSelfTransEvent,
											 const DesEvent* pOldCrtSelfTransEvent)
{
	if (pNewCrtSelfTransEvent)
	{
		//a current transition was established so configure the actions related with the current transition
		m_deleteSelfTransAct->setEnabled(true);
		if (pOldCrtSelfTransEvent == null)
		{
			//the keyboard signal was disconnected so connect it back
			connect(m_selfTransWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteSelfTransition()));
		}
	}
	else
	{
		//the current transition doesn't exist so disable any actions related to it
		m_deleteSelfTransAct->setEnabled(false);
		disconnect(m_selfTransWidg, SIGNAL(onCurrentItemDeleted()), desEditor(), SLOT(onDeleteSelfTransition()));
	}
}

//_________________________________________________________________________________________________

GedDesEditor* GedDesWorkspace::desEditor()
{
	return dynamic_cast<GedDesEditor*>(form());
}

//_________________________________________________________________________________________________

void GedDesWorkspace::setupConnections()
{
	connect(m_pTransEdUiPart, SIGNAL(onChangedCurrentTrans(const DesTransition*, const DesTransition*)),
		    this, SLOT(onChangedCurrentTrans(const DesTransition*, const DesTransition*))) ;

	connect(m_pTransEdUiPart, SIGNAL(onChangedActiveTrans(const DesTransition*, const DesTransition*)),
		    this, SLOT(onChangedCurrentTrans(const DesTransition*, const DesTransition*))) ;

	connect(m_pTransEdUiPart, SIGNAL(onCurrentTransChanged(const DesTransition&)),
		    this, SLOT(updateCurrentTransUi(const DesTransition&))) ;

	connect(m_pTransEdUiPart, SIGNAL(onChangedCurrentSelfTrans(const DesEvent*, const DesEvent*)),
		    this, SLOT(onChangedCurrentSelfTrans(const DesEvent*, const DesEvent*))) ;

	connect(m_pTransEdUiPart, SIGNAL(onChangedActiveSelfTrans(const DesEvent*, const DesEvent*)),
		    this, SLOT(onChangedCurrentSelfTrans(const DesEvent*, const DesEvent*))) ;


}

//_________________________________________________________________________________________________

// Rewite the original size policy function to support diagram scene
// 1) Main splitter
void GedDesWorkspace::positionSplitters()
{

	// 64% area -> scene
	// 20% area -> tabular
	// 6% toolbox
	const float cTabAreaHRatio = 0.06f;
	const float cToolAreaHRatio = 0.2f;

	QSize mainSplitterSize = m_mainSplitterWidg->size();
        int tabAreaWidth = (int)(mainSplitterSize.width() * cTabAreaHRatio);
        int toolAreaWidth = (int)(mainSplitterSize.width() * cToolAreaHRatio);
        int sceneAreaWidth = (int)(mainSplitterSize.width() - toolAreaWidth - tabAreaWidth);

	//arrange the main splitter to have the above sizes
	QList<int> mainSplitterSizeList;
	mainSplitterSizeList.push_back(tabAreaWidth);
	mainSplitterSizeList.push_back(sceneAreaWidth);
    mainSplitterSizeList.push_back(toolAreaWidth);
	m_mainSplitterWidg->setSizes(mainSplitterSizeList);

	//Tabular des area size 20, 20, 40, 20
	const float cStateVRatio = 0.2F;
	const float cEventVRatio = 0.2F;
	const float cTransVRatio = 0.4F;
	const float cQuickVRatio = 0.2F;
	QSize desSplitterSize  = m_desSplitterWidg->size();
        int   stateArea = (int)(desSplitterSize.height() * cStateVRatio);
        int   eventArea = (int)(desSplitterSize.height() * cEventVRatio);
        int   transitionArea = (int)(desSplitterSize.height() * cTransVRatio);
        int   quickViewArea = (int)(desSplitterSize.height() * cQuickVRatio);

	//arrange the des area spliter to have the above sizes
	QList<int> desSplitterSizeList;
	desSplitterSizeList.push_back(stateArea);
	desSplitterSizeList.push_back(eventArea);
	desSplitterSizeList.push_back(transitionArea);
	desSplitterSizeList.push_back(quickViewArea);
	m_desSplitterWidg->setSizes(desSplitterSizeList);

	//Regular transitions and self-transitions are shown 70% / 30%
	const float cTransRatio = 1.7f;
	QSize transSplitterSize = m_transSplitterWidg->size();
        int   transAreaHeight = (int)(transSplitterSize.height() / cTransRatio);
	int   selfTransAreaHeight = transSplitterSize.height() - transAreaHeight; //the rest of the splitter;

	//arange the state transition - self-trans splitter to have the above sizes
	QList<int> transSplitterSizeList;
	transSplitterSizeList.push_back(transAreaHeight);
	transSplitterSizeList.push_back(selfTransAreaHeight);
	m_transSplitterWidg->setSizes(transSplitterSizeList);

	//Scene 80%  output 20%
	const float cSceneRatio = 0.8f;
	QSize sceneSplitterSize = m_sceneSplitterWidg->size();
        int   sceneArea = (int)(sceneSplitterSize.height() * cSceneRatio);
	int   outputArea = sceneSplitterSize.height() - sceneArea; //the rest of the splitter;
	QList<int> sceneSplitterSizeList;
	sceneSplitterSizeList.push_back(sceneArea);
	sceneSplitterSizeList.push_back(outputArea);
	m_sceneSplitterWidg->setSizes(sceneSplitterSizeList);

	//Sizeing widget correctly
	m_stateQuickLookWidg->move(1,1);

}

QAction* GedDesWorkspace::getActionForEventType(EventType eventType)
{
	switch(eventType)
	{
        case eDefaultEvent:
			return m_setEventTypeDefaultAct;

        case eRequestEvent:
			return m_setEventTypeRequestAct;

        case eAnswerEvent:
			return m_setEventTypeAnswerAct;

        case eLDataEvent:
			return m_setEventTypeLDataAct;

		default:
			assert(false);
			throw EX("Unknown event type. Cannot return label.")
	}
}

//_________________________________________________________________________________________________

void GedDesWorkspace::createActions()
{
	m_newDesAct = new QAction(QIcon(":/resources/newRegularDes.png"), tr("New &DES..."), this);
	m_newDesAct->setShortcut(tr("Ctrl+D"));
	m_newDesAct->setToolTip(tr("New DES..."));
	m_newDesAct->setStatusTip(tr("Create a new DES with given name and type"));
	connect(m_newDesAct, SIGNAL(triggered()), mainForm(), SLOT(onNewDes()));
	//connect(m_newDesAct, SIGNAL(triggered()), desEditor(), SLOT(onNewDes()));

	m_openDesAct = new QAction(QIcon(":/resources/openDes.png"), tr("O&pen DES..."), this);
	m_openDesAct->setShortcut(tr("Ctrl+Alt+O"));
	m_openDesAct->setStatusTip(tr("Open existing DES"));
	connect(m_openDesAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenDes()));
	//connect(m_openDesAct, SIGNAL(triggered()), desEditor(), SLOT(onOpenDes()));

	m_saveDesAct = new QAction(QIcon(":/resources/saveDes.png"), tr("&Save"), this);
	m_saveDesAct->setShortcut(tr("Ctrl+S"));
	m_saveDesAct->setStatusTip(tr("Saves DES to a file."));
	connect(m_saveDesAct, SIGNAL(triggered()), desEditor(), SLOT(onSaveDes()));

	m_saveDesAsAct = new QAction(tr("Save &Duplicate..."), this);
	m_saveDesAsAct->setStatusTip(tr("Saves DES to a specified file."));
	connect(m_saveDesAsAct, SIGNAL(triggered()), desEditor(), SLOT(onSaveDesAs()));

	m_desSetNameAct = new QAction(tr("Set &Name..."), this);
	m_desSetNameAct->setStatusTip(tr("Sets the name of DES"));
	connect(m_desSetNameAct, SIGNAL(triggered()), desEditor(), SLOT(onDesSetName()));

	m_desSetTypeAct = new QAction(tr("Set &Type..."), this);
	m_desSetTypeAct->setStatusTip(tr("Sets the type of DES"));
	connect(m_desSetTypeAct, SIGNAL(triggered()), desEditor(), SLOT(onDesSetType()));

	m_printDesAct = new QAction(tr("&Print to file..."), this);
	m_printDesAct->setShortcut(tr("Ctrl+P"));
	m_printDesAct->setStatusTip(tr("Prints the contents of the DES to text file."));
	connect(m_printDesAct, SIGNAL(triggered()), desEditor(), SLOT(onPrintDes()));

	m_closeGedDesEditorAct = new QAction(tr("&Close"), this);
	m_closeGedDesEditorAct->setStatusTip(tr("Closes the DES editor"));
	connect(m_closeGedDesEditorAct, SIGNAL(triggered()), desEditor(), SLOT(onClose()));

	m_addStateAct = new QAction(QIcon(":/resources/addState.png"), tr("&Add State"), this);
	m_addStateAct->setShortcut(tr("Ctrl+A, Ctrl+S"));
	m_addStateAct->setStatusTip(tr("Adds a new state to DES"));
	connect(m_addStateAct, SIGNAL(triggered()), desEditor(), SLOT(onAddState()));

	m_changeStateAct = new QAction(QIcon(":/resources/renameState.png"), tr("&Change State"), this);
	m_changeStateAct->setStatusTip(tr("Change currently selected state in DES"));
	m_changeStateAct->setEnabled(false); //initially disabled until a current state is established
	connect(m_changeStateAct, SIGNAL(triggered()), desEditor(), SLOT(onChangeState()));

	m_deleteStateAct = new QAction(QIcon(":/resources/deleteState.png"), tr("&Delete State"), this);
	m_deleteStateAct->setStatusTip(tr("Deletes currently selected  from DES"));
	m_deleteStateAct->setEnabled(false); //initially disabled until a current state is established
	connect(m_deleteStateAct, SIGNAL(triggered()), desEditor(), SLOT(onDeleteState()));

	m_toggleInitialStateAct = new QAction(tr("&Initial State"), this);
	m_toggleInitialStateAct->setStatusTip(tr("Toggles the initial state status of the currently active state"));
	m_toggleInitialStateAct->setCheckable(true);
	m_toggleInitialStateAct->setEnabled(false); //initially disabled until a current state is established
	connect(m_toggleInitialStateAct, SIGNAL(triggered()), desEditor(), SLOT(onToggleInitialState()));

	m_toggleMarkedStateAct = new QAction(tr("&Marked State"), this);
	m_toggleMarkedStateAct->setStatusTip(tr("Toggles the initial marked status of the currently active state"));
	m_toggleMarkedStateAct->setCheckable(true);
	m_toggleMarkedStateAct->setEnabled(false); //initially disabled until a current state is established
	connect(m_toggleMarkedStateAct, SIGNAL(triggered()), desEditor(), SLOT(onToggleMarkedState()));

	m_markAllStatesAct = new QAction(tr("Mar&k All States"), this);
	m_markAllStatesAct->setStatusTip(tr("Makes all existing states marked states"));
	connect(m_markAllStatesAct, SIGNAL(triggered()), desEditor(), SLOT(onMarkAllStates()));

	m_unmarkAllStatesAct = new QAction(tr("&Unmark All States"), this);
	m_unmarkAllStatesAct->setStatusTip(tr("Makes all existing states unmarked states"));
	connect(m_unmarkAllStatesAct, SIGNAL(triggered()), desEditor(), SLOT(onUnmarkAllStates()));

	m_addEventAct = new QAction(QIcon(":/resources/addEvent.png"), tr("&Add Event"), this);
	m_addEventAct->setShortcut(tr("Ctrl+A, Ctrl+E"));
	m_addEventAct->setStatusTip(tr("Add new event to DES"));
	connect(m_addEventAct, SIGNAL(triggered()), desEditor(), SLOT(onAddEvent()));

	m_changeEventAct = new QAction(QIcon(":/resources/renameEvent.png"), tr("&Change Event"), this);
	m_changeEventAct->setStatusTip(tr("Edits the currently selected event in DES"));
	m_changeEventAct->setEnabled(false);
	connect(m_changeEventAct, SIGNAL(triggered()), desEditor(), SLOT(onChangeEvent()));

	m_deleteEventAct = new QAction(QIcon(":/resources/deleteEvent.png"), tr("&Delete Event"), this);
	m_deleteEventAct->setStatusTip(tr("Deletes the currently selected event from DES"));
	m_deleteEventAct->setEnabled(false);
	connect(m_deleteEventAct, SIGNAL(triggered()), desEditor(), SLOT(onDeleteEvent()));

	m_toggleEventCtrlAct = new QAction(tr("&Controllable Event"), this);
	m_toggleEventCtrlAct->setStatusTip(tr("Toggles the controllability of the currently selected event"));
	m_toggleEventCtrlAct->setCheckable(true);
	m_toggleEventCtrlAct->setEnabled(false);
	connect(m_toggleEventCtrlAct, SIGNAL(triggered()), desEditor(), SLOT(onToggleEventCtrl()));

	m_setEventTypeDefaultAct = new QAction(tr("&Default"), this);
	m_setEventTypeDefaultAct->setStatusTip(tr("Makes the currently selected event a default event"));
	m_setEventTypeDefaultAct->setCheckable(true);
	connect(m_setEventTypeDefaultAct, SIGNAL(triggered()), desEditor(), SLOT(onSetEventTypeDefault()));

	m_setEventTypeAnswerAct = new QAction(tr("&Answer"), this);
	m_setEventTypeAnswerAct->setStatusTip(tr("Makes the currently selected event an answer event"));
	m_setEventTypeAnswerAct->setCheckable(true);
	connect(m_setEventTypeAnswerAct, SIGNAL(triggered()), desEditor(), SLOT(onSetEventTypeAnswer()));

	m_setEventTypeRequestAct = new QAction(tr("&Request"), this);
	m_setEventTypeRequestAct->setStatusTip(tr("Makes the currently selected event a request event"));
	m_setEventTypeRequestAct->setCheckable(true);
	connect(m_setEventTypeRequestAct, SIGNAL(triggered()), desEditor(), SLOT(onSetEventTypeRequest()));

	m_setEventTypeLDataAct = new QAction(tr("&Low Data"), this);
	m_setEventTypeLDataAct->setStatusTip(tr("Makes the currently selected event a low-level data event"));
	m_setEventTypeLDataAct->setCheckable(true);
	connect(m_setEventTypeLDataAct, SIGNAL(triggered()), desEditor(), SLOT(onSetEventTypeLData()));

	m_clearEventTypeAct = new QAction(tr("&Clear"), this);
	m_clearEventTypeAct->setStatusTip(tr("Clears the type of the currently selected event"));
	m_clearEventTypeAct->setEnabled(false); //TODO figure out if we still need this command
	connect(m_clearEventTypeAct, SIGNAL(triggered()), desEditor(), SLOT(onClearEventType()));

	m_setEventTypeActGroup = new QActionGroup(this);
	m_setEventTypeActGroup->addAction(m_setEventTypeDefaultAct);
	m_setEventTypeActGroup->addAction(m_setEventTypeAnswerAct);
	m_setEventTypeActGroup->addAction(m_setEventTypeRequestAct);
	m_setEventTypeActGroup->addAction(m_setEventTypeLDataAct);
	m_setEventTypeActGroup->addAction(m_clearEventTypeAct);

	m_recordTransAct = new QAction(QIcon(":/resources/recordTransitions.png"), tr("&Record Transitions"), this);
	m_recordTransAct->setCheckable(true);
	m_recordTransAct->setStatusTip(tr("Starts / Stops the process of recording transitions by clicking states and events in their respective lists"));
	connect(m_recordTransAct, SIGNAL(triggered()), desEditor(), SLOT(onRecordTransitions()));

	m_addTransAct = new QAction(QIcon(":/resources/addTransition.png"), tr("&Add Transition"), this);
	m_addTransAct->setStatusTip(tr("Adds a new transition to DES"));
	connect(m_addTransAct, SIGNAL(triggered()), desEditor(), SLOT(onAddTransition()));

	m_addSelfTransAct = new QAction(QIcon(":/resources/addSelfTransition.png"), tr("&Add Global Self-Loop"), this);
	m_addSelfTransAct->setStatusTip(tr("Adds a new transition to DES"));
	connect(m_addSelfTransAct, SIGNAL(triggered()), desEditor(), SLOT(onAddSelfTransition()));

	m_changeTransAct = new QAction(QIcon(":/resources/changeTransition.png"), tr("&Change Transition"), this);
	m_changeTransAct->setStatusTip(tr("Renames the currently selected transition in DES"));
	m_changeTransAct->setEnabled(false);
	connect(m_changeTransAct, SIGNAL(triggered()), desEditor(), SLOT(onChangeTransition()));

	m_deleteTransAct = new QAction(QIcon(":/resources/deleteTransition.png"), tr("&Delete Transition"), this);
	m_deleteTransAct->setStatusTip(tr("Deletes the currently selected transition from DES"));
	m_deleteTransAct->setEnabled(false);
	connect(m_deleteTransAct, SIGNAL(triggered()), desEditor(), SLOT(onDeleteTransition()));

	m_deleteSelfTransAct = new QAction(QIcon(":/resources/deleteSelfTransition.png"), tr("&Delete Global Self-Loop"), this);
	m_deleteSelfTransAct->setStatusTip(tr("Deletes the currently selected global self-loop from DES"));
	m_deleteSelfTransAct->setEnabled(false);
	connect(m_deleteSelfTransAct, SIGNAL(triggered()), desEditor(), SLOT(onDeleteSelfTransition()));

	m_checkDesIntegAct = new QAction(QIcon(":/resources/checkDesConsist.png"), tr("&Verify DES Integrity"), this);
	m_checkDesIntegAct->setStatusTip(tr("Verifies the integrity of the DES"));
	connect(m_checkDesIntegAct, SIGNAL(triggered()), desEditor(), SLOT(onCheckDesIntegrity()));

	m_runReachToolAct = new QAction(QIcon(":/resources/reachDes.png"), tr("&Check Reachability"), this);
	m_runReachToolAct->setStatusTip(tr("Checks that DES is reachable - every state is reachable from the initial state"));
	connect(m_runReachToolAct, SIGNAL(triggered()), desEditor(), SLOT(onRunReachableTool()));

	m_runCoreachToolAct = new QAction(QIcon(":/resources/coReachDes.png"), tr("&Check Coreachability"), this);
	m_runCoreachToolAct->setStatusTip(tr("Checks that DES is coreachable - from any state DES can get to a marked state"));
	connect(m_runCoreachToolAct, SIGNAL(triggered()), desEditor(), SLOT(onRunCoreachableTool()));

	m_runNonblockToolAct = new QAction(QIcon(":/resources/checkNonBlocking.png"), tr("&Check Nonblocking"), this);
	m_runNonblockToolAct->setStatusTip(tr("Checks that every reachable state is coreachable"));
	connect(m_runNonblockToolAct, SIGNAL(triggered()), desEditor(), SLOT(onRunNonBlockTool()));

	m_openHelpFileAct = new QAction(tr("&Help Contents"), this);
	m_openHelpFileAct->setStatusTip("Opens the Application Help File");
	connect(m_openHelpFileAct, SIGNAL(triggered()), mainForm(), SLOT(onOpenHelpFile()));

	m_aboutDespotAct = new QAction(tr("&About"), this);
	m_aboutDespotAct->setStatusTip("Displays information about the DESpot application");
	connect(m_aboutDespotAct, SIGNAL(triggered()), mainForm(), SLOT(onAboutDespot()));

	saveAsImageAction = new QAction(tr("E&xport to image"), this);
    saveAsImageAction->setStatusTip(tr("Export to image file"));
    connect(saveAsImageAction, SIGNAL(triggered()), this, SLOT(saveAsImage()));

    if (desEditor()->ownedByProject())
    {
		saveAllAsPsAct = new QAction(tr("E&xport all DES to PostScript"), this);
		saveAllAsPsAct->setStatusTip(tr("Export all DES in project to PostScript files"));
		connect(saveAllAsPsAct, SIGNAL(triggered()), this, SLOT(saveAllAsPs()));

		saveAllAsPngAct = new QAction(tr("Export all DES to png"), this);
		saveAllAsPngAct->setStatusTip(tr("Export all DES in project to png files"));
		connect(saveAllAsPngAct, SIGNAL(triggered()), this, SLOT(saveAllAsPng()));
    }

	restoreDefaultShapeAction = new QAction(tr("Default Shape"), this);
    restoreDefaultShapeAction->setStatusTip(tr("Restore default shape"));

    deleteAction = new QAction(QIcon(":/resources/ged_delete.png"),
                               tr("&Delete"), this);
    deleteAction->setShortcut(tr("Delete"));
    deleteAction->setStatusTip(tr("Delete item from diagram"));


	editAction = new QAction(QIcon(":/resources/ged_edit.png"),
                               tr("&Edit"), this);
    editAction->setShortcut(tr("Edit"));
    editAction->setStatusTip(tr("Edit an item in the diagram"));

	editStateAction = new QAction(tr("&Edit"), 0);
    //toggleMarkedAction->setChecked(spreadsheet->showGrid());
    editStateAction->setStatusTip(tr("Edit state properties"));
	connect(editStateAction, SIGNAL(triggered()),
        this, SLOT(editState()));

	editTransAction = new QAction(tr("&Edit"), 0);
    //toggleMarkedAction->setChecked(spreadsheet->showGrid());
    editStateAction->setStatusTip(tr("Edit transition properties"));
	connect(editStateAction, SIGNAL(triggered()),
        this, SLOT(editTransition()));


    toggleBackgroundGrid= new QAction(QIcon(":/resources/ged_grid.png"),tr("&Show Grid"), 0);
    toggleBackgroundGrid->setCheckable(true);
    toggleBackgroundGrid->setChecked(false);
    toggleBackgroundGrid->setStatusTip(tr("Show Grid"));
	connect(toggleBackgroundGrid,SIGNAL(triggered()),
		this,SLOT(showGrid()));

}

void GedDesWorkspace::setupStatusBar()
{
	QStatusBar* statusBar = desEditor()->statusBar();
	statusBar->addPermanentWidget(m_progressWidget);
	statusBar->showMessage(tr("Use the States, Events and Transitions to create DES"));
}


void GedDesWorkspace::desCompButtonClicked(int id)
{
    QList<QAbstractButton *> buttons = buttonGroup->buttons();
    foreach (QAbstractButton *button, buttons)
	{
		if (buttonGroup->button(id) != button)
			button->setChecked(false);
    }

	QAbstractButton *button = buttonGroup->button(id);
    if (id == InsertTextButton) {
        scene->setMode(GedDesScene::InsertText);
    }
    else if(id == InsertTransButton){
		if (button->isChecked())
			scene->setMode(GedDesScene::InsertTrans);
		else
			scene->setMode(GedDesScene::Mode(pointerTypeGroup->checkedId()));
    } else {
		if (button->isChecked())
		{
			scene->setMode(GedDesScene::InsertState);
			scene->setCompType(GedDesState::GedStateType(id));
		}
		else
			scene->setMode(GedDesScene::Mode(pointerTypeGroup->checkedId()));

    }
}

void GedDesWorkspace::deleteItem()
{
	scene->deleteItem();
}

void GedDesWorkspace::showGrid()
{
	if (!toggleBackgroundGrid->isChecked()){
	    scene->setBackgroundBrush(QPixmap(":/resources/ged_nogrid.png"));
		//toggleBackgroundGrid->setChecked(true);
	}
	else{
		scene->setBackgroundBrush(QPixmap(":/resources/ged_grid.png"));
		//toggleBackgroundGrid->setChecked(false);
	}
    scene->update();
    view->update();
}

void GedDesWorkspace::editState()
{
    foreach (QGraphicsItem *item, scene->selectedItems()) {
        if (item->type() == GedDesState::Type) {
			GedDesState *state = qgraphicsitem_cast<GedDesState *>(item);
			scene->editState(state);
        }
    }
}

void GedDesWorkspace::editTransition()
{
    foreach (QGraphicsItem *item, scene->selectedItems()) {
        if (item->type() == GedDesTrans::Type) {
			GedDesTrans *tran = qgraphicsitem_cast<GedDesTrans *>(item);
			scene->editTransition(tran);
        }
    }
}


void GedDesWorkspace::eventChanged(const DesEvent *ev)
{
	//This maybe not so efficient if there is a huge number of transistion
	Des::TransIteratorPtr transIt = myDes->createTransIterator(true); //true -> exclude global self-loops
	for(transIt->first(); transIt->isDone() == false; transIt->next())
	{
		const DesTransition& trans = transIt->currentItem();
		if (*ev == trans.event())
			scene->gedTrans(&trans)->updateLabel();
	}
}

void GedDesWorkspace::eventDeletePrep(const DesEvent *ev)
{
	transPendingUpdate.clear();
	Des::TransIteratorPtr transIt = myDes->createTransIterator(true); //true -> exclude global self-loops
	for(transIt->first(); transIt->isDone() == false; transIt->next())
	{
		const DesTransition& trans = transIt->currentItem();
		if (*ev == trans.event())
			transPendingUpdate.append(scene->gedTrans(&trans));
	}
}


void GedDesWorkspace::eventDeleted(const DesEvent *ev)
{
	foreach(GedDesTrans* tran, transPendingUpdate)
	{
		tran->deleteEventOnly(ev);
		tran->updateLabel();
		if (tran->eventCount() <= 0)
			scene->deleteTransition(tran);
	}
	transPendingUpdate.clear();
}

void GedDesWorkspace::pointerGroupClicked(int)
{
    scene->setMode(GedDesScene::Mode(pointerTypeGroup->checkedId()));
}

void GedDesWorkspace::stateInserted(GedDesState* /*item*/)
{
	//To support continuning clicking
    //scene->setMode(GedDesScene::Mode(pointerTypeGroup->checkedId()));
    //buttonGroup->button(int(item->desCompType()))->setChecked(false);
}

void GedDesWorkspace::transInserted(GedDesTrans* /*item*/)
{
	//To support continuning clicking
    //scene->setMode(GedDesScene::Mode(pointerTypeGroup->checkedId()));
    //buttonGroup->button(int(item->type()))->setChecked(false);
}

void GedDesWorkspace::textInserted(QGraphicsTextItem *)
{
    buttonGroup->button(InsertTextButton)->setChecked(false);
    scene->setMode(GedDesScene::Mode(pointerTypeGroup->checkedId()));
}

bool GedDesWorkspace::saveAllPrep()
{
	/*
	int ret = QMessageBox::warning(desEditor(), tr("Export All DES"),
						tr("Pleaes make sure you close all graphical DES editors  "
						   "except the current one. Continue exporting with other "
						   "graphical editor open may cause problems"
						   " Continue?"),
						QMessageBox::Yes,
						QMessageBox::No);
	if (ret == QMessageBox::No)
		return false;
	*/
	int ret = QMessageBox::warning(desEditor(), tr("WARNING: Export All DES"),
						tr("1) Make sure you close all graphical DES editors "
						   "except the current one. Continue exporting with other "
						   "graphical editor open may cause problems.\n"
						   "2) Exporting all DES may take a long time. The screen may "
						   "flicker due to opening and closing DES files. The files"
						   " will be saved to the subdirectory images under the project"
						   " folder. Any existing file with the same name <DES>.ps will"
						   " be overwritten.\n"
						   " Continue?"),
						QMessageBox::Yes,
						QMessageBox::No);
	if (ret == QMessageBox::No)
		return false;
	else
		return true;
}

void GedDesWorkspace::saveAllAsPs()
{
	if(!saveAllPrep())
		return;

	m_pOutputUiPart->writeLine("Export all DES to PostScript ...");
	DesProject::DesIteratorPtr desIt = desEditor()->projEditorOwner()->project()->createDesIterator();
	for(desIt->first(); desIt->isDone() == false; desIt->next())
	{
		const Des& des = desIt->currentItem();
		Des* pdes = const_cast<Des*>(&des);
		QString str;
		if (pdes == myDes)
		{
			desEditor()->saveAsPs();
			str="Completed export DES ";
		}
		else
		{
			if (graphInfoExist(pdes))
			{
				GedDesEditor editor(pdes, desEditor()->projEditorOwner(), desEditor()->projEditorOwner()->mainForm());
				editor.open();
				editor.saveAsPs();
				editor.close();
				str="Completed export DES ";
			}
			else
			{
				str="Graphic information does not exist. Skip DES ";
			}
		}
		str += QString::fromStdWString(des.getName());
		m_pOutputUiPart->writeLine(str);
	}

}

void GedDesWorkspace::saveAllAsPng()
{
	if(!saveAllPrep())
		return;

	m_pOutputUiPart->writeLine("Export all DES to png format ...");
	DesProject::DesIteratorPtr desIt = desEditor()->projEditorOwner()->project()->createDesIterator();
	for(desIt->first(); desIt->isDone() == false; desIt->next())
	{
		const Des& des = desIt->currentItem();
		Des* pdes = const_cast<Des*>(&des);
		QString str;
		if (pdes == myDes)
		{
			desEditor()->saveAsPng();
			str="Completed export DES ";
		}
		else
		{
			if (graphInfoExist(pdes))
			{
				GedDesEditor editor(pdes, desEditor()->projEditorOwner(), desEditor()->projEditorOwner()->mainForm());
				editor.open();
				editor.saveAsPng();
				editor.close();
				str="Completed export DES ";
			}
			else
			{
				str="Graphic information does not exist. Skip DES ";
			}
		}
		str += QString::fromStdWString(des.getName());
		m_pOutputUiPart->writeLine(str);
	}

}

bool GedDesWorkspace::graphInfoExist(Des* des)
{

	DesSerializer loader(*des, des, DesSerializer::CheckGraph);  //Note we read graph only here
	QString fname = QString::fromStdWString(des->getFileName());

	try
	{
		loader.load(fname.toStdWString());
		return true;
	}
	catch (...)
	{
		return false;
	}
}

void GedDesWorkspace::saveAsImage()
{

	 //Check suffix. On linux, suffixed is not attached automatically
	QString fileFilter;

	QFileInfo finfo = QFileInfo(QString::fromStdWString(desEditor()->getFilePath()));
	QString defaultFileName=finfo.absolutePath();

	defaultFileName += "/";
	//defaultFileName += finfo.baseName();
	defaultFileName += QString::fromStdWString(myDes->getName());
	//defaultFileName += suffix;

        // Current version of QT (qt-4.5.2-3) conatins a bug that
        // QFileDialog::getSaveFileName  i used as below, the file
        // filter the user selected is not returned which makes the
        //  ouput format selection code fail.  The object form below
        // works correctly, but it uses the qt  file selector instead
        // of the native one, so this doesn't match other file
        // dailogues!  Upgrading to qt-4.6.2-17 fixes this, but
        // introduces a new bug (dragging a state in GED no longer
        // causes transition connections to rubberband; only the state moves!
        // When we upgrade to a new version, we can go back to the old
        // file selection code. 
	QFileDialog dialog(desEditor(), tr("Export as image"), defaultFileName,tr("PostScript file (*.ps);;Image Files (*.png)"));
        dialog.setAcceptMode(QFileDialog::AcceptSave);

        if (dialog.exec() != QDialog::Accepted) 
           return;
        
        fileFilter = dialog.selectedNameFilter();
        QString  fileName = dialog.selectedFiles()[0];  


	/*	QString fileName=
		 QFileDialog::getSaveFileName(desEditor(), tr("Export as image"),
                                      //QDir::currentPath(),
									  defaultFileName,
                                      //tr("Image file (*.JPEG);;Image Files (*.PNG)"),
									  tr("PostScript file (*.ps);;Image Files (*.png)"),
                                      //tr("Image Files (*.png)"),
				      &fileFilter); */

	 if (fileName.isEmpty())
         return;

	QString suffix="unknown";
	if (fileFilter=="PostScript file (*.ps)")
		suffix = ".ps";
	else
		suffix = ".png";

	 QStringList fields = fileName.split('.');
     if (fields.size() < 2)
		 fileName.append(suffix);

     QFile file(fileName);
     if (!file.open(QFile::WriteOnly)) {
         QMessageBox::warning(desEditor(), tr("Export as image"),
                              tr("Cannot write file %1:\n%2.")
                              .arg(fileName)
                              .arg(file.errorString()));
         return;
     }

	if (suffix == ".png")
		saveAsPng(fileName);
	else
		saveAsPs(fileName);
}

void GedDesWorkspace::saveAsPng(QString& fileName)
{
    scene->clearSelection();
	const QSize sz = scene->sceneRect().size().toSize();

	// compute the scale
	// No scale at all
 	//QRectF rect = QRectF(0,0,sz.width()*newScale,sz.height()*newScale);
	//QSize targetSz = rect.size().toSize();

	QImage image(sz,QImage::Format_ARGB32_Premultiplied);
	image.fill(Qt::transparent);

    QPainter painter(&image);
    scene->render(&painter);

	image.save(fileName,"png");

}


/*
void GedDesWorkspace::saveAsPs()
{
	 QString fileFilter;
	 QString fileName=
		 QFileDialog::getSaveFileName(desEditor(), tr("Export as image"),
                                      QDir::currentPath(),
                                      //tr("Image file (*.JPEG);;Image Files (*.PNG)"),
                                      tr("PostScript Files (*.ps)"),
									  &fileFilter);

	 if (fileName.isEmpty())
         return;

	 //Check suffix. On linux, suffixed is not attached automatically
	 QString suffix="unknown";
	 if (fileFilter=="PostScript Files (*.ps)")
		 suffix = ".ps";
	 else
		 suffix = ".ps";

	 QStringList fields = fileName.split('.');
     if (fields.size() < 2)
		 fileName.append(suffix);
	 saveAsPs(fileName);
}
*/

void GedDesWorkspace::saveAsPs(QString& fileName)
{
     QFile file(fileName);
     if (!file.open(QFile::WriteOnly)) {
         QMessageBox::warning(desEditor(), tr("Export to PostScript"),
                              tr("Cannot write file %1:\n%2.")
                              .arg(fileName)
                              .arg(file.errorString()));
         return;
     }

    scene->clearSelection();
	QPrinter printer(QPrinter::HighResolution);
	printer.setPageSize(QPrinter::A4);
	printer.setOutputFormat(QPrinter::PostScriptFormat);
	//printer.setOutputFormat(QPrinter::PdfFormat);

	printer.setOutputFileName(fileName);

    QPainter pp(&printer);
    scene->render(&pp);
	file.close();
}

void GedDesWorkspace::createToolBox()
{
    buttonGroup = new QButtonGroup;
    buttonGroup->setExclusive(false);
    connect(buttonGroup, SIGNAL(buttonClicked(int)),
            this, SLOT(desCompButtonClicked(int)));
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(createDesCompButton(tr("Initial"),
                               GedDesState::InitState), 0, 0);
    layout->addWidget(createDesCompButton(tr("Regular"),
                      GedDesState::RegularState),0, 1);
    layout->addWidget(createDesCompButton(tr("Marked"),
                      GedDesState::MarkedState), 1, 0);
    layout->addWidget(createDesCompButton(tr("InitMarked"),
                      GedDesState::InitMarkedState), 1, 1);

	/*
    // Event botton
    QToolButton *eventButton = new QToolButton;
    eventButton->setCheckable(false);
    buttonGroup->addButton(eventButton, InsertEventButton);
    // image of the text button
    eventButton->setIcon(QIcon(QPixmap(":/resources/ged_event.png")
                        .scaled(25, 25)));
    eventButton->setIconSize(QSize(25, 25));
    // To layout event button and the label
    QGridLayout *eventLayout = new QGridLayout;
    eventLayout->addWidget(eventButton, 0, 0, Qt::AlignHCenter);
    eventLayout->addWidget(new QLabel(tr("Event")), 1, 0, Qt::AlignCenter);
    QWidget *eventWidget = new QWidget;
    eventWidget->setLayout(eventLayout);
    layout->addWidget(eventWidget, 2, 0);
    connect(eventButton, SIGNAL(clicked()), desEditor(), SLOT(onAddEvent()));
	*/

    // Transition botton
    QToolButton *transButton = new QToolButton;
    transButton->setCheckable(true);
    buttonGroup->addButton(transButton, InsertTransButton);
    // image of the trans button
    transButton->setIcon(QIcon(QPixmap(":/resources/ged_transition.png")
                        .scaled(25, 25)));
    transButton->setIconSize(QSize(25, 25));
    // To layout trans button and the label 'trans'
    QGridLayout *transLayout = new QGridLayout;
    transLayout->addWidget(transButton, 0, 0, Qt::AlignHCenter);
    transLayout->addWidget(new QLabel(tr("Transition")), 1, 0, Qt::AlignCenter);
    QWidget *transWidget = new QWidget;
    transWidget->setLayout(transLayout);
    layout->addWidget(transWidget, 2, 1);


    // Text botton
    QToolButton *textButton = new QToolButton;
    textButton->setCheckable(true);
    buttonGroup->addButton(textButton, InsertTextButton);
    // image of the text button
    textButton->setIcon(QIcon(QPixmap(":/resources/ged_textpointer.png")
                        .scaled(25, 25)));
    textButton->setIconSize(QSize(25, 25));
    // To layout text button and the label 'text'
    QGridLayout *textLayout = new QGridLayout;
    textLayout->addWidget(textButton, 0, 0, Qt::AlignHCenter);
    textLayout->addWidget(new QLabel(tr("Text")), 1, 0, Qt::AlignCenter);
    QWidget *textWidget = new QWidget;
    textWidget->setLayout(textLayout);
    layout->addWidget(textWidget, 2, 0);

    layout->setRowStretch(5, 10);
    layout->setColumnStretch(1, 10);

    QWidget *itemWidget = new QWidget;
    itemWidget->setLayout(layout);

    toolBox = new QToolBox;
    toolBox->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Ignored));
    toolBox->setMinimumWidth(itemWidget->sizeHint().width());
    toolBox->addItem(itemWidget, tr("Add DES Components"));
}


void GedDesWorkspace::createMenus()
{

	m_desMenu = desEditor()->menuBar()->addMenu(tr("&File"));
	//m_desMenu->addAction(m_newDesAct);
	//m_desMenu->addAction(m_openDesAct);
	m_desMenu->addAction(m_saveDesAct);
	m_desMenu->addAction(m_saveDesAsAct);
	m_desMenu->addSeparator();
	m_desMenu->addAction(m_desSetNameAct);
	m_desMenu->addAction(m_desSetTypeAct);
	m_desMenu->addSeparator();
	m_desMenu->addAction(m_printDesAct);
	m_desMenu->addAction(saveAsImageAction);

	if (desEditor()->ownedByProject())
	{
		exportSubMenu = m_desMenu->addMenu(tr("&Export All"));
		exportSubMenu->addAction(saveAllAsPsAct);
		exportSubMenu->addAction(saveAllAsPngAct);
	}

	m_desMenu->addSeparator();
	m_desMenu->addAction(m_closeGedDesEditorAct);


	m_editMenu = desEditor()->menuBar()->addMenu(tr("&Edit"));
	/*
	m_editMenu->addAction(m_addStateAct);
	m_editMenu->addAction(m_changeStateAct);
	m_editMenu->addAction(m_deleteStateAct);
	m_editMenu->addSeparator();
	m_editMenu->addAction(m_toggleInitialStateAct);
	m_editMenu->addAction(m_toggleMarkedStateAct);
	m_editMenu->addSeparator();
	m_editMenu->addAction(m_markAllStatesAct);
	m_editMenu->addAction(m_unmarkAllStatesAct);

	m_editMenu->addSeparator();
	*/
	m_editMenu->addAction(m_addEventAct);
	m_editMenu->addAction(m_changeEventAct);
	m_editMenu->addAction(m_deleteEventAct);
	m_editMenu->addSeparator();
	m_editMenu->addAction(m_toggleEventCtrlAct);

	m_eventTypeSubMenu = m_editMenu->addMenu(tr("Set &Type"));
	m_eventTypeSubMenu->addAction(m_setEventTypeDefaultAct);
	m_eventTypeSubMenu->addSeparator();
	m_eventTypeSubMenu->addAction(m_setEventTypeRequestAct);
	m_eventTypeSubMenu->addAction(m_setEventTypeAnswerAct);
	m_eventTypeSubMenu->addAction(m_setEventTypeLDataAct);
	m_eventTypeSubMenu->addSeparator();
	m_eventTypeSubMenu->addAction(m_clearEventTypeAct);

	//disable the menu to start with
	m_eventTypeSubMenu->menuAction()->setEnabled(false);
	m_editMenu->addSeparator();
	m_editMenu->addAction(m_addSelfTransAct);
	m_editMenu->addAction(m_deleteSelfTransAct);

	/*
	m_editMenu->addSeparator();
	//m_editMenu = desEditor()->menuBar()->addMenu(tr("&Transitions"));
	m_editMenu->addAction(m_recordTransAct);
	m_editMenu->addSeparator();
	m_editMenu->addAction(m_addTransAct);
	m_editMenu->addAction(m_addSelfTransAct);
	m_editMenu->addAction(m_changeTransAct);
	m_editMenu->addAction(m_deleteTransAct);
	m_editMenu->addAction(m_deleteSelfTransAct);
	*/
	m_toolsMenu = desEditor()->menuBar()->addMenu(tr("&Tools"));
	m_toolsMenu->addAction(m_checkDesIntegAct);
	m_toolsMenu->addSeparator();
	m_toolsMenu->addAction(m_runReachToolAct);
	//m_toolsMenu->addAction(m_runCoreachToolAct);
	m_toolsMenu->addAction(m_runNonblockToolAct);

	m_formatMenu = desEditor()->menuBar()->addMenu(tr("&Format"));
	m_formatMenu->addAction(toggleBackgroundGrid);

	desEditor()->menuBar()->addSeparator();
	m_helpMenu = desEditor()->menuBar()->addMenu(tr("&Help"));
	m_helpMenu->addAction(m_openHelpFileAct);
	m_helpMenu->addSeparator();
	m_helpMenu->addAction(m_aboutDespotAct);

	QMenu& stateEditorCtxMenu = m_pStateEdUiPart->getContextMenu();
	stateEditorCtxMenu.addAction(m_addStateAct);
	stateEditorCtxMenu.addAction(m_changeStateAct);
	stateEditorCtxMenu.addAction(m_deleteStateAct);

	stateEditorCtxMenu.addSeparator();

	stateEditorCtxMenu.addAction(m_toggleInitialStateAct);
	stateEditorCtxMenu.addAction(m_toggleMarkedStateAct);
	QMenu& eventEditorContextMenu = m_pEventEdUiPart->getContextMenu();
	eventEditorContextMenu.addAction(m_addEventAct);
	eventEditorContextMenu.addAction(m_changeEventAct);
	eventEditorContextMenu.addAction(m_deleteEventAct);

	eventEditorContextMenu.addSeparator();

	eventEditorContextMenu.addAction(m_toggleEventCtrlAct);
	QMenu& eventTypeSubContextMenu = m_pEventEdUiPart->getEventTypeContextSubMenu();
	eventTypeSubContextMenu.addAction(m_setEventTypeDefaultAct);
	eventTypeSubContextMenu.addSeparator();
	eventTypeSubContextMenu.addAction(m_setEventTypeRequestAct);
	eventTypeSubContextMenu.addAction(m_setEventTypeAnswerAct);
	eventTypeSubContextMenu.addAction(m_setEventTypeLDataAct);

	//disable the menu to start with
	eventTypeSubContextMenu.menuAction()->setEnabled(false);

	QMenu& transEditorContextMenu = m_pTransEdUiPart->getTransContextMenu();
	transEditorContextMenu.addAction(m_recordTransAct);
	transEditorContextMenu.addSeparator();
	transEditorContextMenu.addAction(m_addTransAct);
	transEditorContextMenu.addAction(m_addSelfTransAct);
	transEditorContextMenu.addAction(m_changeTransAct);
	transEditorContextMenu.addAction(m_deleteTransAct);
	QMenu& selfTransEditorContextMenu = m_pTransEdUiPart->getSelfTransContextMenu();
	selfTransEditorContextMenu.addAction(m_addSelfTransAct);
	selfTransEditorContextMenu.addAction(m_deleteSelfTransAct);

	stateContextMenu = new QMenu(tr("&States"));
	stateContextMenu->addAction(deleteAction);
	stateContextMenu->addSeparator();
	stateContextMenu->addAction(editAction);
	/*
	stateContextMenu->addAction(toggleInitAction);
    stateContextMenu->addAction(toggleMarkedAction);
	*/

	transContextMenu = new QMenu(tr("&Transition"));
    transContextMenu->addAction(deleteAction);
    transContextMenu->addSeparator();
	transContextMenu->addAction(editAction);
	transContextMenu->addAction(restoreDefaultShapeAction);
	}

void GedDesWorkspace::createToolbars()
{
	m_desToolBar = desEditor()->addToolBar(tr("DES"));
	m_desToolBar->setIconSize(cToolBarIconSize);

	//m_desToolBar->addAction(m_newDesAct);
	//m_desToolBar->addAction(m_openDesAct);
	m_desToolBar->addAction(m_saveDesAct);

	/*
	m_desToolBar->addSeparator();
	m_desToolBar->addAction(m_addStateAct);
	m_desToolBar->addAction(m_changeStateAct);
	m_desToolBar->addAction(m_deleteStateAct);
	*/
	m_desToolBar->addSeparator();
	m_desToolBar->addAction(m_addEventAct);
	m_desToolBar->addAction(m_changeEventAct);
	m_desToolBar->addAction(m_deleteEventAct);
	m_desToolBar->addSeparator();
	/*
	m_desToolBar->addAction(m_recordTransAct);
	m_desToolBar->addAction(m_addTransAct);
	m_desToolBar->addAction(m_changeTransAct);
	m_desToolBar->addAction(m_deleteTransAct);
	*/

	m_desToolBar->addAction(m_addSelfTransAct);
	m_desToolBar->addAction(m_deleteSelfTransAct);

	m_desToolsToolBar = desEditor()->addToolBar(tr("Tools"));
	m_desToolsToolBar->setIconSize(cToolBarIconSize);

	m_desToolsToolBar->addAction(m_checkDesIntegAct);
	//m_desToolsToolBar->addSeparator();
	m_desToolsToolBar->addAction(m_runReachToolAct);
	//m_desToolsToolBar->addAction(m_runCoreachToolAct);
	m_desToolsToolBar->addAction(m_runNonblockToolAct);

    editToolBar = desEditor()->addToolBar(tr("Edit"));
    editToolBar->addAction(editAction);
    editToolBar->addAction(deleteAction);
    editToolBar->addAction(toggleBackgroundGrid);
    //editToolBar->addAction(toFrontAction);
    //editToolBar->addAction(sendBackAction);

    QToolButton *pointerButton = new QToolButton;
    pointerButton->setCheckable(true);
    pointerButton->setChecked(true);
    pointerButton->setIcon(QIcon(":/resources/ged_pointer.png"));
	pointerButton->setStatusTip("Move a DES state or label");
	pointerButton->setToolTip(tr("Move an item..."));
    QToolButton *linePointerButton = new QToolButton;
    linePointerButton->setCheckable(true);
    linePointerButton->setIcon(QIcon(":/resources/ged_linepointer.png"));
	linePointerButton->setStatusTip("Change DES transition shape");
	linePointerButton->setToolTip(tr("Change trans shape..."));

    pointerTypeGroup = new QButtonGroup;
    pointerTypeGroup->addButton(pointerButton, int(GedDesScene::MoveItem));
    pointerTypeGroup->addButton(linePointerButton,
                                int(GedDesScene::ChangeTrans));
    connect(pointerTypeGroup, SIGNAL(buttonClicked(int)),
            this, SLOT(pointerGroupClicked(int)));

    sceneScaleCombo = new QComboBox;
    QStringList scales;
    scales << tr("50%") << tr("75%") << tr("100%") << tr("125%") << tr("150%") << tr("200%") <<
		      tr("300%") << tr("400%") << tr("500%") << tr("600%") << tr("700%") << tr("800%");
    sceneScaleCombo->addItems(scales);
    sceneScaleCombo->setCurrentIndex(2);
	sceneScaleCombo->setStatusTip("Change diagram scale");
	sceneScaleCombo->setToolTip(tr("Scale the diagram"));
    connect(sceneScaleCombo, SIGNAL(currentIndexChanged(const QString &)),
            this, SLOT(sceneScaleChanged(const QString &)));

    pointerToolbar = desEditor()->addToolBar(tr("Pointer type"));
    pointerToolbar->addWidget(pointerButton);
    pointerToolbar->addWidget(linePointerButton);
    pointerToolbar->addWidget(sceneScaleCombo);

}

QWidget *GedDesWorkspace::createDesCompButton(const QString &text,
                      GedDesState::GedStateType type)
{

    GedDesState item(type, itemMenu);
    QIcon icon(item.image());

    QToolButton *button = new QToolButton;
    button->setIcon(icon);
    button->setIconSize(QSize(25, 25));
    button->setCheckable(true);
    buttonGroup->addButton(button, int(type));

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(button, 0, 0, Qt::AlignHCenter);
    layout->addWidget(new QLabel(text), 1, 0, Qt::AlignCenter);

    QWidget *widget = new QWidget;
    widget->setLayout(layout);

    return widget;
}

void GedDesWorkspace::sceneScaleChanged(const QString &scale)
{
    newScale = scale.left(scale.indexOf(tr("%"))).toDouble() / 100.0;
    QMatrix oldMatrix = view->matrix();
    view->resetMatrix();
    view->translate(oldMatrix.dx(), oldMatrix.dy());
    view->scale(newScale, newScale);
}

bool GedDesWorkspace::isGraphModified()
{
	return scene->isModified();
}


} //end of namespace DESpot
