/*
 * ImageLabeler.cpp
 *
 *  Created on: Oct 4, 2011
 *      Author: Gapchich Vladislav
 */

#include "ImageLabeler.h"
#include "functions.h"

#include <QApplication>
#include <QFrame>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QBoxLayout>
#include <QGridLayout>
#include <QPixmap>
#include <QLabel>
#include <QScrollArea>
#include <QPushButton>
#include <QButtonGroup>
#include <QListWidget>
#include <QListWidgetItem>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QColorDialog>
#include <QDir>
#include <QMessageBox>
#include <QListIterator>
#include <QDomDocument>
#include <QFile>
#include <QKeyEvent>
#include <QDebug>

ImageLabeler::ImageLabeler(QWidget *aParent) :
	QMainWindow(aParent)
{
	/*
	 * Variables
	 */

	list_images_ = new QStringList();

	main_label_ = -1;
	pure_data_ = 0;
	//label_ID_ = -1;

	/* options */
	auto_color_generation_ = 0;

	/* flags */
	interrupt_search_ = 0;
	unsaved_data_ = 0;

	/*
	 * menu bar part begins
	 */

	menu_bar_ = new QMenuBar(this);
	setMenuBar(menu_bar_);

	menu_file_ = new QMenu(menu_bar_);
	menu_file_->setTitle(tr("&File"));
	menu_view_ = new QMenu(menu_bar_);
	menu_view_->setTitle(tr("&View"));
	menu_edit_ = new QMenu(menu_bar_);
	menu_edit_->setTitle(tr("&Edit"));
	menu_help_ = new QMenu(menu_bar_);
	menu_help_->setTitle(tr("&Help"));

	/* menu file */
	action_open_image_ = new QAction(this);
	action_open_image_->setText(tr("&Load image"));
	action_open_images_ = new QAction(this);
	action_open_images_->setText(tr("&Load images(recursively)"));
	action_open_labeled_image_ = new QAction(this);
	action_open_labeled_image_->setText(tr("&Load labeled image"));
	action_load_legend_ = new QAction(this);
	action_load_legend_->setText(tr("&Load legend"));
	action_save_labels_ = new QAction(this);
	action_save_labels_->setText(tr("&Save all info"));
	action_save_labels_->setEnabled(false);
	action_save_segmented_ = new QAction(this);
	action_save_segmented_->setText(tr("Save segmented &picture"));
	action_save_segmented_->setEnabled(false);
	action_save_legend_ = new QAction(this);
	action_save_legend_->setText(tr("Save &legend"));
	action_save_legend_->setEnabled(false);
	action_quit_ = new QAction(this);
	action_quit_->setText(tr("&Quit"));
	/* menu view */
	action_view_normal_ = new QAction(this);
	action_view_normal_->setText(tr("&Normal"));
	action_view_normal_->setEnabled(false);
	action_view_segmented_ = new QAction(this);
	action_view_segmented_->setText(tr("&Segmented"));
	action_view_segmented_->setEnabled(false);
	/* menu edit */
	action_undo_ = new QAction(this);
	action_undo_->setText(tr("&Undo"));
	action_undo_->setEnabled(false);
	action_redo_ = new QAction(this);
	action_redo_->setText(tr("&Redo"));
	action_redo_->setEnabled(false);
	action_bound_box_tool_ = new QAction(this);
	action_bound_box_tool_->setText(tr("Bounding box tool"));
	action_bound_box_tool_->setEnabled(false);
	action_polygon_tool_ = new QAction(this);
	action_polygon_tool_->setText(tr("&Polygon tool"));
	action_polygon_tool_->setEnabled(false);
	action_tagging_tool_ = new QAction(this);
	action_tagging_tool_->setText(tr("&Tagging tool"));
	action_tagging_tool_->setEnabled(false);
	action_add_description_ = new QAction(this);
	action_add_description_->setText(tr("&Add image description"));
	action_add_description_->setEnabled(false);
	action_options_ = new QAction(this);
	action_options_->setText(tr("&Options"));
	/* menu help */
	action_help_content_ = new QAction(this);
	action_help_content_->setText(tr("&Help content"));
	action_help_content_->setEnabled(false);
	action_about_ = new QAction(this);
	action_about_->setText(tr("&About"));
	action_about_->setEnabled(false);
	/* ------------------ */

	menu_file_->addAction(action_open_image_);
	menu_file_->addAction(action_open_images_);
	menu_file_->addAction(action_open_labeled_image_);
	menu_file_->addAction(action_load_legend_);
	menu_file_->addAction(action_save_segmented_);
	menu_file_->addAction(action_save_legend_);
	menu_file_->addAction(action_save_labels_);
	menu_file_->addAction(action_quit_);

	menu_view_->addAction(action_view_normal_);
	menu_view_->addAction(action_view_segmented_);

	menu_edit_->addAction(action_undo_);
	menu_edit_->addAction(action_redo_);
	menu_edit_->addAction(action_bound_box_tool_);
	menu_edit_->addAction(action_polygon_tool_);
	menu_edit_->addAction(action_tagging_tool_);
	menu_edit_->addAction(action_add_description_);
	menu_edit_->addAction(action_options_);

	menu_help_->addAction(action_help_content_);
	menu_help_->addAction(action_about_);

	menu_bar_->addAction(menu_file_->menuAction());
	menu_bar_->addAction(menu_view_->menuAction());
	menu_bar_->addAction(menu_edit_->menuAction());
	menu_bar_->addAction(menu_help_->menuAction());

	/*
	 * popup menu part begins
	 */
	popup_area_list_ = new QMenu;

	action_delete_area_ = new QAction(this);
	action_delete_area_->setText(tr("&Delete area"));
	action_edit_area_ = new QAction(this);
	action_edit_area_->setText(tr("&Change area"));

	popup_area_list_->addAction(action_delete_area_);
	popup_area_list_->addAction(action_edit_area_);

	popup_label_list_ = new QMenu;

	action_set_color_ = new QAction(this);
	action_set_color_->setText(tr("Set &color"));
	action_toggle_priority_ = new QAction(this);
	action_toggle_priority_->setText(tr("Toggle &priority"));
	action_delete_label_ = new QAction(this);
	action_delete_label_->setText(tr("&Delete"));

	popup_label_list_->addAction(action_set_color_);
	popup_label_list_->addAction(action_toggle_priority_);
	popup_label_list_->addAction(action_delete_label_);

	/*
	 * widgets part begins
	 */
	central_widget_ = new QWidget(this);
	setCentralWidget(central_widget_);

	frame_toolbox_ = new QFrame(central_widget_);
	frame_toolbox_->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
	frame_toolbox_->setLineWidth(0);
	frame_toolbox_->setMidLineWidth(0);
	frame_center_ = new QFrame(central_widget_);
	//frame_image_->setFrameStyle(QFrame::Box | QFrame::Plain);
	//frame_image_->setLineWidth(1);
	frame_image_ = new QScrollArea(frame_center_);
	//frame_image_->setStyleSheet("QWidget {background: #888888;}");
	frame_image_->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
	frame_image_->setLineWidth(0);
	frame_image_->setMidLineWidth(0);
	frame_image_->setWidgetResizable(false);
	frame_image_->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
	frame_image_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
	frame_labelbox_ = new QFrame(central_widget_);
	frame_labelbox_->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
	frame_labelbox_->setLineWidth(0);
	frame_labelbox_->setMidLineWidth(0);

	image_ = new QPixmap(500, 500);
	image_->fill(QColor(Qt::white));

	//image_holder_ = new ImageHolder(frame_image_);
	image_holder_ = new ImageHolder;//(frame_image_);
	image_holder_->setPixmap(*image_);
	//image_holder_->setStyleSheet("QLabel {background: #ffffff;}");
	image_holder_->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
	image_holder_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
	image_holder_->setFocusPolicy(Qt::StrongFocus);
	image_holder_->setFocus();
	image_holder_->setScaledContents(true);
	image_holder_->setFrameStyle(QFrame::Box | QFrame::Plain);
	image_holder_->setLineWidth(0);

	frame_image_->setWidget(image_holder_);

	list_label_ = new QListWidget(central_widget_);
	list_label_->setContextMenuPolicy(Qt::CustomContextMenu);
	list_areas_ = new QListWidget(central_widget_);
	list_areas_->setContextMenuPolicy(Qt::CustomContextMenu);
	list_images_widget_ = new QListWidget(central_widget_);
	//list_images_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
//	addLabel(0, false, "BACKGROUND");
//	list_label_->item(0)->setFlags(Qt::ItemIsSelectable);
	//QListWidgetItem *background = list_label_->item(0);
	//qDebug() << background;
	//background->setFlags(Qt::ItemIsSelectable);

	label_toolbox_ = new QLabel(tr("Tool box"), frame_toolbox_);
	label_list_areas_ = new QLabel(tr("Selected areas:"), central_widget_);
	label_list_images_ = new QLabel(tr("Loaded images:"), central_widget_);

	/* buttons */
	button_bound_box_tool_ = new QPushButton(frame_toolbox_);
	button_bound_box_tool_->setText(tr("bbox"));
	button_bound_box_tool_->setEnabled(false);
	button_bound_box_tool_->setCheckable(true);
	button_polygon_tool_ = new QPushButton(frame_toolbox_);
	button_polygon_tool_->setText(tr("poly tool"));
	button_polygon_tool_->setEnabled(false);
	button_polygon_tool_->setCheckable(true);
	button_tagging_tool_ = new QPushButton(frame_toolbox_);
	button_tagging_tool_->setText(tr("tagging"));
	button_tagging_tool_->setEnabled(false);
	button_tagging_tool_->setCheckable(true);
	button_clear_selection_tool_ = new QPushButton(frame_toolbox_);
	button_clear_selection_tool_->setText(tr("clear selection"));
	button_clear_selection_tool_->setEnabled(false);
	button_generate_colors_ = new QPushButton(frame_toolbox_);
	button_generate_colors_->setText(tr("generate label colors"));
	button_generate_colors_->setEnabled(false);
	button_delete_all_labels_ = new QPushButton(frame_toolbox_);
	button_delete_all_labels_->setText(tr("delete all labels"));
	button_delete_all_labels_->setEnabled(false);

	group_tools_ = new QButtonGroup;
	group_tools_->addButton(button_bound_box_tool_);
	group_tools_->addButton(button_polygon_tool_);
	group_tools_->addButton(button_tagging_tool_);

	button_confirm_selection_ = new QPushButton(central_widget_);
	button_confirm_selection_->setText(tr("Confirm selection"));
	button_confirm_selection_->setEnabled(false);

	button_add_label_ = new QPushButton(frame_labelbox_);
	button_add_label_->setText(tr("Add label"));
	button_add_label_->setEnabled(false);
	button_remove_label_ = new QPushButton(frame_labelbox_);
	button_remove_label_->setText(tr("Remove label"));
	button_remove_label_->setEnabled(false);

	button_prev_image_ = new QPushButton(central_widget_);
	button_prev_image_->setText("←");
	button_next_image_ = new QPushButton(central_widget_);
	button_next_image_->setText("→");

	/*
	 * layouts part begins
	 */
	layout_main_ = new QHBoxLayout(central_widget_);
	layout_left_ = new QVBoxLayout();
	layout_toolbox_ = new QVBoxLayout();
	layout_center_ = new QVBoxLayout();
	layout_frame_image_ = new QVBoxLayout();
	layout_image_widget_ = new QGridLayout();
	layout_center_buttons_ = new QHBoxLayout();
	layout_right_ = new QVBoxLayout();
	layout_labelbox_ = new QVBoxLayout();
	layout_labelbox_buttons_ = new QHBoxLayout();

	layout_main_->addLayout(layout_left_);
	layout_main_->addLayout(layout_center_);
	layout_main_->addLayout(layout_right_);

	/* making the center part stretchable */
	layout_main_->setStretch(1, 1);

	/* left part */
	layout_left_->addWidget(frame_toolbox_);
	frame_toolbox_->setLayout(layout_toolbox_);

	layout_toolbox_->addWidget(label_toolbox_);
	layout_toolbox_->addWidget(button_bound_box_tool_);
	layout_toolbox_->addWidget(button_polygon_tool_);
	layout_toolbox_->addWidget(button_tagging_tool_);
	layout_toolbox_->addSpacing(10);
	layout_toolbox_->addWidget(button_clear_selection_tool_);
	layout_toolbox_->addWidget(button_delete_all_labels_);
	layout_toolbox_->addSpacing(10);
	layout_toolbox_->addWidget(button_generate_colors_);
	/* stretch is for making toolbox as small as it can be */
	layout_toolbox_->addSpacing(10);
	layout_left_->addWidget(label_list_images_);
	layout_left_->addWidget(list_images_widget_);
	list_images_widget_->setFixedWidth(200);
	layout_left_->addStretch(1);
	layout_left_->addWidget(button_confirm_selection_);


	/* central part */
	layout_center_->addWidget(frame_center_);
	frame_center_->setLayout(layout_frame_image_);

	//layout_frame_image_->addWidget(image_holder_);
	layout_frame_image_->setContentsMargins(0, 0, 0, 0);
	layout_frame_image_->addWidget(frame_image_);

	//frame_image_->setLayout(layout_image_widget_);
//	layout_image_widget_->setRowStretch(0, 1);
//	layout_image_widget_->setColumnStretch(0, 1);
//	layout_image_widget_->addWidget(image_holder_, 1, 1);
//	layout_image_widget_->setRowStretch(2, 1);
//	layout_image_widget_->setColumnStretch(2, 1);

	//layout_frame_image_->addStretch(1);
	layout_frame_image_->addLayout(layout_center_buttons_);
	layout_center_buttons_->addWidget(button_prev_image_);
	layout_center_buttons_->addWidget(button_next_image_);

	/* right part */
	layout_right_->addWidget(frame_labelbox_);
	frame_labelbox_->setFixedWidth(200);
	frame_labelbox_->setLayout(layout_labelbox_);

	layout_labelbox_->addLayout(layout_labelbox_buttons_);
	layout_labelbox_buttons_->addWidget(button_add_label_);
	layout_labelbox_buttons_->addWidget(button_remove_label_);

	layout_labelbox_->addWidget(list_label_);
	layout_labelbox_->addWidget(label_list_areas_);
	layout_labelbox_->addWidget(list_areas_);

	connect(
		action_quit_,
		SIGNAL(triggered()),
		this,
		SLOT(close())
		);
	connect(
		action_open_images_,
		SIGNAL(triggered()),
		this,
		SLOT(loadImages())
		);
	connect(
		action_open_image_,
		SIGNAL(triggered()),
		this,
		SLOT(loadImage())
		);
	connect(
		action_open_labeled_image_,
		SIGNAL(triggered()),
		this,
		SLOT(loadInfo())
		);
	connect(
		action_load_legend_,
		SIGNAL(triggered()),
		this,
		SLOT(loadLegendFromFile())
		);
	connect(
		action_save_legend_,
		SIGNAL(triggered()),
		this,
		SLOT(saveLegend())
		);
	connect(
		action_save_segmented_,
		SIGNAL(triggered()),
		this,
		SLOT(saveSegmentedPicture())
		);
	connect(
		action_save_labels_,
		SIGNAL(triggered()),
		this,
		SLOT(saveAllInfo())
		);
	connect(
		action_view_normal_,
		SIGNAL(triggered()),
		this,
		SLOT(viewNormal())
		);
	connect(
		action_view_segmented_,
		SIGNAL(triggered()),
		this,
		SLOT(viewSegmented())
		);
	connect(
		action_undo_,
		SIGNAL(triggered()),
		image_holder_,
		SLOT(undo())
		);
	connect(
		action_redo_,
		SIGNAL(triggered()),
		image_holder_,
		SLOT(redo())
		);
	connect(
		action_add_description_,
		SIGNAL(triggered()),
		&image_description_form_,
		SLOT(show())
		);
	connect(
		action_options_,
		SIGNAL(triggered()),
		&options_form_,
		SLOT(show())
		);
	connect(
		button_add_label_,
		SIGNAL(clicked()),
		this,
		SLOT(addLabel())
		);
	connect(
		button_remove_label_,
		SIGNAL(clicked()),
		this, SLOT(removeLabel())
		);
	connect(
		button_next_image_,
		SIGNAL(clicked()),
		this,
		SLOT(nextImage())
		);
	connect(
		button_prev_image_,
		SIGNAL(clicked()),
		this,
		SLOT(prevImage())
		);
	connect(
		button_bound_box_tool_,
		SIGNAL(toggled(bool)),
		this,
		SLOT(setBoundingBoxTool(bool))
		);
	connect(
		button_polygon_tool_,
		SIGNAL(toggled(bool)),
		this,
		SLOT(setPolygonTool(bool))
		);
	connect(
		button_clear_selection_tool_,
		SIGNAL(clicked()),
		this,
		SLOT(clearAllTool())
		);
	connect(
		button_generate_colors_,
		SIGNAL(clicked()),
		this,
		SLOT(generateColors())
		);
	connect(
		button_delete_all_labels_,
		SIGNAL(clicked()),
		this,
		SLOT(clearLabelList())
		);
	connect(
		button_confirm_selection_,
		SIGNAL(clicked()),
		this,
		SLOT(confirmSelection())
		);
	connect(
		list_label_,
		SIGNAL(itemChanged(QListWidgetItem *)),
		this,
		SLOT(editLabel(QListWidgetItem *))
		);
	connect(
		list_label_,
		SIGNAL(itemClicked(QListWidgetItem *)),
		this,
		SLOT(setLabelID(QListWidgetItem *))
		);
	connect(
		list_areas_,
		SIGNAL(itemDoubleClicked(QListWidgetItem *)),
		image_holder_,
		SLOT(focusOnArea(QListWidgetItem *))
		);
	connect(
		list_areas_,
		SIGNAL(customContextMenuRequested(const QPoint &)),
		this,
		SLOT(areaListPopupMenu(const QPoint &))
		);
	connect(
		list_areas_,
		SIGNAL(itemChanged(QListWidgetItem *)),
		this,
		SLOT(onAreaItemChange(QListWidgetItem *))
		);
	connect(
		list_label_,
		SIGNAL(customContextMenuRequested(const QPoint &)),
		this,
		SLOT(labelListPopupMenu(const QPoint &))
		);
	connect(
		list_images_widget_,
		SIGNAL(itemDoubleClicked(QListWidgetItem *)),
		this,
		SLOT(selectImage(QListWidgetItem *))
		);
	connect(
		action_delete_area_,
		SIGNAL(triggered()),
		this,
		SLOT(deleteArea())
		);
	connect(
		action_edit_area_,
		SIGNAL(triggered()),
		this,
		SLOT(editArea())
		);
	connect(
		action_set_color_,
		SIGNAL(triggered()),
		this,
		SLOT(setLabelColor())
		);
	connect(
		action_toggle_priority_,
		SIGNAL(triggered()),
		this,
		SLOT(toggleLabelPriority())
		);
	connect(
		action_delete_label_,
		SIGNAL(triggered()),
		this,
		SLOT(removeLabel())
		);
	connect(
		image_holder_,
		SIGNAL(selectionStarted()),
		this,
		SLOT(onSelectionStarted())
		);
	connect(
		&image_description_form_,
		SIGNAL(descriptionSet(QString)),
		this,
		SLOT(setDescription(QString))
		);
	connect(
		image_holder_,
		SIGNAL(imageScaled()),
		this,
		SLOT(onImageScaled())
		);
	connect(
		image_holder_,
		SIGNAL(areaEdited()),
		this,
		SLOT(onAreaEdit())
		);
	connect(
		&options_form_,
		SIGNAL(optionsSet()),
		this,
		SLOT(onOptionsSet())
		);


	image_holder_->setBoundingBoxList(&list_bounding_box_);
	image_holder_->setPolygonList(&list_polygon_);
	image_holder_->setLabelColorList(&list_label_colors_);
	image_holder_->setMainLabelNum(&main_label_);
	image_holder_->setImage(image_);
}

