void Matrix::clearSelection()
{
    if (d_view_type == ImageView)
        return;

	QItemSelectionModel *selModel = d_table_view->selectionModel();
	if (!selModel || !selModel->hasSelection())
		return;

	const QItemSelectionRange sel = selModel->selection()[0];
	int startRow = sel.top();
	int endRow = sel.bottom();
	int startCol = sel.left();
	int endCol = sel.right();
	double *buffer = d_matrix_model->dataCopy(startRow, endRow, startCol, endCol);
	if (buffer){
    	d_undo_stack->push(new MatrixUndoCommand(d_matrix_model, Clear, startRow, endRow, startCol, endCol, buffer, tr("Clear Selection")));
    	emit modifiedWindow(this);
    	modifiedData(this);
	} else if (ignoreUndo()){
		d_matrix_model->clear(startRow, endRow, startCol, endCol);
		emit modifiedWindow(this);
		modifiedData(this);
	}
}
void Matrix::deleteSelectedColumns()
{
	QItemSelectionModel *selModel = d_table_view->selectionModel();
	if (!selModel || !selModel->hasSelection())
		return;

	int startCol = -1;
	int count = 0;
	int cols = numCols();
	for (int i=0; i<cols; i++){
		if (selModel->isColumnSelected(i, QModelIndex())){
			if (startCol < 0)
				startCol = i;
			++count;
		}
	}
	if (startCol < 0 || !count)
		return;

	double *buffer = d_matrix_model->dataCopy(0, numRows() - 1, startCol, startCol + count - 1);
	if (buffer){
    	d_undo_stack->push(new MatrixDeleteColsCommand(d_matrix_model, startCol, count, buffer, tr("Delete Columns") + " " +
                      QString::number(startCol + 1) + " - " + QString::number(startCol + count)));
    	emit modifiedWindow(this);
	} else if (ignoreUndo()){
		d_matrix_model->removeColumns(startCol, count);
		d_table_view->reset();
		emit modifiedWindow(this);
	}
}
void Matrix::importImage(const QString& fn)
{
	QImage image(fn);
    if (image.isNull())
        return;

	x_start = 0.0;
	x_end = image.width() - 1.0;
	y_start = 0.0;
	y_end = image.height() - 1.0;

	double *buffer = d_matrix_model->dataCopy();
	if (buffer){
    	d_undo_stack->push(new MatrixSetImageCommand(d_matrix_model, image, d_view_type, 0,
							numRows() - 1, 0, numCols() - 1, buffer, tr("Import Image") + " \"" + fn + "\""));
		emit modifiedWindow(this);
		modifiedData(this);
	} else if (ignoreUndo()){
		d_matrix_model->setImage(image);
		setViewType(ImageView, false);
		displayImage(image);
		emit modifiedWindow(this);
		modifiedData(this);
	}

	setWindowLabel(fn);
}
void Matrix::fft(bool inverse)
{
	double *buffer = d_matrix_model->dataCopy();
	if (buffer){
		QString commandText = inverse ? tr("Inverse FFT") : tr("Forward FFT");
    	d_undo_stack->push(new MatrixFftCommand(inverse, d_matrix_model, 0, numRows() - 1,
							0, numCols() - 1, buffer, commandText));
		emit modifiedWindow(this);
	} else if (ignoreUndo()){
		d_matrix_model->fft(inverse);
		emit modifiedWindow(this);
	}
}
bool Matrix::muParserCalculate(int startRow, int endRow, int startCol, int endCol)
{
	double *buffer = d_matrix_model->dataCopy(startRow, endRow, startCol, endCol);
	if (buffer){
		d_undo_stack->push(new MatrixUndoCommand(d_matrix_model, MuParserCalculate, startRow, endRow,
												startCol, endCol, buffer, tr("Calculate Values")));
		emit modifiedWindow(this);
		return true;
	} else if(ignoreUndo()){
		d_matrix_model->muParserCalculate(startRow, endRow, startCol, endCol);
		emit modifiedWindow(this);
		return true;
	}
	return false;
}
void Matrix::importImage(const QImage& image)
{
	if (image.isNull())
        return;

	double *buffer = d_matrix_model->dataCopy();
	if (buffer){
    	d_undo_stack->push(new MatrixSetImageCommand(d_matrix_model, image, d_view_type, 0,
							numRows() - 1, 0, numCols() - 1, buffer, tr("Import Image")));
		emit modifiedWindow(this);
	} else if (ignoreUndo()){
		d_matrix_model->setImage(image);
		setViewType(ImageView, false);
		displayImage(image);
		emit modifiedWindow(this);
	}
}
bool Matrix::calculate(int startRow, int endRow, int startCol, int endCol, bool forceMuParser)
{
	if (QString(scriptEnv->name()) == "muParser" || forceMuParser)
		return muParserCalculate(startRow, endRow, startCol, endCol);

	double *buffer = d_matrix_model->dataCopy(startRow, endRow, startCol, endCol);
	if (buffer){
    	d_undo_stack->push(new MatrixUndoCommand(d_matrix_model, Calculate, startRow, endRow,
												startCol, endCol, buffer, tr("Calculate Values")));
		emit modifiedWindow(this);
		return true;
	} else if(ignoreUndo()){
		d_matrix_model->calculate(startRow, endRow, startCol, endCol);
		emit modifiedWindow(this);
		return true;
	}
	return false;
}
void Matrix::setDimensions(int rows, int cols)
{
	int r = numRows();
	int c = numCols();
	if (r == rows && c == cols)
		return;

	if(rows*cols > r*c && !d_matrix_model->canResize(rows, cols))
		return;

	double *buffer = d_matrix_model->dataCopy();
	if (buffer)
		d_undo_stack->push(new MatrixSetSizeCommand(d_matrix_model, QSize(r, c), QSize(rows, cols), buffer,
						tr("Set Dimensions") + " " + QString::number(rows) + "x" + QString::number(cols)));
	else if(ignoreUndo()){
		d_matrix_model->setDimensions(rows, cols);
		resetView();
	}
	emit modifiedWindow(this);
}
void Matrix::pasteSelection()
{
     if (d_view_type == ImageView)
        return;

	QString text = QApplication::clipboard()->text();
	if (text.isEmpty())
		return;

	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

	QStringList linesList = text.split(applicationWindow()->endOfLine(), QString::SkipEmptyParts);
	int rows = linesList.size();
	if (!rows)
		return;

	int cols = linesList[0].split("\t").count();
	for (int i = 1; i < rows; i++){
		int aux = linesList[i].split("\t").count();
		if (aux > cols)
            cols = aux;
	}

	int topRow = 0, leftCol = 0;
	QItemSelectionModel *selModel = d_table_view->selectionModel();
	if (selModel->hasSelection()){
		QItemSelectionRange sel = selModel->selection()[0];
		topRow = sel.top();
		leftCol = sel.left();
	}

	int oldRows = numRows();
	int bottomRow = topRow + rows - 1;
	if (bottomRow > oldRows - 1)
		bottomRow = oldRows - 1;

	int oldCols = numCols();
	int rightCol = leftCol + cols - 1;
	if (rightCol > oldCols - 1)
		rightCol = oldCols - 1;

	double *clipboardBuffer = (double *)malloc(rows*cols*sizeof(double));
	if (!clipboardBuffer){
		QMessageBox::critical(this, tr("QtiPlot") + " - " + tr("Memory Allocation Error"),
		tr("Not enough memory, operation aborted!"));
		QApplication::restoreOverrideCursor();
		return;
	}

	QLocale locale = this->locale(); //Better use QLocale::system() ??
	int cell = 0;
	for(int i = 0; i < rows; i++){
		QStringList cells = linesList[i].split("\t");
		int size = cells.count();
		for(int j = 0; j<cols; j++){
			if (j >= size){
                clipboardBuffer[cell++] = GSL_NAN;
				continue;
			}
			bool numeric = true;
			double value = locale.toDouble(cells[j], &numeric);
			if (numeric)
				clipboardBuffer[cell++] = value;
			else
				clipboardBuffer[cell++] = GSL_NAN;
		}
	}

	QApplication::restoreOverrideCursor();

	double *backupBuffer = d_matrix_model->dataCopy(topRow, bottomRow, leftCol, rightCol);
	if (backupBuffer){
		d_undo_stack->push(new MatrixPasteCommand(d_matrix_model, topRow, bottomRow,
					leftCol, rightCol, clipboardBuffer, rows, cols, backupBuffer, oldRows,
					oldCols, tr("Paste")));
		emit modifiedWindow(this);
	} else if (ignoreUndo()){
		d_matrix_model->pasteData(clipboardBuffer, topRow, leftCol, rows, cols);
		emit modifiedWindow(this);
	}
}