[qet] [1907] Reworked the way project saving is presented to users.

[ Thread Index | Date Index | More lists.tuxfamily.org/qet Archives ]


Revision: 1907
Author:   xavier
Date:     2012-07-13 09:21:19 +0200 (Fri, 13 Jul 2012)
Log Message:
-----------
Reworked the way project saving is presented to users.

Modified Paths:
--------------
    trunk/sources/projectview.cpp
    trunk/sources/projectview.h
    trunk/sources/qetdiagrameditor.cpp
    trunk/sources/qetdiagrameditor.h
    trunk/sources/qetproject.cpp
    trunk/sources/qetproject.h

Added Paths:
-----------
    trunk/sources/closediagramsdialog.cpp
    trunk/sources/closediagramsdialog.h
    trunk/sources/qetresult.cpp
    trunk/sources/qetresult.h

Added: trunk/sources/closediagramsdialog.cpp
===================================================================
--- trunk/sources/closediagramsdialog.cpp	                        (rev 0)
+++ trunk/sources/closediagramsdialog.cpp	2012-07-13 07:21:19 UTC (rev 1907)
@@ -0,0 +1,313 @@
+/*
+	Copyright 2006-2012 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "closediagramsdialog.h"
+#include "diagram.h"
+#include "qeticons.h"
+
+/**
+	Construct a dialog showing \a diagrams.
+	@param parent Parent QWidget
+*/
+CloseDiagramsDialog::CloseDiagramsDialog(const QList<Diagram *> &diagrams, QWidget *parent) :
+	QDialog(parent),
+	diagrams_list_(diagrams),
+	answer_(-1)
+{
+	initWidgets();
+	initLayout();
+}
+
+/**
+	Destructor
+*/
+CloseDiagramsDialog::~CloseDiagramsDialog() {
+}
+
+/**
+	@return the user answer once the dialog has been executed.
+*/
+int CloseDiagramsDialog::answer() const {
+	return(answer_);
+}
+
+/**
+	@return what the user wants to do with \a diagram
+	@see CloseDiagramsDialog::Actions
+*/
+int CloseDiagramsDialog::actionForDiagram(Diagram *diagram) {
+	if (QCheckBox *checkbox = getCheckBoxForDiagram(diagram)) {
+		if (!diagram -> undoStack().isClean()) {
+			return(checkbox -> isChecked() ? Save : DoNotSave);
+		} else if (!diagram -> wasWritten()) {
+			return(checkbox -> isChecked() ? Save : Remove);
+		}
+	}
+	return(Unknown);
+}
+
+/**
+	@return the list of diagrams for which users have chosen the \a action
+	action.
+*/
+QList<Diagram *> CloseDiagramsDialog::diagramsByAction(Actions action) {
+	QList<Diagram *> diagrams;
+	foreach (Diagram *diagram, diagrams_list_) {
+		if (actionForDiagram(diagram) == action) {
+			diagrams << diagram;
+		}
+	}
+	return(diagrams);
+}
+
+/**
+	Initialize widgets.
+*/
+void CloseDiagramsDialog::initWidgets() {
+	setWindowTitle(tr("Fermer un projet", "window title"));
+	
+	connect(&show_mapper_, SIGNAL(mapped(int)), this, SLOT(requireShowDiagram(int)));
+	
+	// label when diagrams were modified
+	informative_label1_ = new QLabel(
+		tr(
+			"Les sch\351mas ci-dessous contiennent des modifications non "
+			"enregistr\351es. Faut-il les sauvegarder ?",
+			"informative label"
+		)
+	);
+	informative_label1_ -> setWordWrap(true);
+	
+	// label when no diagrams were modified
+	informative_label2_ = new QLabel(tr("Voulez-vous enregistrer le projet ?", "informative label"));
+	informative_label2_ -> setWordWrap(true);
+	
+	// header labels
+	QLabel *state_label = new QLabel(tr("\311tat", "column header"));
+	QLabel *title_label = new QLabel(tr("Sch\351ma", "column header"));
+	
+	// header checkbox in order to check/uncheck all diagrams
+	all_checkbox_ = new QCheckBox(tr("Action",  "column header"));
+	all_checkbox_ -> setChecked(true);
+	connect(all_checkbox_, SIGNAL(stateChanged(int)), this, SLOT(topCheckBoxChangedState(int)));
+	
+	// spacers inserted in the header row
+	QSpacerItem *spacer1 = new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum);
+	QSpacerItem *spacer2 = new QSpacerItem(25, 10, QSizePolicy::Preferred, QSizePolicy::Minimum);
+	
+	buttons_ = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Discard | QDialogButtonBox::Cancel);
+	connect(buttons_, SIGNAL(clicked(QAbstractButton *)), this, SLOT(storeAnswer(QAbstractButton *)));
+	
+	// widget layout
+	diagrams_list_layout_ = new QGridLayout();
+	diagrams_list_layout_ -> addWidget(state_label, 0, 1, 1, 1, Qt::AlignCenter);
+	diagrams_list_layout_ -> addItem(spacer1, 0, 2);
+	diagrams_list_layout_ -> addWidget(title_label, 0, 3, 1, 1, Qt::AlignCenter);
+	diagrams_list_layout_ -> addItem(spacer2, 0, 4);
+	diagrams_list_layout_ -> addWidget(all_checkbox_, 0, 5, 1, 1, Qt::AlignCenter);
+	
+	// widget
+	diagrams_list_widget_ = new QWidget();
+	diagrams_list_widget_ -> setLayout(diagrams_list_layout_);
+	diagrams_list_widget_ -> setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
+	
+	// scroll area
+	diagrams_list_area_ = new QScrollArea();
+	diagrams_list_area_ -> setWidgetResizable(true);
+	diagrams_list_area_ -> setFrameStyle(QFrame::Plain | QFrame::NoFrame);
+	
+	loadDiagramsList();
+	diagrams_list_area_ -> setWidget(diagrams_list_widget_);
+}
+
+/**
+	Initialize layout.
+*/
+void CloseDiagramsDialog::initLayout() {
+	setMinimumSize(650, 340);
+	
+	QVBoxLayout *vlayout0 = new QVBoxLayout();
+	vlayout0 -> addWidget(informative_label1_);
+	vlayout0 -> addWidget(informative_label2_);
+	vlayout0 -> addWidget(diagrams_list_area_);
+	vlayout0 -> addWidget(buttons_);
+	setLayout(vlayout0);
+}
+
+/**
+	Create a visual list of all modified diagrams.
+*/
+void CloseDiagramsDialog::loadDiagramsList() {
+	if (diagrams_list_.count()) {
+		int row_id = 1;
+		foreach (Diagram *diagram, diagrams_list_) {
+			addDiagram(diagram, row_id);
+			++ row_id;
+		}
+		informative_label2_ -> setVisible(false);
+	} else {
+		informative_label1_ -> setVisible(false);
+		diagrams_list_area_ -> setVisible(false);
+	}
+}
+
+/**
+	Add \a diagram to the \a row_id row of the visual list.
+*/
+void CloseDiagramsDialog::addDiagram(Diagram *diagram, int row_id) {
+	QLabel *diagram_title = new QLabel(diagramTitle(diagram));
+	QPushButton *diagram_show = new QPushButton(QET::Icons::ZoomOriginal, ""); // tr("Afficher ce sch\351ma", "button label")
+	show_mapper_.setMapping(diagram_show, row_id - 1);
+	connect(diagram_show, SIGNAL(released()), &show_mapper_, SLOT(map()));
+	QLabel *diagram_status = new QLabel(diagramStatus(diagram));
+	QCheckBox *diagram_checkbox = new QCheckBox(diagramAction(diagram));
+	diagram_checkbox -> setChecked(true);
+	connect(diagram_checkbox, SIGNAL(stateChanged(int)), this, SLOT(lambdaCheckBoxChangedState(int)));
+	
+	diagrams_list_layout_ -> addWidget(diagram_show,       row_id, 0, 1, 1, Qt::AlignCenter);
+	diagrams_list_layout_ -> addWidget(diagram_title,      row_id, 1, 1, 1, Qt::AlignCenter);
+	diagrams_list_layout_ -> addWidget(diagram_status,     row_id, 3, 1, 1, Qt::AlignCenter);
+	diagrams_list_layout_ -> addWidget(diagram_checkbox,   row_id, 5, 1, 1, Qt::AlignCenter);
+}
+
+/**
+	@return the action checkbox for \a diagram, or 0 if no adequate checkbox could be found.
+*/
+QCheckBox *CloseDiagramsDialog::getCheckBoxForDiagram(Diagram *diagram) {
+	int diagram_index = diagrams_list_.indexOf(diagram);
+	if (diagram_index == -1) return(0);
+	
+	// We add 1 because there is one row dedicated to column headers;
+	// 4 is the column containing checkboxes, see initWidgets().
+	QLayoutItem *item = diagrams_list_layout_ -> itemAtPosition(diagram_index + 1, 5);
+	if (!item) return(0);
+	
+	QWidget *widget = item -> widget();
+	if (!widget) return(0);
+	
+	return(static_cast<QCheckBox *>(widget));
+}
+
+/**
+	@return the title for \a diagram
+*/
+QString CloseDiagramsDialog::diagramTitle(Diagram *diagram) {
+	if (!diagram -> title().isEmpty()) {
+		return(diagram -> title());
+	}
+	return(tr("Sch\351ma sans titre", "fallback diagram title"));
+}
+
+/**
+	@return a string describing the status of \a diagram
+*/
+QString CloseDiagramsDialog::diagramStatus(Diagram *diagram) {
+	if (!diagram) return(QString());
+	if (!diagram -> undoStack().isClean()) {
+		return(tr("Modifi\351", "diagram status"));
+	} else if (!diagram -> wasWritten()) {
+		return(tr("Ajout\351, non modifi\351", "diagram status"));
+	} else {
+		return(QString());
+	}
+}
+
+/**
+	@return a string describing the effect of saving \a diagram (e.g. "Save" or
+	"Keep").
+*/
+QString CloseDiagramsDialog::diagramAction(Diagram *diagram) {
+	if (!diagram) return(QString());
+	if (!diagram -> undoStack().isClean()) {
+		return(tr("Enregistrer", "diagram action"));
+	} else if (!diagram -> wasWritten()) {
+		return(tr("Conserver", "diagram action"));
+	} else {
+		return(QString());
+	}
+}
+
+/**
+	Adjust the state of the header checkbox when a diagram checkbox was
+	switched to \a new_state.
+*/
+void CloseDiagramsDialog::lambdaCheckBoxChangedState(int new_state) {
+	bool state = new_state;
+	
+	bool all_same_state = true;
+	foreach (Diagram *diagram, diagrams_list_) {
+		if (QCheckBox *checkbox = getCheckBoxForDiagram(diagram)) {
+			if (checkbox -> isChecked() != state) {
+				all_same_state = false;
+				break;
+			}
+		}
+	}
+	
+	all_checkbox_ -> blockSignals(true);
+	if (all_same_state) {
+		all_checkbox_ -> setTristate(false);
+		all_checkbox_ -> setChecked(state);
+	} else {
+		all_checkbox_ -> setTristate(true);
+		all_checkbox_ -> setCheckState(Qt::PartiallyChecked);
+	}
+	all_checkbox_ -> blockSignals(false);
+	all_checkbox_ -> update();
+}
+
+/**
+	Adjust diagram checkboxes when the header checkbox was switched to \a
+	new_state.
+*/
+void CloseDiagramsDialog::topCheckBoxChangedState(int new_state) {
+	setCheckedAll((bool)new_state);
+}
+
+/**
+	Set all diagram checkboxes to the checked (true) or unchecked (false)
+	state.
+*/
+void CloseDiagramsDialog::setCheckedAll(bool checked) {
+	foreach (Diagram *diagram, diagrams_list_) {
+		if (QCheckBox *checkbox = getCheckBoxForDiagram(diagram)) {
+			if (checkbox -> isChecked() != checked) {
+				checkbox -> blockSignals(true);
+				checkbox -> setChecked(checked);
+				checkbox -> blockSignals(false);
+			}
+		}
+	}
+}
+
+/**
+	Find the diagram at \a diagram_index and emts the showDiagram() signal with
+	it.
+*/
+void CloseDiagramsDialog::requireShowDiagram(int diagram_index) {
+	Diagram *diagram = diagrams_list_.value(diagram_index);
+	if (!diagram) return;
+	emit(showDiagram(diagram));
+}
+
+/**
+	Store the user answer when the dialog is validated or rejected.
+*/
+void CloseDiagramsDialog::storeAnswer(QAbstractButton *button) {
+	answer_ = buttons_ -> buttonRole(button);
+	accept();
+}