ImageLabeler::~ImageLabeler()
{
	delete action_quit_;
	delete action_open_labeled_image_;
	delete action_open_image_;
	delete action_open_images_;
	delete action_load_legend_;
	delete action_save_legend_;
	delete action_save_segmented_;
	delete action_save_labels_;
	delete action_view_normal_;
	delete action_view_segmented_;
	delete action_undo_;
	delete action_redo_;
	delete action_bound_box_tool_;
	delete action_polygon_tool_;
	delete action_tagging_tool_;
	delete action_add_description_;
	delete action_options_;
	delete action_about_;
	delete action_help_content_;

	delete menu_file_;
	delete menu_view_;
	delete menu_edit_;
	delete menu_help_;

	delete menu_bar_;

	delete action_delete_area_;
	delete action_edit_area_;

	delete popup_area_list_;

	delete action_toggle_priority_;
	delete action_set_color_;
	delete action_delete_label_;

	delete popup_label_list_;

	delete image_;
	delete image_holder_;

	delete button_add_label_;
	delete button_remove_label_;
	delete button_bound_box_tool_;
	delete button_polygon_tool_;
	delete button_tagging_tool_;
	delete button_clear_selection_tool_;
	delete button_generate_colors_;
	delete button_delete_all_labels_;
	delete button_next_image_;
	delete button_prev_image_;

	delete button_confirm_selection_;

	delete label_list_areas_;
	delete label_toolbox_;
	delete label_list_images_;
	delete list_areas_;
	delete list_label_;
	delete list_images_widget_;

	delete layout_toolbox_;
	delete layout_right_;
	delete layout_center_buttons_;
	delete layout_frame_image_;
	delete layout_center_;
	delete layout_labelbox_buttons_;
	delete layout_labelbox_;
	delete layout_left_;
	delete layout_main_;

	delete frame_labelbox_;
	delete frame_toolbox_;
	delete frame_image_;
	delete frame_center_;

	delete central_widget_;
	//delete current_image_;

	if (pure_data_) {
		delete[] *pure_data_;
		delete pure_data_;
	}

	delete list_images_;
}

