diff --git a/aboutqet.cpp b/aboutqet.cpp
index 4d731a676..0ce4eb130 100644
--- a/aboutqet.cpp
+++ b/aboutqet.cpp
@@ -33,7 +33,7 @@ AboutQET::AboutQET(QWidget *parent) : QDialog(parent) {
/**
@return Le titre QElectroTech avec son icone
*/
-QWidget *AboutQET::titre() {
+QWidget *AboutQET::titre() const {
QWidget *icone_et_titre = new QWidget();
// icone
QLabel *icone = new QLabel();
@@ -54,7 +54,7 @@ QWidget *AboutQET::titre() {
/**
@return Le widget contenu par l'onglet « A propos »
*/
-QWidget *AboutQET::ongletAPropos() {
+QWidget *AboutQET::ongletAPropos() const {
QLabel *apropos = new QLabel(
tr("QElectroTech, une application de r\351alisation de sch\351mas \351lectriques.") +
"
" +
@@ -72,7 +72,7 @@ QWidget *AboutQET::ongletAPropos() {
/**
@return Le widget contenu par l'onglet « Auteurs »
*/
-QWidget *AboutQET::ongletAuteurs() {
+QWidget *AboutQET::ongletAuteurs() const {
QLabel *auteurs = new QLabel(
"" +
tr("Id\351e originale") +
@@ -95,7 +95,7 @@ QWidget *AboutQET::ongletAuteurs() {
/**
@return Le widget contenu par l'onglet « Accord de Licence »
*/
-QWidget *AboutQET::ongletLicence() {
+QWidget *AboutQET::ongletLicence() const {
QWidget *licence = new QWidget();
// label
QLabel *titre_licence = new QLabel(tr("Ce programme est sous licence GNU/GPL."));
diff --git a/aboutqet.h b/aboutqet.h
index bc5123ca7..307c38895 100644
--- a/aboutqet.h
+++ b/aboutqet.h
@@ -10,9 +10,9 @@
public:
AboutQET(QWidget * = 0);
private:
- QWidget *titre();
- QWidget *ongletAPropos();
- QWidget *ongletAuteurs();
- QWidget *ongletLicence();
+ QWidget *titre() const;
+ QWidget *ongletAPropos() const;
+ QWidget *ongletAuteurs() const;
+ QWidget *ongletLicence() const;
};
#endif
diff --git a/borne.cpp b/borne.cpp
index 404e6ebee..9a708de6a 100644
--- a/borne.cpp
+++ b/borne.cpp
@@ -97,7 +97,7 @@ Borne::Orientation Borne::orientation() const {
Borne::Orientation ori_def = elt -> defaultOrientation();
if (ori_cur == ori_def) return(sens);
else {
- /* calcul l'angle de rotation implique par l'orientation de l'element parent */
+ // calcul l'angle de rotation implique par l'orientation de l'element parent
// angle de rotation de la borne sur la scene, divise par 90
int angle = ori_cur - ori_def + sens;
while (angle >= 4) angle -= 4;
@@ -361,7 +361,7 @@ QList Borne::conducteurs() const {
@param doc Le Document XML a utiliser pour creer l'element XML
@return un QDomElement representant cette borne
*/
-QDomElement Borne::toXml(QDomDocument &doc) {
+QDomElement Borne::toXml(QDomDocument &doc) const {
QDomElement qdo = doc.createElement("borne");
qdo.setAttribute("x", amarrage_elmt.x());
qdo.setAttribute("y", amarrage_elmt.y());
diff --git a/borne.h b/borne.h
index a974fda86..c5c33551f 100644
--- a/borne.h
+++ b/borne.h
@@ -34,7 +34,7 @@
// methodes de manipulation des conducteurs lies a cette borne
bool addConducteur(Conducteur *);
void removeConducteur(Conducteur *);
- inline int nbConducteurs() { return(liste_conducteurs.size()); }
+ inline int nbConducteurs() const { return(liste_conducteurs.size()); }
// methodes de lecture
QList conducteurs() const;
@@ -45,8 +45,9 @@
// methodes relatives a l'import/export au format XML
static bool valideXml(QDomElement &);
bool fromXml (QDomElement &);
- QDomElement toXml (QDomDocument &);
+ QDomElement toXml (QDomDocument &) const;
+ protected:
// methodes de gestion des evenements
void hoverEnterEvent (QGraphicsSceneHoverEvent *);
void hoverMoveEvent (QGraphicsSceneHoverEvent *);
diff --git a/element.cpp b/element.cpp
index cfc86854f..33efe9f86 100644
--- a/element.cpp
+++ b/element.cpp
@@ -62,8 +62,8 @@ QPoint Element::setHotspot(QPoint hs) {
if (dimensions.isNull()) hotspot_coord = QPoint(0, 0);
else {
// les coordonnees indiquees ne doivent pas depasser les dimensions de l'element
- int hsx = hs.x() > dimensions.width() ? dimensions.width() : hs.x();
- int hsy = hs.y() > dimensions.height() ? dimensions.height() : hs.y();
+ int hsx = qMin(hs.x(), dimensions.width());
+ int hsy = qMin(hs.y(), dimensions.height());
hotspot_coord = QPoint(hsx, hsy);
}
return(hotspot_coord);
diff --git a/exportdialog.cpp b/exportdialog.cpp
new file mode 100644
index 000000000..76b80de82
--- /dev/null
+++ b/exportdialog.cpp
@@ -0,0 +1,210 @@
+#include "exportdialog.h"
+
+/**
+ Constructeur
+ @param schema Le schema a exporter
+ @param parent Le Widget parent de ce dialogue
+*/
+ExportDialog::ExportDialog(Schema &schema, QWidget *parent) : QDialog(parent) {
+ // recupere le schema a exporter, sa taille et ses proportions
+ schema_schema = &schema;
+ schema_size = schema_schema -> imageSize();
+ schema_ratio = (qreal)schema_size.width() / (qreal)schema_size.height();
+
+ // la taille du dialogue est fixee
+ setFixedSize(400, 310);
+ setWindowTitle(tr("Exporter"));
+
+ // le dialogue est un empilement vertical d'elements
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+
+ /* le dialogue comprend une ligne permettant d'indiquer un chemin de fichier (hboxLayout) */
+ QHBoxLayout *hboxLayout = new QHBoxLayout();
+ hboxLayout -> addWidget(new QLabel(tr("Nom de fichier :"), this));
+ hboxLayout -> addWidget(filename = new QLineEdit(this));
+ hboxLayout -> addWidget(button_browse = new QPushButton(tr("Parcourir"), this));
+
+ vboxLayout -> addLayout(hboxLayout);
+
+ /* une ligne permettant de choisir le format (hboxLayout1) */
+ QHBoxLayout *hboxLayout1 = new QHBoxLayout();
+ hboxLayout1 -> addWidget(new QLabel(tr("Format :"), this));
+ hboxLayout1 -> addWidget(format = new QComboBox(this));
+ format -> addItem(tr("PNG (*.png)"), "PNG");
+ format -> addItem(tr("JPEG (*.jpg)"), "JPG");
+ format -> addItem(tr("Bitmap (*.bmp)"), "BMP");
+
+ vboxLayout -> addLayout(hboxLayout1);
+
+ /* un cadre permettant de specifier les dimensions de l'image finale */
+ vboxLayout -> addWidget(setupDimensionsGroupBox());
+
+ /* un cadre permettant de specifier les options de l'image finale */
+ vboxLayout -> addWidget(setupOptionsGroupBox());
+
+ /* et deux boutons */
+ buttons = new QDialogButtonBox(this);
+ buttons -> setOrientation(Qt::Horizontal);
+ buttons -> setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Save);
+
+ vboxLayout -> addWidget(buttons);
+
+ // ordre des input selectionnes avec la touche tab
+ setTabOrder(filename, button_browse);
+ setTabOrder(button_browse, format);
+ setTabOrder(format, width);
+ setTabOrder(width, height);
+ setTabOrder(height, keep_aspect_ratio);
+ setTabOrder(keep_aspect_ratio, buttons);
+
+ // connexions signaux/slots
+ connect(button_browse, SIGNAL(released()), this, SLOT(slot_chooseAFile()));
+ connect(width, SIGNAL(valueChanged(int)), this, SLOT(slot_correctHeight()));
+ connect(keep_aspect_ratio, SIGNAL(stateChanged(int)), this, SLOT(slot_correctHeight()));
+ connect(height, SIGNAL(valueChanged(int)), this, SLOT(slot_correctWidth()));
+ connect(buttons, SIGNAL(accepted()), this, SLOT(slot_check()));
+ connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+/**
+ Met en place la partie du dialogue dans lequel l'utilisateur entre les
+ dimensions souhaitees de l'image.
+ @return La QGroupBox permettant de regler les dimensions de l'image
+*/
+QGroupBox *ExportDialog::setupDimensionsGroupBox() {
+ QGroupBox *groupbox_dimensions = new QGroupBox(tr("Dimensions"), this);
+ QGridLayout *gridLayout = new QGridLayout(groupbox_dimensions);
+
+ // hauteur
+ gridLayout -> addWidget(new QLabel(tr("Hauteur :"), groupbox_dimensions), 2, 0, 1, 1);
+
+ width = new QSpinBox(groupbox_dimensions);
+ width -> setRange(1, 10000);
+ width -> setValue(schema_size.width());
+ gridLayout -> addWidget(width, 0, 1, 1, 1);
+
+ gridLayout -> addWidget(new QLabel(tr("px"), groupbox_dimensions), 0, 2, 1, 1);
+
+ // largeur
+ gridLayout -> addWidget(new QLabel(tr("Largeur :"), groupbox_dimensions), 0, 0, 1, 1);
+
+ height = new QSpinBox(groupbox_dimensions);
+ height -> setRange(1, 10000);
+ height -> setValue(schema_size.height());
+ gridLayout -> addWidget(height, 2, 1, 1, 1);
+
+ gridLayout -> addWidget(new QLabel(tr("px"), groupbox_dimensions), 2, 2, 1, 1);
+
+ // conserver les proportions
+ keep_aspect_ratio = new QCheckBox(tr("Conserver les proportions"), groupbox_dimensions);
+ keep_aspect_ratio -> setChecked(true);
+
+ gridLayout -> addWidget(keep_aspect_ratio, 1, 3, 1, 1);
+
+ return(groupbox_dimensions);
+}
+
+/**
+ Met en place la partie du dialogue dans lequel l'utilisateur entre les
+ options souhaitees de l'image.
+ @return La QGroupBox permettant de regler les options de l'image
+*/
+QGroupBox *ExportDialog::setupOptionsGroupBox() {
+ QGroupBox *groupbox_options = new QGroupBox(tr("Options"), this);
+ QHBoxLayout *optionshlayout = new QHBoxLayout(groupbox_options);
+
+ // exporter la grille
+ export_grid = new QCheckBox(tr("Exporter la grille"), groupbox_options);
+ optionshlayout -> addWidget(export_grid);
+
+ // Conserver les couleurs
+ keep_colors = new QCheckBox(tr("Conserver les couleurs"), groupbox_options);
+ optionshlayout -> addWidget(keep_colors);
+
+ return(groupbox_options);
+}
+
+void ExportDialog::slot_correctWidth() {
+ if (!keep_aspect_ratio -> isChecked() || dontchangewidth) return;
+ dontchangeheight = true;
+ width -> setValue(qRound(height -> value() * schema_ratio));
+ dontchangeheight = false;
+}
+
+void ExportDialog::slot_correctHeight() {
+ if (!keep_aspect_ratio -> isChecked() || dontchangeheight) return;
+ dontchangewidth = true;
+ height -> setValue(qRound(width -> value() / schema_ratio));
+ dontchangewidth = false;
+}
+
+void ExportDialog::slot_chooseAFile() {
+ QString user_file = QFileDialog::getSaveFileName(
+ this,
+ tr("Exporter vers le fichier"),
+ QDir::homePath(),
+ tr("Images (*.png *.bmp *.jpg)")
+ );
+ if (user_file != "") {
+ schema_path = user_file;
+ filename -> setText(schema_path);
+ }
+}
+
+void ExportDialog::slot_check() {
+
+ // verifie que le fichier a ete specifie
+ if (schema_path == "") {
+ QMessageBox::information(
+ this,
+ tr("Fichier non sp\351cifi\351"),
+ tr("Vous devez sp\351cifier le chemin du fichier dans lequel sera enregistr\351e l'image."),
+ QMessageBox::Ok
+ );
+ return;
+ }
+
+ // recupere le format a utiliser (acronyme et extension)
+ QString format_acronym = format -> itemData(format -> currentIndex()).toString();
+ QString format_extension = "." + format_acronym.toLower();
+
+ // corrige l'extension du fichier
+ if (!schema_path.endsWith(format_extension, Qt::CaseInsensitive)) schema_path += format_extension;
+
+ // recupere des informations sur le fichier specifie
+ QFileInfo file_infos(schema_path);
+
+ // verifie qu'il est possible d'ecrire dans le fichier en question
+ if (file_infos.exists() && !file_infos.isWritable()) {
+ QMessageBox::critical(
+ this,
+ tr("Impossible d'\351crire dans ce fichier"),
+ tr("Il semblerait que vous n'ayez pas les permissions n\351cessaires pour \351crire dans ce fichier.."),
+ QMessageBox::Ok
+ );
+ return;
+ }
+
+ // ouvre le fichier
+ QFile fichier(schema_path);
+
+ // genere l'image
+ if (!export_grid -> isChecked()) schema_schema -> setAffichageGrille(false);
+ QImage image = schema_schema -> toImage(width -> value(), height -> value(), keep_aspect_ratio -> isChecked());
+ if (!export_grid -> isChecked()) schema_schema -> setAffichageGrille(true);
+
+ // convertit l'image en niveaux de gris si besoin
+ if (!keep_colors -> isChecked()) {
+ QVector ColorTab;
+ for (int i = 0 ; i < 256 ; ++ i) ColorTab << qRgb(i, i, i);
+ image = image.convertToFormat(QImage::Format_Indexed8, ColorTab, Qt::ThresholdDither);
+ }
+
+ // enregistre l'image dans le fichier
+ image.save(&fichier, format_acronym.toUtf8().data());
+ fichier.close();
+
+ // fermeture du dialogue
+ accept();
+}
+
diff --git a/exportdialog.h b/exportdialog.h
new file mode 100644
index 000000000..5f6903a60
--- /dev/null
+++ b/exportdialog.h
@@ -0,0 +1,45 @@
+#ifndef EXPORTDIALOG_H
+ #define EXPORTDIALOG_H
+ #include
+ #include "schema.h"
+ /**
+ Cette classe represente le dialogue permettant d'exporter un schema
+ sous forme d'image selon les desirs de l'utilisateur
+ */
+ class ExportDialog : public QDialog {
+ Q_OBJECT
+ public:
+ ExportDialog(Schema &, QWidget * = 0);
+
+ private:
+ // elements graphiques
+ QLineEdit *filename;
+ QPushButton *button_browse;
+ QComboBox *format;
+ QSpinBox *width;
+ QSpinBox *height;
+ QCheckBox *keep_aspect_ratio;
+ QCheckBox *export_grid;
+ QCheckBox *keep_colors;
+ QDialogButtonBox *buttons;
+
+ // booleens pour ne pas avoir de boucle lors de l'edition des dimensions de l'image
+ bool dontchangewidth;
+ bool dontchangeheight;
+
+ // elements relatifs au traitement effectue par le dialogue
+ Schema *schema_schema;
+ QSize schema_size;
+ QString schema_path;
+ qreal schema_ratio;
+
+ QGroupBox *setupDimensionsGroupBox();
+ QGroupBox *setupOptionsGroupBox();
+
+ public slots:
+ void slot_correctWidth();
+ void slot_correctHeight();
+ void slot_chooseAFile();
+ void slot_check();
+ };
+#endif
diff --git a/qelectrotech.pro b/qelectrotech.pro
index 9b09f172a..51d15e759 100644
--- a/qelectrotech.pro
+++ b/qelectrotech.pro
@@ -4,7 +4,7 @@
TEMPLATE = app
TARGET =
-DEPENDPATH += .
+DEPENDPATH += . lang
INCLUDEPATH += .
# Input
@@ -14,6 +14,7 @@ HEADERS += aboutqet.h \
element.h \
elementfixe.h \
elementperso.h \
+ exportdialog.h \
panelappareils.h \
qetapp.h \
schema.h \
@@ -24,12 +25,13 @@ SOURCES += aboutqet.cpp \
element.cpp \
elementfixe.cpp \
elementperso.cpp \
+ exportdialog.cpp \
main.cpp \
panelappareils.cpp \
qetapp.cpp \
schema.cpp \
schemavue.cpp
RESOURCES += qelectrotech.qrc
-TRANSLATIONS += qet_en.ts
+TRANSLATIONS += lang/qet_en.ts lang/qt_fr.ts
QT += xml
diff --git a/qetapp.cpp b/qetapp.cpp
index f695457ac..8daabe3b7 100644
--- a/qetapp.cpp
+++ b/qetapp.cpp
@@ -3,6 +3,7 @@
#include "schema.h"
#include "panelappareils.h"
#include "aboutqet.h"
+#include "exportdialog.h"
/**
constructeur
@@ -515,13 +516,12 @@ void QETApp::dialogue_imprimer() {
Gere l'export de schema vers un autre format (PNG pour le moment)
*/
void QETApp::dialogue_exporter() {
+ Schema *sc = schemaEnCours() -> scene;
+ ExportDialog ed(*sc);
+ ed.exec();
+ /*
// demande un nom de fichier
- QString nom_fichier = QFileDialog::getSaveFileName(
- this,
- tr("Exporter vers le fichier"),
- QDir::homePath(),
- tr("Image PNG (*.png)")
- );
+
// exporte le schema
if (nom_fichier != "") {
if (!nom_fichier.endsWith(".png", Qt::CaseInsensitive)) nom_fichier += ".png";
@@ -533,6 +533,7 @@ void QETApp::dialogue_exporter() {
image.save(&fichier, "PNG");
fichier.close();
}
+ */
}
/**
diff --git a/schema.cpp b/schema.cpp
index 231433daa..df925e1d1 100644
--- a/schema.cpp
+++ b/schema.cpp
@@ -67,16 +67,26 @@ void Schema::drawBackground(QPainter *p, const QRectF &r) {
Exporte le schema vers une image
@return Une QImage representant le schema
*/
-QImage Schema::toImage() {
- QRectF vue = itemsBoundingRect();
- // la marge = 5 % de la longueur necessaire
- qreal marge = 0.05 * vue.width();
- vue.translate(-marge, -marge);
- vue.setWidth(vue.width() + 2.0 * marge);
- vue.setHeight(vue.height() + 2.0 * marge);
- QSize dimensions_image = vue.size().toSize();
+QImage Schema::toImage(int width, int height, bool respectRatio) {
+ // determine le contenu du schema
+ QRectF schema_content = itemsBoundingRect();
- QImage pix = QImage(dimensions_image, QImage::Format_RGB32);
+ // calcule la marge = 5 % de la longueur necessaire
+ qreal margin = 0.05 * schema_content.width();
+
+ // en deduit la zone source utilisee pour l'image
+ QRectF source_area = schema_content;
+ source_area.translate(-margin, -margin);
+ source_area.setWidth(schema_content.width() + 2.0 * margin);
+ source_area.setHeight(schema_content.height() + 2.0 * margin);
+
+ // si les dimensions ne sont pas precisees, l'image est exportee a l'echelle 1:1
+ QSize image_size = (width == -1 && height == -1) ? source_area.size().toSize() : QSize(width, height);
+
+ // initialise une image avec ces dimensions
+ QImage pix = QImage(image_size, QImage::Format_RGB32);
+
+ // prepare le rendu
QPainter p;
bool painter_ok = p.begin(&pix);
if (!painter_ok) return(QImage());
@@ -86,11 +96,41 @@ QImage Schema::toImage() {
p.setRenderHint(QPainter::TextAntialiasing, true);
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
- render(&p, pix.rect(), vue, Qt::KeepAspectRatio);
+ // deselectionne tous les elements
+ QList selected_elmts = selectedItems();
+ foreach (QGraphicsItem *qgi, selected_elmts) qgi -> setSelected(false);
+
+ // effectue le rendu lui-meme
+ render(&p, pix.rect(), source_area, respectRatio ? Qt::KeepAspectRatio : Qt::IgnoreAspectRatio);
p.end();
+
+ // restaure les elements selectionnes
+ foreach (QGraphicsItem *qgi, selected_elmts) qgi -> setSelected(true);
+
return(pix);
}
+/**
+ Permet de connaitre les dimensions qu'aura l'image generee par la methode toImage()
+ @return La taille de l'image generee par toImage()
+*/
+QSize Schema::imageSize() const {
+ // determine le contenu du schema
+ QRectF schema_content = itemsBoundingRect();
+
+ // calcule la marge = 5 % de la longueur necessaire
+ qreal margin = 0.05 * schema_content.width();
+
+ // en deduit la zone source utilisee pour l'image
+ QRectF source_area = schema_content;
+ source_area.translate(-margin, -margin);
+ source_area.setWidth(schema_content.width() + 2.0 * margin);
+ source_area.setHeight(schema_content.height() + 2.0 * margin);
+
+ // renvoie la taille de la zone source
+ return(source_area.size().toSize());
+}
+
/**
Exporte tout ou partie du schema
@param schema Booleen (a vrai par defaut) indiquant si le XML genere doit
diff --git a/schema.h b/schema.h
index c6ea13e58..b7a218a7e 100644
--- a/schema.h
+++ b/schema.h
@@ -21,7 +21,8 @@
}
inline void setDepart (QPointF d) { poseur_de_conducteur -> setLine(QLineF(d, poseur_de_conducteur -> line().p2())); }
inline void setArrivee(QPointF a) { poseur_de_conducteur -> setLine(QLineF(poseur_de_conducteur -> line().p1(), a)); }
- QImage toImage();
+ QImage toImage(int = -1, int = -1, bool = true);
+ QSize imageSize() const;
QDomDocument toXml(bool = true);
bool fromXml(QDomDocument &, QPointF = QPointF());
QGraphicsItem *getElementById(uint id);