Added: trunk/sources/closediagramsdialog.h
===================================================================
--- trunk/sources/closediagramsdialog.h	                        (rev 0)
+++ trunk/sources/closediagramsdialog.h	2012-07-13 07:21:19 UTC (rev 1907)
@@ -0,0 +1,92 @@
+/*
+	Copyright 2006-2012 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef CLOSE_DIAGRAMS_DIALOG_H
+#define CLOSE_DIAGRAMS_DIALOG_H
+#include <QDialog>
+#include <QSignalMapper>
+class QAbstractButton;
+class QDialogButtonBox;
+class QCheckBox;
+class QLabel;
+class QPushButton;
+class Diagram;
+class QGridLayout;
+class QScrollArea;
+
+/**
+	This class represents a dialog asking users whether they want to save
+	their modified project when it is being closed and what they wish to save
+	in it.
+*/
+class CloseDiagramsDialog : public QDialog {
+	Q_OBJECT
+	public:
+	enum Actions {
+		Unknown,
+		Save,
+		DoNotSave,
+		Remove
+	};
+	
+	// Constructors, destructor
+	public:
+	CloseDiagramsDialog(const QList<Diagram *> &diagrams, QWidget *parent = 0);
+	virtual ~CloseDiagramsDialog();
+	private:
+	CloseDiagramsDialog(const CloseDiagramsDialog &);
+	
+	// methods
+	public:
+	int answer() const;
+	int actionForDiagram(Diagram *);
+	QList<Diagram *> diagramsByAction(Actions);
+	
+	private:
+	void initWidgets();
+	void initLayout();
+	void loadDiagramsList();
+	void addDiagram(Diagram *, int);
+	QCheckBox *getCheckBoxForDiagram(Diagram *);
+	QString diagramTitle(Diagram *);
+	QString diagramStatus(Diagram *);
+	QString diagramAction(Diagram *);
+	
+	signals:
+	void showDiagram(Diagram *);
+	
+	private slots:
+	void lambdaCheckBoxChangedState(int);
+	void topCheckBoxChangedState(int);
+	void setCheckedAll(bool);
+	void requireShowDiagram(int);
+	void storeAnswer(QAbstractButton *);
+	
+	// attributes
+	private:
+	QList<Diagram *> diagrams_list_;     ///< List of (modified or newly added) diagrams displayed by the dialog
+	QLabel *informative_label1_;         ///< Informative label when there are modified diagrams
+	QLabel *informative_label2_;         ///< Informative label when there is no modified diagram
+	QCheckBox *all_checkbox_;            ///< Header checkbox to check/uncheck all other checkboxes
+	QScrollArea *diagrams_list_area_;    ///< Scroll area to make the diagrams visual list fit in the dialog
+	QWidget *diagrams_list_widget_;      ///< Scrolled widget
+	QGridLayout *diagrams_list_layout_;  ///< Layout used to list diagrams
+	QDialogButtonBox *buttons_;          ///< Buttons for users to input their final choice
+	int answer_;                         ///< Reflects the user answer once the diagram has been executed
+	QSignalMapper show_mapper_;          ///< Signal mapper for the "show diagram" buttons to work
+};
+#endif