void
ImageLabeler::addImage(QString *anImage)
{
	QListWidgetItem *newItem = new QListWidgetItem;

	QString itemText = QString("%1: %2").
		arg(list_images_widget_->count()).
		arg(getFilenameFromPath(anImage));
	newItem->setText(itemText);

	list_images_widget_->addItem(newItem);
	list_images_->append(*anImage);
}

void
ImageLabeler::addLabel()
{
	QListWidgetItem *newItem = new QListWidgetItem;

	QString label;
	int itemNum = list_label_->count();
	label.append(QString("%1: ").arg(itemNum));

	if (itemNum) {
		newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
		label.append("New label");
	}
	else {
		newItem->setFlags(
				Qt::ItemIsUserCheckable | Qt::ItemIsSelectable |
				Qt::ItemIsEnabled
				);
		label.append("BACKGROUND");
	}
	newItem->setText(label);

	QPixmap iconPix = QPixmap(20, 20);
	QColor color;
	if (0 != itemNum)
		color = Qt::white;
	else
		color = Qt::black;
	iconPix.fill(color);
	QIcon icon(iconPix);
	list_label_colors_.append(color.rgb());

	newItem->setIcon(icon);

	list_label_->addItem(newItem);
	list_label_->setItemSelected(newItem, true);
	label_ID_ = list_label_->count() - 1;

	unsaved_data_ = 1;
}

void
ImageLabeler::addLabel(
	int aLabelID,
	bool isMain,
	QString aLabel
)
{
	QListWidgetItem *newItem = new QListWidgetItem;

	if (0 == aLabelID) {
		aLabel = QString("BACKGROUND");
		newItem->setFlags(
				Qt::ItemIsUserCheckable | Qt::ItemIsSelectable |
				Qt::ItemIsEnabled
				);
	}

	QString label;
	label.append(QString("%1: %2").
		arg(aLabelID).
		arg(aLabel)
		);

	/* TODO: check if there is another main label and make it common */
	if (isMain) {
		main_label_ = aLabelID;
	}

	QPixmap iconPix = QPixmap(20, 20);
	QColor color;
	if (0 != aLabelID)
		color = Qt::white;
	else
		color = Qt::black;
	iconPix.fill(color);
	QIcon icon(iconPix);
	list_label_colors_.append(color.rgb());

	newItem->setIcon(icon);

	newItem->setText(label);
	newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
	list_label_->addItem(newItem);
	list_label_->setItemSelected(newItem, true);

	unsaved_data_ = 1;
}

void
ImageLabeler::editLabel(QListWidgetItem *anItem)
{
	QString label = anItem->text();
	int itemRow = list_label_->row(anItem);

	QString prefix = QString("%1: ").arg(itemRow);
	if (-1 != label.indexOf(prefix)) {
		return;
		/* NOTREACHED */
	}

	label.prepend(QString("%1: ").arg(itemRow));

	if (main_label_ == itemRow) {
		label.append(" #main");
	}

	list_label_->blockSignals(true);
	anItem->setText(label);
	list_label_->blockSignals(false);

	unsaved_data_ = 1;
}

void
ImageLabeler::removeLabel()
{
	if (0 == list_label_->count()) {
		return;
		/* NOTREACHED */
	}

	//QListWidgetItem *current = list_label_->currentItem();
	/* we need to keep BACKGROUND category */
	if (label_ID_ < 1) {
		return;
		/* NOTREACHED */
	}

	if (list_label_->count() <= label_ID_ ||
		list_label_colors_.count() <= label_ID_) {
		return;
		/* NOTREACHED */
	}
	list_label_->takeItem(label_ID_);
	list_label_colors_.takeAt(label_ID_);

	unsaved_data_ = 1;
}

void
ImageLabeler::setLabelID(
	QListWidgetItem *anItem
)
{
	Q_UNUSED(anItem)

	if (!list_label_->count()) {
		return;
		/* NOTREACHED */
	}

	label_ID_ = list_label_->row(anItem);
}
void
ImageLabeler::addBBoxArea(
	int anID,
	BoundingBox aBBox,
	int itemID
)
{
	QListWidgetItem *newItem = new QListWidgetItem;

	if (-1 == itemID)
		itemID = list_areas_->count();

	QString label;
	label.append(QString("%1: ").arg(itemID));

	label.append(QString("BBox #%1; ").arg(anID));
	label.append(QString("LabelID: %1; ").arg(aBBox.label_ID_));
	label.append(
		QString("data:%1;%2;%3;%4; ").
		arg(aBBox.rect.topLeft().x()).
		arg(aBBox.rect.topLeft().y()).
		arg(aBBox.rect.width()).
		arg(aBBox.rect.height())
		);

	newItem->setText(label);
	//newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
	list_areas_->insertItem(itemID, newItem);
	list_areas_->setItemSelected(newItem, true);
}

void
ImageLabeler::addPolyArea(
	int aPolyID,
	Polygon aPoly,
	int itemID
)
{
	QListWidgetItem *newItem = new QListWidgetItem;

	if (-1 == itemID)
		itemID = list_areas_->count();

	QString label;
	label.append(QString("%1: ").arg(itemID));

	label.append(QString("Poly #%1; ").arg(aPolyID));
	label.append(QString("LabelID: %1; ").arg(aPoly.label_ID_));
	label.append("points:");
	for (int i = 0; i < aPoly.poly.count(); i++) {
		label.append(
			QString("%1;%2;").
			arg(aPoly.poly.point(i).x()).
			arg(aPoly.poly.point(i).y())
			);
	}

	newItem->setText(label);
	//newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
	list_areas_->insertItem(itemID, newItem);
	list_areas_->setItemSelected(newItem, true);
}

void
ImageLabeler::editArea()
{
	bool oldState = list_areas_->blockSignals(true);
	if (!list_areas_->currentItem() || !list_areas_->count()) {
		return;
		/* NOTREACHED */
	}

	QListWidgetItem *current = list_areas_->currentItem();

	old_area_string_ = current->text();
	current->setFlags(current->flags() | Qt::ItemIsEditable);
	list_areas_->editItem(current);
	list_areas_->blockSignals(oldState);
}

void
ImageLabeler::onAreaItemChange(QListWidgetItem *anItem)
{
	list_areas_->blockSignals(true);
	QString areaString = anItem->text();
	int oldID = -1;
	if (-1 != areaString.indexOf("Poly")) {
		Polygon *poly = new Polygon;
		*poly = polyFromString(&areaString, &oldID);

		if (-1 < poly->label_ID_ && !poly->poly.isEmpty() &&
			-1 < oldID) {
			list_polygon_.takeAt(oldID);
			list_polygon_.insert(oldID, poly);
		}
		else
			anItem->setText(old_area_string_);
	}
	else if (-1 != areaString.indexOf("BBox")) {
		BoundingBox *bbox = new BoundingBox;
		*bbox = BBoxFromString(&areaString, &oldID);

		if (-1 < bbox->label_ID_ && -1 < oldID) {
			list_bounding_box_.takeAt(oldID);
			list_bounding_box_.insert(oldID, bbox);
		}
		else
			anItem->setText(old_area_string_);
	}
	else {
		showWarning(tr("record format is corrupted, try again"));
		anItem->setText(old_area_string_);
	}

	anItem->setFlags(anItem->flags() ^ Qt::ItemIsEditable);
	list_areas_->blockSignals(false);
	image_holder_->update();

	unsaved_data_ = 1;
}


void
ImageLabeler::onAreaEdit()
{
	if (!list_areas_->count() ||
		-1 == image_holder_->focusedSelection()) {
		//showWarning(tr("You haven't added any label"));
		return;
		/* NOTREACHED */
	}

	int figureID = image_holder_->focusedSelection();
	Figure figure = image_holder_->focusedSelectionType();

	for (int i = 0; i < list_areas_->count(); i++) {
		QListWidgetItem *item = list_areas_->item(i);
		QString text = item->text();
		if (RectFigure == figure && -1 != text.indexOf("BBox")) {
			bool ok = 0;
			int num = getNumFromString(&text, "BBox #", ";", &ok);
			if (ok && num == figureID) {
				list_areas_->takeItem(i);
				addBBoxArea(num, *list_bounding_box_.at(num), i);
			}
		}
		else if (PolyFigure == figure && -1 != text.indexOf("Poly")) {
			bool ok = 0;
			int num = getNumFromString(&text, "Poly #", ";", &ok);
			if (ok && num == figureID) {
				list_areas_->takeItem(i);
				addPolyArea(num, *list_polygon_.at(num), i);
			}
		}
	}

	unsaved_data_ = 1;
}

void
ImageLabeler::deleteArea()
{
	if (!list_areas_->currentItem() || !list_areas_->count()) {
		return;
		/* NOTREACHED */
	}

	QString text = list_areas_->currentItem()->text();

	bool ok = 0;
	//int labelID = getNumFromString(&text, "LabelID:", ";", &ok);

//	if (!ok) {
//		return;
//		/* NOTREACHED */
//	}

	/*
	 * 0 - bbox
	 * 1 - poly
	 */
	QString shape;
	if (-1 != text.indexOf("BBox"))
		shape = QString("BBox");
	else if (-1 != text.indexOf("Poly"))
		shape = QString("Poly");
	else {
		return;
		/* NOTREACHED */
	}

	int areaNum = getNumFromString(&text, "#", ";", &ok);

	if (!ok) {
		return;
		/* NOTREACHED */
	}

	int currentItemRow = list_areas_->row(list_areas_->currentItem());

	/* changing all shapes(depends on current) which are next in the list */
	for (int i = list_areas_->count() - 1; i > currentItemRow; i--) {
		QListWidgetItem item = *(list_areas_->item(i));
		QString newText = item.text();

		if (-1 == newText.indexOf(shape))
			continue;

		int num = getNumFromString(&newText, "#", ";", &ok);
		num--;
		QString numString = QString("%1").arg(num);

		int numPos = newText.indexOf("#") + 1;
		newText.replace(numPos, numString.size(), numString);

		list_areas_->takeItem(i);
		list_areas_->insertItem(i, newText);
	}

	list_areas_->takeItem(currentItemRow);
	if (shape == "BBox")
		list_bounding_box_.removeAt(areaNum);
	else
		list_polygon_.removeAt(areaNum);

	image_holder_->update();

	unsaved_data_ = 1;
}

void
ImageLabeler::toggleLabelPriority()
{
	if (!list_label_->count()) {
		return;
		/* NOTREACHED */
	}

	QListWidgetItem *item = list_label_->currentItem();

	/* because we need to keep BACKGROUND category */
	if (0 == list_label_->row(item)) {
		return;
		/* NOTREACHED */
	}

	int itemRow = list_label_->row(item);
	QString text = item->text();

	/* cleaning previous " #main" mark */
	if (-1 != main_label_) {
		QListWidgetItem *lastMain = list_label_->item(main_label_);
		QString lastMainText = lastMain->text();
		int mainPos = lastMainText.indexOf(" #main");
		lastMainText = lastMainText.mid(0, mainPos);
		list_label_->blockSignals(true);
		lastMain->setText(lastMainText);
		list_label_->blockSignals(false);
	}

	if (main_label_ == itemRow) {
		int mainPos = text.indexOf(" #main");
		text = text.mid(0, mainPos);
		main_label_ = -1;
	}
	else {
		text.append(" #main");
		main_label_ = list_label_->row(item);
	}

	list_label_->blockSignals(true);
	item->setText(text);
	list_label_->blockSignals(false);

	image_holder_->update();

	unsaved_data_ = 1;
}

void
ImageLabeler::getImagesFromDir(const QDir &dir)
{
	/* avoiding freezing during recursive search for files */
	QApplication::processEvents();

	if (interrupt_search_) {
		clearAll();
		return;
	}

	QStringList filenameFilter;
	filenameFilter <<
		"*.jpeg" <<
		"*.jpg" <<
		"*.gif" <<
		"*.png" <<
		"*.bmp" <<
		"*.tiff"
		;

	QStringList listImages =
		dir.entryList(filenameFilter, QDir::Files);

	foreach (QString file, listImages) {
		QString itemText = dir.absoluteFilePath(file);
		addImage(&itemText);
		//list_label_->setItemSelected(newItem, true);
		//list_images_->append(dir.absoluteFilePath(file));
	}

	QStringList listDir = dir.entryList(QDir::Dirs);
	foreach (QString subdir, listDir) {
		if ("." == subdir || ".." == subdir)
			continue;
		getImagesFromDir(QDir(dir.absoluteFilePath(subdir)));
	}
}

void
ImageLabeler::nextImage()
{
	if (list_images_->isEmpty()) {
		return;
		/* NOTREACHED */
	}

	if (askForUnsavedData()) {
		return;
		/* NOTREACHED */
	}

	if (list_images_widget_->count() - 1 == image_ID_) {
		current_image_ = list_images_->at(0);
		image_ID_ = 0;
	}
	else {
		image_ID_ ++;
		current_image_ = list_images_->at(image_ID_);
	}

	list_images_widget_->setCurrentRow(image_ID_);

	if (current_image_.isEmpty()) {
		return;
		/* NOTREACHED */
	}

	QString winTitle;
	winTitle.append("ImageLabeler - ");
	winTitle.append(current_image_);
	setWindowTitle(winTitle);

	image_->load(current_image_);
	image_holder_->resize(image_->size());
	image_holder_->setPixmap(*image_);
	list_bounding_box_.clear();
	list_polygon_.clear();
	list_areas_->clear();
	image_holder_->clearAll();

	//setWindowTitle(tr("ImageLabeler"));
}

void
ImageLabeler::prevImage()
{
	if (!list_images_widget_->count()) {
		return;
		/* NOTREACHED */
	}

	if (askForUnsavedData()) {
		return;
		/* NOTREACHED */
	}

	if (!image_ID_) {
		image_ID_ = list_images_widget_->count() - 1;
		current_image_ = list_images_->at(image_ID_);
	}
	else {
		image_ID_--;
		current_image_ = list_images_->at(image_ID_);
	}

	list_images_widget_->setCurrentRow(image_ID_);

	QString winTitle;
	winTitle.append("ImageLabeler - ");
	winTitle.append(current_image_);
	setWindowTitle(winTitle);

	image_->load(current_image_);
	image_holder_->resize(image_->size());
	image_holder_->setPixmap(*image_);
	list_bounding_box_.clear();
	list_polygon_.clear();
	list_areas_->clear();
	image_holder_->clearAll();

	//setWindowTitle(tr("ImageLabeler"));
}