Modified: trunk/sources/projectview.cpp
===================================================================
--- trunk/sources/projectview.cpp	2012-07-10 00:11:12 UTC (rev 1906)
+++ trunk/sources/projectview.cpp	2012-07-13 07:21:19 UTC (rev 1907)
@@ -18,6 +18,7 @@
 #include "projectview.h"
 #include "qetproject.h"
 #include "configdialog.h"
+#include "closediagramsdialog.h"
 #include "projectconfigpages.h"
 #include "diagramview.h"
 #include "diagram.h"
@@ -94,6 +95,36 @@
 }
 
 /**
+	@return A list containing child diagrams matching provided \a options.
+*/
+QList<Diagram *> ProjectView::getDiagrams(ProjectSaveOptions options) {
+	QList<Diagram *> selection;
+	if ((options & AllDiagrams) == AllDiagrams) {
+		selection << project_ -> diagrams();
+	} else {
+		Diagram *current = 0;
+		if (DiagramView *view = currentDiagram()) {
+			current = view -> diagram();
+		}
+		if (options & CurrentDiagram) {
+			if (current) selection << current;
+		} else if (options & AllDiagramsButCurrent) {
+			selection = project_ -> diagrams();
+			selection.removeOne(current);
+		}
+	}
+	
+	if (options & ModifiedDiagramsOnly) {
+		foreach (Diagram *diagram, selection) {
+			if (!diagram -> undoStack().isClean() || !diagram -> wasWritten()) continue;
+			selection.removeOne(diagram);
+		}
+	}
+	
+	return(selection);
+}
+
+/**
 	@return le schema actuellement active
 */
 DiagramView *ProjectView::currentDiagram() const {
@@ -106,35 +137,7 @@
 	@param qce Le QCloseEvent decrivant l'evenement
 */
 void ProjectView::closeEvent(QCloseEvent *qce) {
-	// si la vue n'est pas liee a un projet, on ferme directement
-	if (!project_) {
-		qce -> accept();
-		emit(projectClosed(this));
-		return;
-	}
-	
-	// si le projet est comme neuf et n'est pas enregistre, on ferme directement
-	if (!project_ -> projectWasModified() && project_ -> filePath().isEmpty()) {
-		qce -> accept();
-		emit(projectClosed(this));
-		return;
-	}
-	
-	bool can_close_project = true;
-	if (!tryClosing()) {
-		// l'utilisateur a refuse la fermeture du projet - on arrete la
-		can_close_project = false;
-	} else {
-		// a ce stade, l'utilisateur a accepte la fermeture de tout le contenu du projet
-		if (!project_ -> filePath().isEmpty()) {
-			// si le projet a un chemin specifie, on l'enregistre et on le ferme
-			can_close_project = project_ -> write();
-		} else {
-			// l'utilisateur n'enregistre pas son projet
-			can_close_project = true;
-		}
-	}
-	
+	bool can_close_project = tryClosing();
 	if (can_close_project) {
 		qce -> accept();
 		emit(projectClosed(this));
@@ -152,34 +155,46 @@
 	@see tryClosingDiagrams()
 */
 bool ProjectView::tryClosing() {
+	if (!project_) return(true);
+	
+	// First step: require external editors closing -- users may either cancel
+	// the whole closing process or save (and therefore add) content into this
+	// project. Of course, they may also discard them.
 	if (!tryClosingElementEditors()) {
 		return(false);
 	}
 	
-	if (!tryClosingDiagrams()) {
-		return(false);
+	// Check how different the current situation is from a brand new, untouched project
+	if (project_ -> filePath().isEmpty() && !project_ -> projectWasModified()) {
+		return(true);
 	}
 	
-	// a ce stade, l'utilisateur a accepte de fermer tous les editeurs
-	// d'elements et tous les schemas
-	// on regarde s'il reste du contenu dans le projet
-	if (project_ -> projectWasModified() && project_ -> filePath().isEmpty()) {
-		// si oui, on propose a l'utilisateur d'enregistrer le projet
-		QMessageBox::StandardButton answer = QET::MessageBox::question(
-			this,
-			tr("Enregistrer le projet en cours ?", "message box title"),
-			QString(tr("Voulez-vous enregistrer le projet ?", "message box content")),
-			QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
-			QMessageBox::Cancel
-		);
-		if (answer == QMessageBox::Cancel) {
-			return(false);
-		} else if (answer == QMessageBox::Yes) {
-			return(save());
-		}
+	// Second step: users are presented with a dialog that enables them to
+	// choose whether they want to:
+	//   - cancel the closing process,
+	//   - discard all modifications,
+	//   - or specify what is to be saved, i.e. they choose whether they wants to
+	// save/give up/remove diagrams considered as modified.
+	int user_input = tryClosingDiagrams();
+	if (user_input == QDialogButtonBox::RejectRole) {
+		return(false); // the closing process was cancelled
+	} else if (user_input == QDialogButtonBox::DestructiveRole) {
+		return(true); // all modifications were discarded
 	}
 	
-	return(true);
+	// Check how different the current situation is from a brand new, untouched project (yes , again)
+	if (project_ -> filePath().isEmpty() && !project_ -> projectWasModified()) {
+		return(true);
+	}
+	
+	if (project_ -> filePath().isEmpty()) {
+		QString filepath = askUserForFilePath();
+		if (filepath.isEmpty()) return(false); // users may cancel the closing
+	}
+	QETResult result = project_ -> write();
+	updateWindowTitle();
+	if (!result.isOk()) emit(errorEncountered(result.errorMessage()));
+	return(result.isOk());
 }
 
 /**
@@ -215,49 +230,45 @@
 	l'utilisateur s'il souhaite l'enlever.
 	@return true si tous les schemas peuvent etre fermes, false sinon
 */
-bool ProjectView::tryClosingDiagrams() {
-	if (!project_) return(true);
+int ProjectView::tryClosingDiagrams() {
+	if (!project_) return(QDialogButtonBox::DestructiveRole);
 	
-	foreach(DiagramView *diagram_view, diagrams()) {
-		if (!diagram_view -> diagram() -> undoStack().isClean()) {
-			// ce schema a ete modifie - on demande a l'utilisateur s'il veut l'enregistrer
-			showDiagram(diagram_view -> diagram());
-			QMessageBox::StandardButton answer = QET::MessageBox::question(
-				this,
-				tr("Enregistrer le sch\351ma en cours ?", "message box title"),
-				QString(tr("Voulez-vous enregistrer le sch\351ma %1 ?", "message box content - %1 is a diagram title")).arg(diagram_view -> windowTitle()),
-				QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
-				QMessageBox::Cancel
-			);
-			if (answer == QMessageBox::Cancel) {
-				return(false);
-			} else if (answer == QMessageBox::Yes) {
-				if (!save()) {
-					return(false);
-				}
-			}
-		} else if (!diagram_view -> diagram() -> wasWritten()) {
-			// ce schema a ete ajoute mais pas modifie - on demande a l'utilisateur s'il veut le conserver
-			showDiagram(diagram_view -> diagram());
-			QMessageBox::StandardButton answer = QET::MessageBox::question(
-				this,
-				tr("Enregistrer le nouveau sch\351ma ?", "message box title"),
-				tr("Ce sch\351ma a \351t\351 ajout\351 mais n'a \351t\351 ni modifi\351 ni enregistr\351. Voulez-vous le conserver ?", "message box content"),
-				QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
-				QMessageBox::Cancel
-			);
-			if (answer == QMessageBox::Cancel) {
-				return(false);
-			} else if (answer == QMessageBox::Yes) {
-				if (!save()) {
-					return(false);
-				}
-			} else if (answer == QMessageBox::No) {
-				removeDiagram(diagram_view);
-			}
+	QList<Diagram *> modified_diagrams = getDiagrams(AllDiagrams | ModifiedDiagramsOnly);
+	if (!modified_diagrams.count() && !project_ -> filePath().isEmpty()) {
+		// nothing was modified, and we have a filepath, i.e. everything was already
+		// saved, i.e we can close the project right now
+		return(QDialogButtonBox::DestructiveRole);
+	}
+	
+	CloseDiagramsDialog close_dialog(modified_diagrams, this);
+	if (!project_ -> title().isEmpty()) {
+		close_dialog.setWindowTitle(
+			QString(
+				tr(
+					"Fermer le projet \"%1\"",
+					"project closing dialog title -- %1 is a project title"
+				)
+			).arg(project_ -> title())
+		);
+	}
+	connect(&close_dialog, SIGNAL(showDiagram(Diagram*)), this, SLOT(showDiagram(Diagram*)));
+	if (close_dialog.exec() == QDialog::Rejected) {
+		return(QDialogButtonBox::RejectRole);
+	}
+	
+	if (close_dialog.answer() == QDialogButtonBox::AcceptRole) {
+		// save diagrams the user marked as to be saved
+		QList<Diagram *> to_save = close_dialog.diagramsByAction(CloseDiagramsDialog::Save);
+		saveDiagrams(to_save);
+		
+		// remove diagrams the user marked as to be removed
+		QList<Diagram *> to_close = close_dialog.diagramsByAction(CloseDiagramsDialog::Remove);
+		foreach (Diagram *diagram, to_close) {
+			removeDiagram(diagram);
 		}
 	}
-	return(true);
+	
+	return(close_dialog.answer());
 }
 
 /**
@@ -291,6 +302,15 @@
 }
 
 /**
+	@return the QETResult object to be returned when it appears this project
+	view is not associated to any project.
+*/
+QETResult ProjectView::noProjectResult() const {
+	QETResult no_project(tr("aucun projet affich\351", "error message"), false);
+	return(no_project);
+}
+
+/**
 	Ajoute un nouveau schema au ProjectView
 */
 void ProjectView::addNewDiagram() {
@@ -530,58 +550,78 @@
 }
 
 /**
-	Enregistre le projet dans un fichier.
+	Save project properties along with all modified diagrams.
 	@see filePath()
 	@see setFilePath()
-	@return true si l'enregistrement a reussi, false sinon
+	@return a QETResult object reflecting the situation
 */
-bool ProjectView::save() {
-	bool result = false;
-	if (project_) {
-		if (project_ -> filePath().isEmpty()) {
-			// le projet n'est pas encore enregistre dans un fichier
-			// save() equivaut alors a saveAs()
-			return(saveAs());
-		}
-		// on enregistre le schema en cours
-		if (DiagramView *current_view = currentDiagram()) {
-			if (Diagram *diagram = current_view -> diagram()) {
-				diagram -> write();
-				result = true;
-			}
-		} else {
-			// s'il n'y a pas de schema, on appelle directement la methode write()
-			result = project_ -> write();
-		}
+QETResult ProjectView::save() {
+	return(doSave(AllDiagrams | ModifiedDiagramsOnly));
+}
+
+/**
+	Ask users for a filepath in order to save the project.
+	@param options May be used to specify what should be saved; defaults to
+	all modified diagrams.
+	@return a QETResult object reflecting the situation; note that a valid
+	QETResult object is returned if the operation was cancelled.
+*/
+QETResult ProjectView::saveAs(ProjectSaveOptions options) {
+	if (!project_) return(noProjectResult());
+	
+	QString filepath = askUserForFilePath();
+	if (filepath.isEmpty()) return(QETResult());
+	return(doSave(options));
+}
+
+/**
+	Save the current diagram.
+	@return A QETResult object reflecting the situation.
+*/
+QETResult ProjectView::saveCurrentDiagram() {
+	return(doSave(CurrentDiagram));
+}
+
+/**
+	Save project content according to \a options, then write the project file. May
+	call saveAs if no filepath was provided before.
+	@param options May be used to specify what should be saved (e.g. modified
+	diagrams only).
+	@return a QETResult object reflecting the situation; note that a valid
+	QETResult object is returned if the operation was cancelled.
+*/
+QETResult ProjectView::doSave(ProjectSaveOptions options) {
+	if (!project_) return(noProjectResult());
+	
+	if (project_ -> filePath().isEmpty()) {
+		// The project has not been saved to a file yet,
+		// so save() actually means saveAs().
+		return(saveAs(options));
 	}
+	
+	// look for diagrams matching the required save options
+	saveDiagrams(getDiagrams(options));
+	
+	// write to file
+	QETResult result = project_ -> write();
 	updateWindowTitle();
 	return(result);
 }
 
 /**
-	Save all diagrams in the project.
-	@return False if something went wrong (no project, no filepath provided, write
-	error), true otherwise.
+	Save \a diagrams without emitting the written() signal and without writing
+	the project file itself.
 */
-bool ProjectView::saveAll() {
-	if (project_) {
-		if (project_ -> filePath().isEmpty()) {
-			QString filepath = askUserForFilePath();
-			if (filepath.isEmpty()) return(false);
-		}
-		foreach (Diagram *diagram, project_ -> diagrams()) {
-			// Diagram::write() emits the written() signal, which is connected to
-			// QETProject::write() through QETProject::componentWritten(). We do not want
-			// to write the project immediately, so we block this signal.
-			diagram -> blockSignals(true);
-			diagram -> write();
-			diagram -> blockSignals(false);
-		}
-		bool writing = project_ -> write();
-		updateWindowTitle();
-		return(writing);
+void ProjectView::saveDiagrams(const QList<Diagram *> &diagrams) {
+	foreach (Diagram *diagram, diagrams) {
+		// Diagram::write() emits the written() signal, which is connected
+		// to QETProject::write() through QETProject::componentWritten().
+		// We do not want to write the project immediately, so we block
+		// this signal.
+		diagram -> blockSignals(true);
+		diagram -> write();
+		diagram -> blockSignals(false);
 	}
-	return(false);
 }
 
 /**
@@ -653,20 +693,6 @@
 }
 
 /**
-	Demande un nom de fichier a l'utilisateur pour enregistrer le projet
-	Si aucun nom n'est entre, elle renvoie faux.
-	Si le nom ne se termine pas par l'extension .qet, celle-ci est ajoutee.
-	Si l'enregistrement reussit, le nom du fichier est conserve et la fonction renvoie true.
-	Sinon, faux est renvoye.
-	@return true si l'enregistrement a reussi, false sinon
-*/
-bool ProjectView::saveAs() {
-	QString filepath = askUserForFilePath();
-	if (filepath.isEmpty()) return(false);
-	return(save());
-}
-
-/**
 	Initialize actions for this widget.
 */
 void ProjectView::initActions() {

Modified: trunk/sources/projectview.h
===================================================================
--- trunk/sources/projectview.h	2012-07-10 00:11:12 UTC (rev 1906)
+++ trunk/sources/projectview.h	2012-07-13 07:21:19 UTC (rev 1907)
@@ -19,6 +19,7 @@
 #define PROJECT_VIEW_H
 #include <QtGui>
 #include "templatelocation.h"
+#include "qetresult.h"
 class QETProject;
 class DiagramView;
 class Diagram;
@@ -29,6 +30,17 @@
 */
 class ProjectView : public QWidget {
 	Q_OBJECT
+	
+	public:
+	enum ProjectSaveOption {
+		ModifiedDiagramsOnly = 1,
+		CurrentDiagram = 2,
+		AllDiagramsButCurrent = 4,
+		AllDiagrams = 6
+	};
+	Q_DECLARE_FLAGS(ProjectSaveOptions, ProjectSaveOption)
+	
+	
 	// constructeurs, destructeur
 	public:
 	ProjectView(QETProject *, QWidget * = 0);
@@ -41,6 +53,7 @@
 	QETProject *project();
 	void setProject(QETProject *);
 	QList<DiagramView *> diagrams() const;
+	QList<Diagram *> getDiagrams(ProjectSaveOptions options);
 	DiagramView *currentDiagram() const;
 	void closeEvent(QCloseEvent *);
 	
@@ -61,9 +74,11 @@
 	void moveDiagramDown(Diagram *);
 	void printProject();
 	void exportProject();
-	bool save();
-	bool saveAs();
-	bool saveAll();
+	QETResult save();
+	QETResult saveAs(ProjectSaveOptions = ProjectSaveOptions(AllDiagrams | ModifiedDiagramsOnly));
+	QETResult saveCurrentDiagram();
+	QETResult doSave(ProjectSaveOptions);
+	void saveDiagrams(const QList<Diagram *> &);
 	int cleanProject();
 	void updateWindowTitle();
 	void updateTabTitle(DiagramView *, const QString &);
@@ -77,6 +92,7 @@
 	void diagramActivated(DiagramView *);
 	void diagramOrderChanged(ProjectView *, int, int);
 	void projectClosed(ProjectView *);
+	void errorEncountered(const QString &);
 	// relayed signals
 	void findElementRequired(const ElementsLocation &);
 	void editElementRequired(const ElementsLocation &);
@@ -91,8 +107,9 @@
 	void rebuildDiagramsMap();
 	bool tryClosing();
 	bool tryClosingElementEditors();
-	bool tryClosingDiagrams();
+	int tryClosingDiagrams();
 	QString askUserForFilePath(bool = true);
+	QETResult noProjectResult() const;
 	
 	private slots:
 	void tabChanged(int);
@@ -113,4 +130,5 @@
 	QMap<int, DiagramView *> diagram_ids_;
 	QList<DiagramView *> diagrams_;
 };
+Q_DECLARE_OPERATORS_FOR_FLAGS(ProjectView::ProjectSaveOptions)
 #endif

Modified: trunk/sources/qetdiagrameditor.cpp
===================================================================
--- trunk/sources/qetdiagrameditor.cpp	2012-07-10 00:11:12 UTC (rev 1906)
+++ trunk/sources/qetdiagrameditor.cpp	2012-07-13 07:21:19 UTC (rev 1907)
@@ -27,6 +27,7 @@
 #include "qeticons.h"
 #include "qetelementeditor.h"
 #include "qetmessagebox.h"
+#include "qetresult.h"
 #include "genericpanel.h"
 
 /**
@@ -179,8 +180,8 @@
 	open_file         = new QAction(QET::Icons::DocumentOpen,          tr("&Ouvrir"),                              this);
 	close_file        = new QAction(QET::Icons::DocumentClose,         tr("&Fermer"),                              this);
 	save_file         = new QAction(QET::Icons::DocumentSave,          tr("&Enregistrer"),                         this);
-	save_file_sous    = new QAction(QET::Icons::DocumentSaveAs,        tr("Enregistrer sous"),                     this);
-	save_all          = new QAction(QET::Icons::DocumentSaveAll,       tr("&Enregistrer tous les sch\351mas"),     this);
+	save_file_as      = new QAction(QET::Icons::DocumentSaveAs,        tr("Enregistrer sous"),                     this);
+	save_cur_diagram  = new QAction(QET::Icons::DocumentSaveAll,       tr("&Enregistrer tous les sch\351mas"),     this);
 	import_diagram    = new QAction(QET::Icons::DocumentImport,        tr("&Importer"),                            this);
 	export_diagram    = new QAction(QET::Icons::DocumentExport,        tr("E&xporter"),                            this);
 	print             = new QAction(QET::Icons::DocumentPrint,         tr("Imprimer"),                             this);
@@ -273,9 +274,9 @@
 	new_file          -> setStatusTip(tr("Cr\351e un nouveau sch\351ma", "status bar tip"));
 	open_file         -> setStatusTip(tr("Ouvre un sch\351ma existant", "status bar tip"));
 	close_file        -> setStatusTip(tr("Ferme le sch\351ma courant", "status bar tip"));
-	save_file         -> setStatusTip(tr("Enregistre le sch\351ma courant", "status bar tip"));
-	save_file_sous    -> setStatusTip(tr("Enregistre le sch\351ma courant avec un autre nom de fichier", "status bar tip"));
-	save_all          -> setStatusTip(tr("Enregistre tous les sch\351mas du projet courant", "status bar tip"));
+	save_file         -> setStatusTip(tr("Enregistre le projet courant et tous ses sch\351mas", "status bar tip"));
+	save_file_as      -> setStatusTip(tr("Enregistre le project courant avec un autre nom de fichier", "status bar tip"));
+	save_cur_diagram  -> setStatusTip(tr("Enregistre tous les sch\351mas du projet courant", "status bar tip"));
 	import_diagram    -> setStatusTip(tr("Importe un sch\351ma dans le sch\351ma courant", "status bar tip"));
 	export_diagram    -> setStatusTip(tr("Exporte le sch\351ma courant dans un autre format", "status bar tip"));
 	print             -> setStatusTip(tr("Imprime le sch\351ma courant", "status bar tip"));
@@ -356,9 +357,9 @@
 	connect(zoom_reset,         SIGNAL(triggered()), this,       SLOT(slot_zoomReset())            );
 	connect(print,              SIGNAL(triggered()), this,       SLOT(printDialog())               );
 	connect(export_diagram,     SIGNAL(triggered()), this,       SLOT(exportDialog())              );
-	connect(save_file_sous,     SIGNAL(triggered()), this,       SLOT(saveAsDialog())              );
+	connect(save_file_as,       SIGNAL(triggered()), this,       SLOT(saveAs())                    );
 	connect(save_file,          SIGNAL(triggered()), this,       SLOT(save())                      );
-	connect(save_all,           SIGNAL(triggered()), this,       SLOT(saveAll())                   );
+	connect(save_cur_diagram,   SIGNAL(triggered()), this,       SLOT(saveCurrentDiagram())        );
 	connect(new_file,           SIGNAL(triggered()), this,       SLOT(newProject())                );
 	connect(open_file,          SIGNAL(triggered()), this,       SLOT(openProject())               );
 	connect(close_file,         SIGNAL(triggered()), this,       SLOT(closeCurrentProject())       );
@@ -421,8 +422,8 @@
 	menu_fichier -> addMenu(QETApp::projectsRecentFiles() -> menu());
 	connect(QETApp::projectsRecentFiles(), SIGNAL(fileOpeningRequested(const QString &)), this, SLOT(openRecentFile(const QString &)));
 	menu_fichier -> addAction(save_file);
-	menu_fichier -> addAction(save_file_sous);
-	menu_fichier -> addAction(save_all);
+	menu_fichier -> addAction(save_file_as);
+	menu_fichier -> addAction(save_cur_diagram);
 	menu_fichier -> addAction(close_file);
 	menu_fichier -> addSeparator();
 	//menu_fichier -> addAction(import_diagram);
@@ -504,8 +505,8 @@
 	main_bar -> addAction(new_file);
 	main_bar -> addAction(open_file);
 	main_bar -> addAction(save_file);
-	main_bar -> addAction(save_file_sous);
-	main_bar -> addAction(save_all);
+	main_bar -> addAction(save_file_as);
+	main_bar -> addAction(save_cur_diagram);
 	main_bar -> addAction(close_file);
 	main_bar -> addAction(print);
 	main_bar -> addSeparator();
@@ -561,45 +562,45 @@
 	Methode enregistrant le schema dans le dernier nom de fichier connu.
 	@return true si l'enregistrement a reussi, false sinon
 */
-bool QETDiagramEditor::save() {
+void QETDiagramEditor::save() {
 	if (ProjectView *project_view = currentProject()) {
-		bool save_file = project_view -> save();
-		if (save_file) {
+		QETResult save_file = project_view -> save();
+		if (save_file.isOk()) {
 			QETApp::projectsRecentFiles() -> fileWasOpened(project_view -> project() -> filePath());
+		} else {
+			showError(save_file);
 		}
-		return(save_file);
 	}
-	return(false);
 }
 
 /**
 	Cette methode demande un nom de fichier a l'utilisateur pour enregistrer le schema
 	@return true si l'enregistrement a reussi, false sinon
 */
-bool QETDiagramEditor::saveAsDialog() {
+void QETDiagramEditor::saveAs() {
 	if (ProjectView *project_view = currentProject()) {
-		bool save_file = project_view -> saveAs();
-		if (save_file) {
+		QETResult save_file = project_view -> saveAs();
+		if (save_file.isOk()) {
 			QETApp::projectsRecentFiles() -> fileWasOpened(project_view -> project() -> filePath());
+		} else {
+			showError(save_file);
 		}
-		return(save_file);
 	}
-	return(false);
 }
 
 /**
 	Methode enregistrant tous les schemas.
 	@return true si l'enregistrement a reussi, false sinon
 */
-bool QETDiagramEditor::saveAll() {
+void QETDiagramEditor::saveCurrentDiagram() {
 	if (ProjectView *project_view = currentProject()) {
-		bool save_file = project_view -> saveAll();
-		if (save_file) {
+		QETResult save_file = project_view -> saveCurrentDiagram();
+		if (save_file.isOk()) {
 			QETApp::projectsRecentFiles() -> fileWasOpened(project_view -> project() -> filePath());
+		} else {
+			showError(save_file);
 		}
-		return(save_file);
 	}
-	return(false);
 }
 
 /**
@@ -1044,8 +1045,8 @@
 	// actions ayant juste besoin d'un document ouvert
 	close_file        -> setEnabled(opened_project);
 	save_file         -> setEnabled(editable_project);
-	save_file_sous    -> setEnabled(opened_project);
-	save_all          -> setEnabled(editable_diagram);
+	save_file_as      -> setEnabled(opened_project);
+	save_cur_diagram  -> setEnabled(editable_diagram);
 	prj_edit_prop     -> setEnabled(opened_project);
 	prj_add_diagram   -> setEnabled(editable_project);
 	prj_del_diagram   -> setEnabled(editable_project);
@@ -1197,6 +1198,9 @@
 		QETApp::instance(), SLOT(openTitleBlockTemplate(TitleBlockTemplateLocation, bool))
 	);
 	
+	// display error messages sent by the project view
+	connect(project_view, SIGNAL(errorEncountered(QString)), this, SLOT(showError(const QString &)));
+	
 	// affiche la fenetre
 	if (maximise) project_view -> showMaximized();
 	else project_view -> show();
@@ -1687,6 +1691,22 @@
 }
 
 /**
+	Show the error message contained in \a result.
+*/
+void QETDiagramEditor::showError(const QETResult &result) {
+	if (result.isOk()) return;
+	showError(result.errorMessage());
+}
+
+/**
+	Show the \a error message.
+*/
+void QETDiagramEditor::showError(const QString &error) {
+	if (error.isEmpty()) return;
+	QET::MessageBox::critical(this, tr("Erreur", "message box title"), error);
+}
+
+/**
 	@return Les proprietes par defaut pour le cartouche d'un schema
 */
 TitleBlockProperties QETDiagramEditor::defaultTitleBlockProperties() {

Modified: trunk/sources/qetdiagrameditor.h
===================================================================
--- trunk/sources/qetdiagrameditor.h	2012-07-10 00:11:12 UTC (rev 1906)
+++ trunk/sources/qetdiagrameditor.h	2012-07-13 07:21:19 UTC (rev 1907)
@@ -24,6 +24,7 @@
 #include "titleblockproperties.h"
 #include "exportproperties.h"
 class QETProject;
+class QETResult;
 class ProjectView;
 class Diagram;
 class DiagramView;
@@ -83,9 +84,9 @@
 	public slots:
 	void printDialog();
 	void exportDialog();
-	bool saveAsDialog();
-	bool save();
-	bool saveAll();
+	void save();
+	void saveAs();
+	void saveCurrentDiagram();
 	bool newProject();
 	bool openProject();
 	bool openRecentFile(const QString &);
@@ -147,6 +148,8 @@
 	void diagramWasRemoved(DiagramView *);
 	void findElementInPanel(const ElementsLocation &);
 	void editElementInEditor(const ElementsLocation &);
+	void showError(const QETResult &);
+	void showError(const QString &);
 	
 	// attributs
 	public:
@@ -160,9 +163,9 @@
 	QAction *new_file;           ///< Cree un nouveau schema
 	QAction *open_file;          ///< OUvre un fichier
 	QAction *close_file;         ///< Ferme le fichier
-	QAction *save_file;          ///< Enregistre le fichier
-	QAction *save_file_sous;     ///< Enregistrer le fichier sous un nom donne
-	QAction *save_all;           ///< Enregistre tous les schemas
+	QAction *save_file;          ///< Save current project
+	QAction *save_file_as;       ///< Save current project as a specific file
+	QAction *save_cur_diagram;   ///< Save current diagram of the current project only
 	QAction *import_diagram;     ///< Importe un schema existant (non implemente)
 	QAction *export_diagram;     ///< Exporte le schema sous forme d'image
 	QAction *print;              ///< Imprime le schema

Modified: trunk/sources/qetproject.cpp
===================================================================
--- trunk/sources/qetproject.cpp	2012-07-10 00:11:12 UTC (rev 1906)
+++ trunk/sources/qetproject.cpp	2012-07-13 07:21:19 UTC (rev 1907)
@@ -22,6 +22,7 @@
 #include "elementscategory.h"
 #include "qetapp.h"
 #include "qetdiagrameditor.h"
+#include "qetresult.h"
 #include "integrationmoveelementshandler.h"
 #include "movetemplateshandler.h"
 #include "basicmoveelementshandler.h"
@@ -468,17 +469,15 @@
 	@see setFilePath()
 	@return true si l'enregistrement a reussi, false sinon
 */
-bool QETProject::write() {
-	// le chemin du fichier doit etre connu
+QETResult QETProject::write() {
+	// this operation requires a filepath
 	if (file_path_.isEmpty()) {
-		qDebug() << qPrintable(QString("QETProject::write() : called without a known filepath [%1]").arg(QET::pointerString(this)));
-		return(false);
+		return(QString("unable to save project to file: no filepath was specified"));
 	}
 	
-	// si le projet a ete ouvert en mode lecture seule et que le fichier n'est pas accessible en ecriture, on n'effectue pas l'enregistrement
+	// if the project was opened read-only and the file is still non-writable, do not save the project
 	if (isReadOnly() && !QFileInfo(file_path_).isWritable()) {
-		qDebug() << qPrintable(QString("QETProject::write() : the file %1 was opened read-only and thus will not be written. [%2]").arg(file_path_).arg(QET::pointerString(this)));
-		return(true);
+		return(QString("the file %1 was opened read-only and thus will not be written").arg(file_path_));
 	}
 	
 	// realise l'export en XML du projet dans le document XML interne
@@ -488,11 +487,11 @@
 	QString error_message;
 	bool writing = QET::writeXmlFile(document_root_, file_path_, &error_message);
 	if (!writing) {
-		qDebug() << qPrintable(QString("QETProject::write() : %1 [%2]").arg(error_message).arg(QET::pointerString(this)));
-	} else {
-		setModified(false);
+		return(error_message);
 	}
-	return(writing);
+	
+	setModified(false);
+	return(QETResult());
 }
 
 /**
@@ -1180,6 +1179,10 @@
 		return(true);
 	}
 	
+	// the integration category must be empty
+	if (integ_cat -> categories().count()) return(true);
+	if (integ_cat -> elements().count()) return(true);
+	
 	return(false);
 }
 
@@ -1205,7 +1208,7 @@
 	if (diagrams_.count() != 1) return(true);
 	
 	// dont la pile d'annulation est "clean"
-	return(!(diagrams_[0] -> undoStack().isClean()));
+	return(!(diagrams_[0] -> undoStack().isClean() && !diagrams_[0] -> wasWritten()));
 }
 
 /**

Modified: trunk/sources/qetproject.h
===================================================================
--- trunk/sources/qetproject.h	2012-07-10 00:11:12 UTC (rev 1906)
+++ trunk/sources/qetproject.h	2012-07-13 07:21:19 UTC (rev 1907)
@@ -30,6 +30,7 @@
 class ElementsCategory;
 class ElementDefinition;
 class ElementsLocation;
+class QETResult;
 class TitleBlockTemplate;
 class XmlElementsCollection;
 class MoveElementsHandler;
@@ -98,7 +99,7 @@
 	void setDefaultConductorProperties(const ConductorProperties &);
 	QDomDocument toXml();
 	bool close();
-	bool write();
+	QETResult write();
 	bool isReadOnly() const;
 	void setReadOnly(bool);
 	bool isEmpty() const;

Added: trunk/sources/qetresult.cpp
===================================================================
--- trunk/sources/qetresult.cpp	                        (rev 0)
+++ trunk/sources/qetresult.cpp	2012-07-13 07:21:19 UTC (rev 1907)
@@ -0,0 +1,70 @@
+/*
+	Copyright 2006-2012 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "qetresult.h"
+
+/**
+	Construct a default "true" QET result without an error message.
+*/
+QETResult::QETResult() :
+	result_(true)
+{
+}
+
+/**
+	Construct a QET result embedding \a error_message and \a result (defaults
+	to false).
+*/
+QETResult::QETResult(const QString &error_message, bool result) :
+	result_(result),
+	error_message_(error_message)
+{
+}
+
+/**
+	Destructor
+*/
+QETResult::~QETResult() {
+}
+
+/**
+	@return the boolean value embedded within this result.
+*/
+bool QETResult::isOk() const {
+	return(result_);
+}
+
+/**
+	Embed \a result.
+*/
+void QETResult::setResult(bool result) {
+	result_ = result;
+}
+
+/**
+	@return the error message embedded within this result.
+*/
+QString QETResult::errorMessage() const {
+	return(error_message_);
+}
+
+/**
+	Embed \a error_message wihthin this result.
+*/
+void QETResult::setErrorMessage(const QString &error_message) {
+	error_message_ = error_message;
+}

Added: trunk/sources/qetresult.h
===================================================================
--- trunk/sources/qetresult.h	                        (rev 0)
+++ trunk/sources/qetresult.h	2012-07-13 07:21:19 UTC (rev 1907)
@@ -0,0 +1,46 @@
+/*
+	Copyright 2006-2012 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef QET_RESULT_H
+#define QET_RESULT_H
+#include <QString>
+
+/**
+	This class represents the result of a lambda operation. Technically, it is
+	a mere boolean+error message pair.
+*/
+class QETResult {
+	// Constructor, destructor
+	public:
+	QETResult();
+	QETResult(const QString &error_message, bool = false);
+	virtual ~QETResult();
+	
+	// methods
+	public:
+	bool isOk() const;
+	void setResult(bool);
+	QString errorMessage() const;
+	void setErrorMessage(const QString &);
+	
+	// attributes
+	private:
+	bool result_;           ///< Embedded boolean value
+	QString error_message_; ///< Embedded error message, typically used to explain what failed to users
+};
+
+#endif


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/