void
ImageLabeler::saveAllInfo()
{
	if (!list_images_widget_->count()) {
		showWarning("You have not opened any image yet");
		return;
		/* NOTREACHED */
	}

	/* ------------------------------------------------------------------------
	 * XML part
	 */
	QDomDocument doc(tr("ImageLabeler"));
	QDomElement root = doc.createElement(tr("pixelwise_labeling"));
	doc.appendChild(root);

	QDomElement image = doc.createElement(tr("image"));
	root.appendChild(image);

	QDomText pathToImage = doc.createTextNode(current_image_);
	image.appendChild(pathToImage);

	if (!segmented_image_.isEmpty()) {
		QDomElement segmentedImage = doc.createElement(tr("segmented"));
		root.appendChild(segmentedImage);

		QDomText pathToSegmented = doc.createTextNode(segmented_image_);
		segmentedImage.appendChild(pathToSegmented);
	}

	QDomElement description = doc.createElement(tr("description"));
	root.appendChild(description);

	QDomText descriptionText = doc.createTextNode(image_description_);
	description.appendChild(descriptionText);

	legendToXml(&doc, &root);

	objectsToXml(&doc, &root);

	setPureData();
	QDomElement pureData = doc.createElement(tr("pure_data"));
	QSize imageSize = image_->size();
	QString pixelValues;

	for (int i = 0; i < imageSize.height(); i++) {
		for (int j = 0; j < imageSize.width(); j++) {
			pixelValues.append(QString("%1").arg(pure_data_[i][j]));
			//pixelValues.append(QString(""));
		}
		pixelValues.append("\n");
	}

	QDomText pureDataText = doc.createTextNode(pixelValues);
	pureData.appendChild(pureDataText);
	root.appendChild(pureData);

	QString xml = doc.toString();
	/* ------------------------------------------------------------------------
	 * XML part ends
	 */

	QFileDialog fileDialog(0, tr("Save all info"));
	fileDialog.setAcceptMode(QFileDialog::AcceptSave);
	fileDialog.setDefaultSuffix("dat");
	fileDialog.setFileMode(QFileDialog::AnyFile);
	QString dir = getDirFromPath(&current_image_);

	/* altering the name of a new file */
	QString newFileName = alterFileName(current_image_, "_labeled");

	fileDialog.selectFile(newFileName);

	fileDialog.setDirectory(dir);

	QString filename;
	if (fileDialog.exec()) {
		filename = fileDialog.selectedFiles().last();
	}
	else {
		//showWarning(tr("Can not open file dialog"));
		return;
		/* NOTREACHED */
	}

	if (filename.isEmpty()) {
		return;
		/* NOTREACHED */
	}

	QFile file(filename);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
		showWarning(tr("Can not open file for writing"));
		return;
		/* NOTREACHED */
	}

	file.write(xml.toLocal8Bit());
	file.close();

	unsaved_data_ = 0;
}

void
ImageLabeler::saveSegmentedPicture()
{
	if (list_bounding_box_.isEmpty() && list_polygon_.isEmpty()) {
		return;
		/* NOTREACHED */
	}

	setPureData();

//	QString suffix = *current_image_;
//	int dotPos = suffix.lastIndexOf(".");
//	suffix.mid(dotPos + 1, suffix.size() - dotPos - 1);

	QFileDialog fileDialog(0, tr("Save segmented picture"));
	fileDialog.setAcceptMode(QFileDialog::AcceptSave);
	fileDialog.setDefaultSuffix("png");
	fileDialog.setFileMode(QFileDialog::AnyFile);
	QString dir = getDirFromPath(&current_image_);

	/* altering the name of a new file */
	QString newFileName = alterFileName(current_image_, "_segmented");

	fileDialog.selectFile(newFileName);

	fileDialog.setDirectory(dir);

	QString filename;
	if (fileDialog.exec()) {
		filename = fileDialog.selectedFiles().last();
	}
	else {
		return;
		/* NOTREACHED */
	}

	QSize imageSize = image_holder_->pixmap()->size();
	QImage newImage(imageSize, QImage::Format_RGB32);
	bool generateColorsFlag = auto_color_generation_;
	bool flag = 0;


	/* checking if all the colors are are different from white(default) */
	if (!generateColorsFlag) {
		for (int i = 1; i < list_label_->count(); i++) {
			if (list_label_colors_.at(i) == 0xffffffff && !flag)
				flag = 1;
			else if (list_label_colors_.at(i) == 0xffffffff && flag) {
				QMessageBox msgBox;
				msgBox.setText(tr("There are few labels with default white color."));
				msgBox.setInformativeText(tr("Do you want to generate all colors automatically? Otherwise you'll have to do it manually."));
				msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
				msgBox.setDefaultButton(QMessageBox::Yes);
				msgBox.setIcon(QMessageBox::Question);
				int ret = msgBox.exec();

				if (QMessageBox::Yes == ret) {
					generateColorsFlag = 1;
					break;
				}
				else {
					return;
					/* NOTREACHED */
				}
			}
		}
	}

	/* generating colors for labels */
	if (list_label_colors_.count() < list_label_->count() ||
		generateColorsFlag) {
		generateColors();
	}

	for (int i = 0; i < imageSize.height(); i++)
		for (int j = 0; j < imageSize.width(); j++) {
			newImage.setPixel(j, i, list_label_colors_.at(pure_data_[i][j]));
		}

	if (!newImage.save(filename, "png", 100)) {
		showWarning(tr("An error occurred while saving the segmented image"));
		return;
		/* NOTREACHED */
	}

	segmented_image_ = filename;
	action_view_segmented_->setEnabled(true);
}

void
ImageLabeler::saveLegend()
{
	if (!list_label_->count()) {
			showWarning("You have not added any label yet");
			return;
			/* NOTREACHED */
		}

		/* ------------------------------------------------------------------------
		 * XML part
		 */
		QDomDocument doc(tr("ImageLabeler"));
		QDomElement root = doc.createElement(tr("root"));
		doc.appendChild(root);

		legendToXml(&doc, &root);

		QString xml = doc.toString();
		/* ------------------------------------------------------------------------
		 * XML part ends
		 */

		QFileDialog fileDialog(0, tr("Save legend"));
		fileDialog.setAcceptMode(QFileDialog::AcceptSave);
		fileDialog.setDefaultSuffix("dat");
		fileDialog.setFileMode(QFileDialog::AnyFile);
		QString dir = getDirFromPath(&current_image_);

		/* altering the name of a new file */
		QString newFileName = alterFileName(current_image_, "_legend");

		fileDialog.selectFile(newFileName);

		fileDialog.setDirectory(dir);

		QString filename;
		if (fileDialog.exec()) {
			filename = fileDialog.selectedFiles().last();
		}
		else {
			//showWarning(tr("Can not open file dialog"));
			return;
			/* NOTREACHED */
		}

		if (filename.isEmpty()) {
			return;
			/* NOTREACHED */
		}

		QFile file(filename);
		if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
			showWarning(tr("Can not open file for writing"));
			return;
			/* NOTREACHED */
		}

		file.write(xml.toLocal8Bit());
		file.close();
}

void
ImageLabeler::loadInfo()
{
	if (askForUnsavedData()) {
		return;
		/* NOTREACHED */
	}

	QFileDialog fileDialog(0, tr("Load file with info"));
	fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
	fileDialog.setDefaultSuffix("dat");
	fileDialog.setFileMode(QFileDialog::AnyFile);

	QString filename;
	if (fileDialog.exec()) {
		filename = fileDialog.selectedFiles().last();
	}
	else {
		//showWarning(tr("Can not open file dialog"));
		return;
		/* NOTREACHED */
	}

	QDomDocument doc("Image Labeler");
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly)) {
		showWarning(tr("Can not open such file"));
		return;
		/* NOTREACHED */
	}

	QString errMsg;
	if (!doc.setContent(&file, &errMsg)) {
		showWarning(errMsg);
		file.close();
		return;
		/* NOTREACHED */
	}

	file.close();

	clearAll();
	list_label_->clear();
	enableTools();

	/* getting all info */
	QDomElement elements = doc.documentElement();
	QDomNode rootNode = elements.firstChild();
	QString string;

	while(!rootNode.isNull()) {
		QDomElement element = rootNode.toElement();
		if(!element.isNull()) {
			/* path to the image */
			if (element.tagName() == "image") {
				string = element.text();
				if (string.isEmpty()) {
					showWarning(
						tr(
						"The file with data doesn't contain path to the image"
						)
						);
					return;
					/* NOTREACHED */
				}
				addImage(&string);
				current_image_ = string;
				image_ID_ = list_images_widget_->count() - 1;
				list_images_widget_->setCurrentRow(image_ID_);

				QString winTitle;
				winTitle.append("ImageLabeler - ");
				winTitle.append(current_image_);
				setWindowTitle(winTitle);

				image_->load(current_image_);
				image_holder_->resize(image_->size());
				image_holder_->setPixmap(*image_);
			}
			/* path to the segmented image */
			if (element.tagName() == "segmented") {
				string = element.text();
				if (string.isEmpty()) {
					continue;
				}
				segmented_image_ = string;
				action_view_segmented_->setEnabled(true);
			}
			/* image description */
			else if (element.tagName() == "description" &&
				!element.text().isEmpty()) {
				image_description_ = element.text();
			}
			/* legend */
			else if (element.tagName() == "legend") {
				loadLegendFromNode(&element);
			}
			/* objects */
			else if (element.tagName() == "objects") {
				QDomNode subNode = element.firstChild();
				QDomElement subElement;

				while(!subNode.isNull()) {
					subElement = subNode.toElement();

					if (subElement.isNull() || subElement.text().isEmpty()) {
						subNode = subNode.nextSibling();
						continue;
					}

					string = subElement.attribute("id");
					bool ok = 1;
					int id = string.toInt(&ok, 10);

					if (!ok) {
						qDebug() <<
							"loadInfo: "
							"poly id format is corrupted";
						subNode = subNode.nextSibling();
						continue;
					}

					string = subElement.text();

					if (subElement.tagName() == "bbox") {
						setBBoxFromData(&string, &id);
					}
					if (subElement.tagName() == "poly") {
						setPolyFromData(&string, &id);
					}

					subNode = subNode.nextSibling();
				}
			}
		}
		rootNode = rootNode.nextSibling();
	}
}

void
ImageLabeler::loadImage()
{
	if (askForUnsavedData()) {
		return;
		/* NOTREACHED */
	}

	QFileDialog fileDialog(0, tr("Load image"));
	fileDialog.setFileMode(QFileDialog::AnyFile);
	QString filename;

	if (fileDialog.exec()) {
		filename = fileDialog.selectedFiles().last();
	}
	else {
		//showWarning(tr("Could not open file dialog"));
		return;
		/* NOTREACHED */
	}

	if (filename.isEmpty()) {
		return;
		/* NOTREACHED */
	}

	clearAllTool();


	addImage(&filename);

	if (!list_images_widget_->count()) {
		return;
		/* NOTREACHED */
	}

	current_image_ = filename;
	image_ID_ = list_images_widget_->count() - 1;
	list_images_widget_->setCurrentRow(image_ID_);

	QString winTitle;
	winTitle.append("ImageLabeler - ");
	winTitle.append(current_image_);
	setWindowTitle(winTitle);

	image_->load(current_image_);
	image_holder_->resize(image_->size());
	image_holder_->setPixmap(*image_);

	enableTools();
}

void
ImageLabeler::loadImages()
{
	if (askForUnsavedData()) {
		return;
		/* NOTREACHED */
	}

	QFileDialog fileDialog(0, tr("Load images"));
	fileDialog.setFileMode(QFileDialog::Directory);
	QString dirName("");

	if (fileDialog.exec()) {
		/* TODO: make it possible to select multiple folders */
		dirName = fileDialog.selectedFiles().last();
	}
	else {
		//showWarning(tr("Could not open file dialog"));
		return;
		/* NOTREACHED */
	}

	clearAllTool();

	QWidget *searchInProgress = new QWidget(0);
	searchInProgress->setWindowTitle(tr("Loading images"));
	QLabel *info = new QLabel(searchInProgress);
	info->setText(
		tr("Program is looking for all image files in your directory recursively."));
	QPushButton *cancel = new QPushButton(tr("Cancel"), searchInProgress);
	connect(cancel, SIGNAL(clicked()), this, SLOT(interruptSearch()));
	QVBoxLayout *layout = new QVBoxLayout(searchInProgress);
	searchInProgress->setLayout(layout);
	layout->addWidget(info);
	layout->addWidget(cancel);
	searchInProgress->adjustSize();
	searchInProgress->move(QApplication::desktop()->screen()->rect().center() - rect().center());
	searchInProgress->show();

	getImagesFromDir(QDir(dirName));

	cancel->disconnect();
	searchInProgress->hide();
	delete info;
	delete cancel;
	delete layout;
	delete searchInProgress;

	if (interrupt_search_) {
		interrupt_search_ = 0;
		return;
		/* NOTREACHED */
	}

	if (!list_images_widget_->count()) {
		showWarning(tr("The folder you selected contains no images"));
		return;
		/* NOTREACHED */
	}

	current_image_ = list_images_->at(0);
	image_ID_ = 0;
	list_images_widget_->setCurrentRow(image_ID_);

	QString winTitle;
	winTitle.append("ImageLabeler - ");
	winTitle.append(current_image_);
	setWindowTitle(winTitle);

	image_->load(current_image_);
	image_holder_->resize(image_->size());
	image_holder_->setPixmap(*image_);

	enableTools();
}

void
ImageLabeler::loadLegendFromFile()
{
	QFileDialog fileDialog(0, tr("Load legend"));
	fileDialog.setFileMode(QFileDialog::AnyFile);
	QString filename;

	if (fileDialog.exec()) {
		filename = fileDialog.selectedFiles().last();
	}
	else {
		//showWarning(tr("Could not open file dialog"));
		return;
		/* NOTREACHED */
	}

	QDomDocument doc("Image Labeler");
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly)) {
		showWarning(tr("Can not open such file"));
		return;
		/* NOTREACHED */
	}

	QString errMsg;
	if (!doc.setContent(&file, &errMsg)) {
		showWarning(errMsg);
		file.close();
		return;
		/* NOTREACHED */
	}

	file.close();

	list_label_->clear();

	/* getting legend */
	QDomElement elements = doc.documentElement();
	QDomNode rootNode = elements.firstChild();
	QString string;

	while(!rootNode.isNull()) {
		QDomElement element = rootNode.toElement();
		if(!element.isNull()) {
			if (element.tagName() == "legend") {
				loadLegendFromNode(&element);
			}
		}
		rootNode = rootNode.nextSibling();
	}
}

void
ImageLabeler::loadLegendFromNode(QDomElement *anElement)
{
	if (!anElement) {
		return;
		/* NOTREACHED */
	}
	QDomNode subNode = anElement->firstChild();
	QDomElement subElement;
	QString string;
	int id = -1;
	bool isMain;
	uint color = 0xff000000;

	while(!subNode.isNull()) {
		subElement = subNode.toElement();

		if (!subElement.isNull() && !subElement.text().isEmpty()) {
			string = subElement.attribute("id");
			bool ok = 0;
			id = string.toInt(&ok, 10);

			if (!ok) {
				qDebug() <<
					"loadLegendFromNode: "
					"label id format is corrupted";
				subNode = subNode.nextSibling();
				continue;
			}

			string = subElement.attribute("isMain");
			isMain = string.toInt(&ok, 2);

			if (!ok) {
				qDebug() <<
					"loadLegendFromNode: "
					"label isMain flag format is corrupted";
				subNode = subNode.nextSibling();
				continue;
			}

			string = subElement.attribute("color");
			color = string.toUInt(&ok, 16);

			if (!ok) {
				qDebug() <<
					"loadLegendFromNode: "
					"label color format is corrupted";
				subNode = subNode.nextSibling();
				continue;
			}

			string = subElement.text();

			addLabel(id, isMain, string);
			setLabelColor(id, color);
		}

		subNode = subNode.nextSibling();
	}
}

void
ImageLabeler::legendToXml(QDomDocument *aDoc, QDomElement *aRoot)
{
	QDomElement legend = aDoc->createElement(tr("legend"));
	aRoot->appendChild(legend);

	/* storing all labels made by user */
	int labelCount = list_label_->count();
	for (int i = 0; i < labelCount; i++) {
		QDomElement label = aDoc->createElement(tr("label"));
		label.setAttribute("color", QString("%1").arg(list_label_colors_.at(i), 0, 16));
		label.setAttribute("id", i);

		QString priority;
		if (main_label_ == i)
			priority.append("1");
		else
			priority.append("0");
		label.setAttribute("isMain", priority);

		QString labelText = list_label_->item(i)->text();

		/* removing the number prefix of label */
		if (-1 != labelText.indexOf(QString("%1: ").arg(i))) {
			labelText = labelText.mid(3, labelText.size() - 3);
		}

		QDomText labelName = aDoc->createTextNode(labelText);
		label.appendChild(labelName);
		legend.appendChild(label);
	}

	/* in case we have no labels */
	if (0 == labelCount) {
		QDomElement label = aDoc->createElement(tr("label"));
		label.setAttribute(tr("id"), -1);
		legend.appendChild(label);
	}
}

void
ImageLabeler::objectsToXml(QDomDocument *aDoc, QDomElement *aRoot)
{
	QDomElement objects = aDoc->createElement(tr("objects"));
	aRoot->appendChild(objects);

	/* rects first */
	for (int i = 0; i < list_bounding_box_.size(); i++) {
		QDomElement rectData = aDoc->createElement(tr("bbox"));

		rectData.setAttribute("id", list_bounding_box_.at(i)->label_ID_);

		QRect rect = list_bounding_box_.at(i)->rect.normalized();

		QString rectDataString =
			QString("%1;%2;%3;%4;").
				arg(rect.x()).
				arg(rect.y()).
				arg(rect.width()).
				arg(rect.height());

		QDomText rectDataText = aDoc->createTextNode(rectDataString);
		rectData.appendChild(rectDataText);
		objects.appendChild(rectData);
	}

	/* polys next */
	for (int i = 0; i < list_polygon_.size(); i++) {
		QDomElement polyData = aDoc->createElement(tr("poly"));

		polyData.setAttribute("id", list_polygon_.at(i)->label_ID_);

		QPolygon poly = list_polygon_.at(i)->poly;

		QString polyDataString;
		for (int j = 0; j < poly.count(); j++)
			polyDataString.append(
				QString("%1;%2;").
					arg(poly.point(j).x()).
					arg(poly.point(j).y())
				);


		QDomText polyDataText = aDoc->createTextNode(polyDataString);
		polyData.appendChild(polyDataText);
		objects.appendChild(polyData);
	}
}

void
ImageLabeler::generateColors()
{
	int labelCount = list_label_->count();

	if (!labelCount) {
		showWarning(tr("you have not added any labels yet"));
		return;
		/* NOTREACHED */
	}

	int coeff = (0xff / labelCount) * 3;
	//QList< uint > colors;
	list_label_colors_.clear();
	list_label_colors_.append(0);
	uchar red = 0xff;
	uchar green = 0xff;
	uchar blue = 0xff;
	uchar iterationColor = coeff;
	uint color = 0xffffffff;
	int j = 1;
	for (int i = 1; i < labelCount; i++) {
		if (6 == j) {
			iterationColor += coeff;
			j = 1;
		}

		if (5 == j) {
			red = 0xff - iterationColor;
			green = 0xff - iterationColor;
			blue = 0xff;
		}
		else if (4 == j) {
			red = 0xff - iterationColor;
			green = 0xff;
			blue = 0xff - iterationColor;
		}
		else if (3 == j) {
			red = 0xff - iterationColor;
			green = 0xff;
			blue = 0xff;
		}
		else if (2 == j) {
			red = 0xff;
			green = 0xff - iterationColor;
			blue = 0xff;
		}
		else if (1 == j){
			red = 0xff;
			green = 0xff;
			blue = 0xff - iterationColor;
		}
		j++;
		color = red + (green * 0x100) + (blue * 0x10000) + 0xff000000;

		int itemNo = list_label_colors_.count();

		QPixmap iconPix = QPixmap(20, 20);
		iconPix.fill(color);
		QIcon icon(iconPix);

		list_label_->item(itemNo)->setIcon(icon);
		list_label_colors_.append(color);
	}
}

void
ImageLabeler::setBBoxFromData(
	QString *aBBoxData,
	int *ID
)
{
	BoundingBox *bbox = new BoundingBox;
	*bbox = BBoxFromData(aBBoxData);
	if (!bbox->rect.isValid() || !ID) {
		return;
		/* NOTREACHED */
	}

	bbox->label_ID_ = *ID;
	list_bounding_box_.append(bbox);
	addBBoxArea(list_bounding_box_.count() - 1, *bbox);
}

BoundingBox
ImageLabeler::BBoxFromData(
	QString *aBBoxData
)
{
	qDebug() << *aBBoxData;
	BoundingBox bbox;
	QString buffer;
	bbox.rect.setRect(-1, -1, -1, -1);
	int startPos = 0;
	bool ok = 1;

	for (int i = 0; i < aBBoxData->size(); i++) {
		if (';' != aBBoxData->at(i))
			continue;

		buffer = aBBoxData->mid(startPos, i - startPos);

		int bboxData = buffer.toInt(&ok, 10);
		if (!ok) {
			qDebug() <<
				"BBoxFromData: "
				"bbox format is corrupted";
			break;
		}

		if (-1 == bbox.rect.x()) {
			bbox.rect.setX(bboxData);
			bbox.rect.setWidth(-1);
		}
		else if (-1 == bbox.rect.y()) {
			bbox.rect.setY(bboxData);
			bbox.rect.setHeight(-1);
		}
		else if (-1 == bbox.rect.width()) {
			bbox.rect.setWidth(bboxData);
		}
		else if (-1 == bbox.rect.height()) {
			bbox.rect.setHeight(bboxData);
		}

		startPos = i + 1;
	}

	if (!bbox.rect.isValid()) {
		qDebug() <<
			"BBoxFromData: "
			"bbox format is corrupted";
		bbox.rect.setRect(-1, -1, -1, -1);
	}
	else if (!ok) {
		bbox.rect.setRect(-1, -1, -1, -1);
	}

	return bbox;
}

BoundingBox
ImageLabeler::BBoxFromString(
	QString *aString,
	int *oldID
)
{
	BoundingBox bbox;
	bbox.label_ID_ = -1;
	*oldID = -1;

	if (!aString) {
		return bbox;
		/* NOTREACHED */
	}

	if (-1 == aString->indexOf("BBox")) {
		return bbox;
		/* NOTREACHED */
	}

	/* getting bbox id in the list(it cannot be changed) */
	bool ok = 0;
	int bboxID = getNumFromString(aString, "BBox #", ";", &ok);
	if (!ok || bboxID <= -1) {
		qDebug() <<
			"BBoxFromString: bboxID is corrupted";
		return bbox;
		/* NOTREACHED */
	}

	/* getting new label id */
	int labelID = getNumFromString(aString, "LabelID: ", ";", &ok);
	if (!ok || labelID <= -1) {
		showWarning(
			tr("new LabelID is wrong, area can not be changed")
				);
		return bbox;
		/* NOTREACHED */
	}

	/* getting new points */
	int pointsPos = aString->indexOf("data:") + 5;
	int pointsLen = aString->size() - pointsPos;
	if (pointsLen <= 0) {
		showWarning(
			tr("new data is wrong, area can not be changed")
				);
		return bbox;
		/* NOTREACHED */
	}
	QString pointsData = aString->mid(pointsPos, pointsLen);
	bbox = BBoxFromData(&pointsData);
	bbox.label_ID_ = labelID;


	*oldID = bboxID;
	return bbox;
}

void
ImageLabeler::setPolyFromData(
	QString *aPolyData,
	int *ID
)
{
	Polygon *poly = new Polygon;
	*poly = polyFromData(aPolyData);

	if (poly->poly.isEmpty() || !ID) {
		return;
		/* NOTREACHED */
	}

	poly->label_ID_ = *ID;
	list_polygon_.append(poly);
	addPolyArea(list_polygon_.count() - 1, *poly);
}

Polygon
ImageLabeler::polyFromData(
	QString *aPolyData
)
{
	Polygon poly;
	poly.label_ID_ = -1;
	QPoint point;
	QString buffer;
	int startPos = 0;
	bool ok = 1;
	bool evenFlag = 0;

	for (int i = 0; i < aPolyData->size(); i++) {
		if (';' != aPolyData->at(i))
			continue;

		buffer = aPolyData->mid(startPos, i - startPos);

		int polyCoor = buffer.toInt(&ok, 10);
		if (!ok) {
			qDebug() <<
				"polyFromData: "
				"poly format is corrupted";
			break;
		}

		if (!evenFlag) {
			point.setX(polyCoor);
			evenFlag = 1;
		}
		else {
			point.setY(polyCoor);
			poly.poly.append(point);
			evenFlag = 0;
		}
		startPos = i + 1;
	}

	if (evenFlag) {
		qDebug() <<
			"polyFromData: "
			"poly format is corrupted";
		poly.poly.clear();
	}
	else if (!ok) {
		poly.poly.clear();
	}

	return poly;
}

Polygon
ImageLabeler::polyFromString(
	QString *aString,
	int *oldID
)
{
	Polygon poly;
	poly.label_ID_ = -1;
	*oldID = -1;

	if (!aString) {
		return poly;
		/* NOTREACHED */
	}

	if (-1 == aString->indexOf("Poly")) {
		return poly;
		/* NOTREACHED */
	}

	/* getting poly id in the list(it cannot be changed) */
	bool ok = 0;
	int polyID = getNumFromString(aString, "Poly #", ";", &ok);
	if (!ok || polyID <= -1) {
		qDebug() <<
			"polyFromString: poly ID is corrupted";
		return poly;
		/* NOTREACHED */
	}

	/* getting new label id */
	int labelID = getNumFromString(aString, "LabelID: ", ";", &ok);
	if (!ok || labelID <= -1) {
		showWarning(
			tr("new LabelID is wrong, area can not be changed")
				);
		return poly;
		/* NOTREACHED */
	}

	/* getting new points */
	int pointsPos = aString->indexOf("points:") + 7;
	int pointsLen = aString->size() - pointsPos;
	if (pointsLen <= 0) {
		showWarning(
			tr("new points data is wrong, area can not be changed")
				);
		return poly;
		/* NOTREACHED */
	}
	QString pointsData = aString->mid(pointsPos, pointsLen);
	poly = polyFromData(&pointsData);
	poly.label_ID_ = labelID;


	*oldID = polyID;
	return poly;
}

void
ImageLabeler::showWarning(
		const QString text
)
{
	if (text.isEmpty()) {
		return;
		/* NOTREACHED */
	}

	QMessageBox msgBox;
	msgBox.setText(text);
	msgBox.setIcon(QMessageBox::Warning);
	msgBox.exec();
}

bool
ImageLabeler::askForUnsavedData()
{
	if ((!list_bounding_box_.isEmpty() ||
		!list_polygon_.isEmpty()) &&
		unsaved_data_)
	{
		QMessageBox msgBox;
		msgBox.setText(tr("There is some unsaved data"));
		msgBox.setInformativeText(tr("Do you want to save your progress?"));
		msgBox.setStandardButtons(
			QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
		msgBox.setDefaultButton(QMessageBox::Save);
		msgBox.setIcon(QMessageBox::Question);
		int ret = msgBox.exec();

		if (QMessageBox::Save == ret)
			saveAllInfo();
		else if (QMessageBox::Cancel == ret)
			return true;
	}
	return false;
}

void
ImageLabeler::setBoundingBoxTool(bool aButtonPressed)
{
	if (aButtonPressed)
		image_holder_->setTool(ImageHolder::BoundingBoxTool);
	else {
		image_holder_->setTool(ImageHolder::NoTool);
		image_holder_->clearLast();
	}
}

void
ImageLabeler::setPolygonTool(bool aButtonPressed)
{
	if (aButtonPressed) {
		image_holder_->setTool(ImageHolder::PolygonTool);
		image_holder_->setFocus();
	}
	else {
		image_holder_->setTool(ImageHolder::NoTool);
		image_holder_->clearLast();
	}
}

void
ImageLabeler::onSelectionStarted()
{
	button_confirm_selection_->setEnabled(true);
}

void
ImageLabeler::onImageScaled()
{

}

void
ImageLabeler::confirmSelection()
{
	if (!list_label_->count()) {
		showWarning(tr("You haven't added any label"));
		return;
		/* NOTREACHED */
	}

	image_holder_->confirmSelection();

	if (label_ID_ < 0)
		label_ID_ = 0;

	ImageHolder::Tool tool = image_holder_->tool();
	switch (tool) {
	case ImageHolder::BoundingBoxTool:
		list_bounding_box_.last()->label_ID_ = label_ID_;
		addBBoxArea(
			list_bounding_box_.count() - 1,
			*(list_bounding_box_.last())
			);
		break;
	case ImageHolder::PolygonTool:
		list_polygon_.last()->label_ID_ = label_ID_;
		addPolyArea(
			list_polygon_.count() - 1,
			*(list_polygon_.last())
			);
		break;
	default:
		break;
	}
	button_confirm_selection_->setEnabled(false);

	unsaved_data_ = 1;
}

void
ImageLabeler::clearAll()
{
	clearLabelList();
	list_areas_->clear();
	list_bounding_box_.clear();
	list_polygon_.clear();
	list_images_->clear();
	list_images_widget_->clear();
	main_label_ = -1;
	image_holder_->clearAll();
	segmented_image_.clear();
	action_view_normal_->setEnabled(false);
	action_view_segmented_->setEnabled(false);
}

void
ImageLabeler::clearAllTool()
{
	list_areas_->clear();
	list_bounding_box_.clear();
	list_polygon_.clear();
	main_label_ = -1;
	image_holder_->clearAll();
}

void ImageLabeler::clearLabelList()
{
	list_label_->clear();
	addLabel(0, false, "BACKGROUND");
	list_label_->item(0)->setFlags(
		Qt::ItemIsUserCheckable | Qt::ItemIsSelectable |
		Qt::ItemIsEnabled
		);
}

void
ImageLabeler::enableTools()
{
	action_save_labels_->setEnabled(true);
	action_save_segmented_->setEnabled(true);
	action_save_legend_->setEnabled(true);
	action_bound_box_tool_->setEnabled(true);
	action_polygon_tool_->setEnabled(true);
	action_add_description_->setEnabled(true);
	action_undo_->setEnabled(true);
	action_redo_->setEnabled(true);
	button_bound_box_tool_->setEnabled(true);
	button_polygon_tool_->setEnabled(true);
	button_add_label_->setEnabled(true);
	button_remove_label_->setEnabled(true);
	button_prev_image_->setEnabled(true);
	button_next_image_->setEnabled(true);
	button_clear_selection_tool_->setEnabled(true);
	button_generate_colors_->setEnabled(true);
	button_delete_all_labels_->setEnabled(true);
}

void
ImageLabeler::disableTools()
{
	action_save_labels_->setEnabled(false);
	action_save_segmented_->setEnabled(false);
	action_save_legend_->setEnabled(false);
	action_bound_box_tool_->setEnabled(false);
	action_polygon_tool_->setEnabled(false);
	action_add_description_->setEnabled(false);
	action_undo_->setEnabled(false);
	action_redo_->setEnabled(false);
	button_bound_box_tool_->setEnabled(false);
	button_polygon_tool_->setEnabled(false);
	button_add_label_->setEnabled(false);
	button_remove_label_->setEnabled(false);
	button_prev_image_->setEnabled(false);
	button_next_image_->setEnabled(false);
	button_clear_selection_tool_->setEnabled(false);
	button_generate_colors_->setEnabled(false);
	button_delete_all_labels_->setEnabled(false);
}

void
ImageLabeler::areaListPopupMenu(const QPoint &aPos)
{
	QPoint globalPos = list_areas_->mapToGlobal(aPos);
	QModelIndex index = list_areas_->indexAt(aPos);

	if (-1 == index.row()) {
		return;
		/* NOTREACHED */
	}

	list_areas_->item(index.row())->setSelected(true);

	popup_area_list_->exec(globalPos);
}

void
ImageLabeler::labelListPopupMenu(const QPoint &aPos)
{
	QPoint globalPos = list_label_->mapToGlobal(aPos);
	QModelIndex index = list_label_->indexAt(aPos);

	if (-1 == index.row() || !index.row()) {
		return;
		/* NOTREACHED */
	}

	list_label_->item(index.row())->setSelected(true);

	popup_label_list_->exec(globalPos);
}

void
ImageLabeler::setDescription(QString aDescription)
{
	image_description_ = aDescription;
	setWindowTitle(image_description_);
}

void
ImageLabeler::setPureData()
{
	/* initializing array */
	if (pure_data_) {
		delete[] *pure_data_;
		delete pure_data_;
	}

	QSize imageSize = image_->size();
	pure_data_ = new int *[imageSize.height()];
	if (!pure_data_) {
		return;
		/* NOTREACHED */
	}
	for (int i = 0; i < imageSize.height(); i++) {
		pure_data_[i] = new int[imageSize.width()];
		if (!pure_data_[i]) {
			return;
			/* NOTREACHED */
		}
	}

	int bboxCnt = list_bounding_box_.count();
	int polyCnt = list_polygon_.count();
	for (int i = 0; i < imageSize.height(); i++)
		for (int j = 0; j < imageSize.width(); j++) {
			pure_data_[i][j] = 0;
			/* bboxes first */
			for (int cnt = 0; cnt < bboxCnt; cnt++) {
				BoundingBox *bbox = list_bounding_box_.at(cnt);
				if (bbox->rect.contains(j, i)) {
					pure_data_[i][j] = bbox->label_ID_;
				}
			}
			/* polys next */
			for (int cnt = 0; cnt < polyCnt; cnt++) {
				Polygon *poly = list_polygon_.at(cnt);
				if (poly->poly.containsPoint(QPoint(j, i), Qt::OddEvenFill)) {
					pure_data_[i][j] = poly->label_ID_;
				}
			}
		}


}

void
ImageLabeler::setLabelColor()
{
	if (list_label_colors_.count() < list_label_->count()) {
		generateColors();
	}

	QListWidgetItem *current = list_label_->currentItem();

	int labelID = list_label_->row(current);
	QColor defaultColor;
	defaultColor.setRgb(list_label_colors_.at(labelID));
	QColor newColor = QColorDialog::getColor(
		defaultColor,
		list_label_
		);

	if (!newColor.isValid()) {
		return;
		/* NOTREACHED */
	}
	list_label_colors_.takeAt(labelID);
	list_label_colors_.insert(labelID, newColor.rgb());

	QPixmap iconPix = QPixmap(20, 20);
	iconPix.fill(newColor);
	QIcon icon(iconPix);

	current->setIcon(icon);
}

void
ImageLabeler::setLabelColor(int anID, QColor aColor)
{
	if (anID < 0) {
		return;
		/* NOTREACHED */
	}

	if (list_label_colors_.count() < list_label_->count()) {
		generateColors();
	}

	QListWidgetItem *item = list_label_->item(anID);
	list_label_colors_.takeAt(anID);
	list_label_colors_.insert(anID, aColor.rgb());

	QPixmap iconPix = QPixmap(20, 20);
	iconPix.fill(aColor);
	QIcon icon(iconPix);

	item->setIcon(icon);
}

void
ImageLabeler::onOptionsSet()
{
	auto_color_generation_ = options_form_.autoColorGeneration();
}

void
ImageLabeler::viewNormal()
{
	if (current_image_.isEmpty()) {
		return;
		/* NOTREACHED */
	}

	image_->load(current_image_);
	image_holder_->setPixmap(*image_);

	action_view_segmented_->setEnabled(true);
	action_view_normal_->setEnabled(false);
}

void
ImageLabeler::viewSegmented()
{
	if (segmented_image_.isEmpty()) {
		return;
		/* NOTREACHED */
	}

	image_->load(segmented_image_);
	image_holder_->setPixmap(*image_);

	action_view_segmented_->setEnabled(false);
	action_view_normal_->setEnabled(true);
}

void
ImageLabeler::interruptSearch()
{
	interrupt_search_ = 1;
}

void
ImageLabeler::selectImage(QListWidgetItem *anItem)
{
	if (!anItem || list_images_widget_->row(anItem) < 0)  {
		return;
		/* NOTREACHED */
	}

	image_ID_ = list_images_widget_->row(anItem);

	image_->load(list_images_->at(image_ID_));
	image_holder_->setPixmap(*image_);
	image_holder_->resize(image_->size());
}

void
ImageLabeler::resizeEvent (QResizeEvent *anEvent)
{
	QWidget::resizeEvent(anEvent);
}

void
ImageLabeler::mousePressEvent(QMouseEvent *anEvent)
{
	QWidget::mousePressEvent(anEvent);
}

void
ImageLabeler::keyPressEvent(QKeyEvent *anEvent)
{
	keyboard_modifier_ = anEvent->modifiers();

	if (Qt::Key_Left == anEvent->key() &&
		Qt::ControlModifier == keyboard_modifier_) {
		prevImage();
	}

	if (Qt::Key_Right == anEvent->key() &&
		Qt::ControlModifier == keyboard_modifier_) {
		nextImage();
	}

	if ((Qt::Key_Enter == anEvent->key() ||
		Qt::Key_Return == anEvent->key()) &&
	//	Qt::NoModifier == anEvent->modifiers() &&
		ImageHolder::NewSelection == image_holder_->state()) {
		confirmSelection();
	}

	if ((Qt::Key_Enter == anEvent->key() ||
		Qt::Key_Return == anEvent->key()) &&
	//	Qt::NoModifier == anEvent->modifiers() &&
		-1 != image_holder_->focusedSelection()) {
		image_holder_->clearFocusOnArea();
		image_holder_->clearEdition();
		image_holder_->update();
	}

	if (Qt::Key_Escape == anEvent->key()) {
		image_holder_->clearLast();
		image_holder_->clearFocusOnArea();
		image_holder_->clearEdition();
		image_holder_->update();
	}

	if (Qt::Key_Z == anEvent->key() &&
		Qt::ControlModifier == anEvent->modifiers()) {
		image_holder_->undo();
	}

	if (Qt::Key_Y == anEvent->key() &&
		Qt::ControlModifier == anEvent->modifiers()) {
		image_holder_->redo();
	}

	QWidget::keyPressEvent(anEvent);
}

void
ImageLabeler::wheelEvent(QWheelEvent *anEvent)
{
	/* zoomin */
	if (0 < anEvent->delta() &&
		Qt::ControlModifier == keyboard_modifier_) {
		image_holder_->scaleImage(ZoomIn, 1.1);
	}
	/* zoomout */
	else if (anEvent->delta() < 0 &&
		Qt::ControlModifier == keyboard_modifier_) {
		image_holder_->scaleImage(ZoomOut, 1.1);
	}
}

/*
 *
 */