Rapatriement de la branche 0.2 dans le trunk

git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@558 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
xavier
2009-04-03 19:30:25 +00:00
parent f84b86e4a4
commit 4da7e54d75
366 changed files with 31970 additions and 3696 deletions

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -16,6 +16,7 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QtGui>
#include "qettabwidget.h"
#include "aboutqet.h"
#include "qet.h"
@@ -25,16 +26,16 @@
*/
AboutQET::AboutQET(QWidget *parent) : QDialog(parent) {
// Titre, taille, comportement...
setWindowTitle(tr("\300 propos de QElectrotech"));
setWindowTitle(tr("\300 propos de QElectrotech", "window title"));
setMinimumWidth(680);
setMinimumHeight(350);
setModal(true);
// Trois onglets
QTabWidget *onglets = new QTabWidget(this);
onglets -> addTab(ongletAPropos(), tr("\300 &propos"));
onglets -> addTab(ongletAuteurs(), tr("A&uteurs"));
onglets -> addTab(ongletLicence(), tr("&Accord de licence"));
QETTabWidget *onglets = new QETTabWidget(this);
onglets -> addTab(ongletAPropos(), tr("\300 &propos","tab title"));
onglets -> addTab(ongletAuteurs(), tr("A&uteurs", "tab title"));
onglets -> addTab(ongletLicence(), tr("&Accord de licence", "tab title"));
// Un bouton pour fermer la boite de dialogue
QDialogButtonBox *boutons = new QDialogButtonBox(QDialogButtonBox::Close);
@@ -64,7 +65,7 @@ QWidget *AboutQET::titre() const {
QLabel *icone = new QLabel();
icone -> setPixmap(QIcon(":/ico/qelectrotech.png").pixmap(48, 48));
// label "QElectroTech"
QLabel *titre = new QLabel("<span style=\"font-weight:0;font-size:16pt;\">QElectroTech v" + QET::version + "</span>");
QLabel *titre = new QLabel("<span style=\"font-weight:0;font-size:16pt;\">QElectroTech v" + QET::displayedVersion + "</span>");
titre -> setTextFormat(Qt::RichText);
// le tout dans une grille
QGridLayout *dispo_horiz = new QGridLayout();
@@ -83,10 +84,10 @@ QWidget *AboutQET::ongletAPropos() const {
QLabel *apropos = new QLabel(
tr("QElectroTech, une application de r\351alisation de sch\351mas \351lectriques.") +
"<br><br>" +
tr("\251 2006-2008 Les d\351veloppeurs de QElectroTech") +
tr("\251 2006-2009 Les d\351veloppeurs de QElectroTech") +
"<br><br>"
"<a href=\"http://qelectrotech.tuxfamily.org/\">"
"http://qelectrotech.tuxfamily.org/</a>"
"<a href=\"http://qelectrotech.org/\">"
"http://qelectrotech.org/</a>"
);
apropos -> setAlignment(Qt::AlignCenter);
apropos -> setOpenExternalLinks(true);

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -0,0 +1,126 @@
#include "basicmoveelementshandler.h"
/**
Constructeur
@param parent QObject parent
*/
BasicMoveElementsHandler::BasicMoveElementsHandler(QObject *parent) :
MoveElementsHandler(parent),
already_exists_(QET::Erase),
not_readable_(QET::Ignore),
not_writable_(QET::Ignore),
error_(QET::Ignore),
rename_("renamed")
{
}
/**
Destructeur
*/
BasicMoveElementsHandler::~BasicMoveElementsHandler() {
}
/**
@param action Action a renvoyer si un item existe deja
*/
void BasicMoveElementsHandler::setActionIfItemAlreadyExists(QET::Action action) {
already_exists_ = action;
}
/**
@param action Action a renvoyer si un item n'est pas lisible
*/
void BasicMoveElementsHandler::setActionIfItemIsNotReadable(QET::Action action) {
not_readable_ = action;
}
/**
@param action Action a renvoyer si un item n'est pas accessible en ecriture
*/
void BasicMoveElementsHandler::setActionIfItemIsNotWritable(QET::Action action) {
not_writable_ = action;
}
/**
@param action Action a renvoyer si un item provoque une erreur
*/
void BasicMoveElementsHandler::setActionIfItemTriggersAnError(QET::Action action) {
error_ = action;
}
/**
@param name Nom a renvoyer pour une eventuelle operation de renommage
Il est toutefois deconseille de proceder a un renommage systematique, vu que
cette propriete est invariable.
*/
void BasicMoveElementsHandler::setNameForRenamingOperation(const QString &name) {
rename_ = name;
}
/**
@return l'action a effectuer si la categorie cible existe deja
*/
QET::Action BasicMoveElementsHandler::categoryAlreadyExists(ElementsCategory *, ElementsCategory *) {
return(already_exists_);
}
/**
@return l'action a effectuer si l'element cible existe deja
*/
QET::Action BasicMoveElementsHandler::elementAlreadyExists(ElementDefinition *, ElementDefinition *) {
return(already_exists_);
}
/**
@return l'action a effectuer si la categorie existe deja
*/
QET::Action BasicMoveElementsHandler::categoryIsNotReadable(ElementsCategory *) {
return(not_readable_);
}
/**
@return l'action a effectuer si l'element existe deja
*/
QET::Action BasicMoveElementsHandler::elementIsNotReadable(ElementDefinition *) {
return(not_readable_);
}
/**
@return l'action a effectuer si la categorie cible n'est pas accessible
en ecriture
*/
QET::Action BasicMoveElementsHandler::categoryIsNotWritable(ElementsCategory *) {
return(not_writable_);
}
/**
@return l'action a effectuer si l'element cible n'est pas accessible
en ecriture
*/
QET::Action BasicMoveElementsHandler::elementIsNotWritable(ElementDefinition *) {
return(not_writable_);
}
/**
@return l'action a effectuer lorsque l'erreur decrite dans la QString
s'est produite avec la categorie indiquee
*/
QET::Action BasicMoveElementsHandler::errorWithACategory(ElementsCategory *, const QString &) {
return(error_);
}
/**
@return l'action a effectuer lorsque l'erreur decrite dans la QString
s'est produite avec l'element indique
*/
QET::Action BasicMoveElementsHandler::errorWithAnElement(ElementDefinition *, const QString &) {
return(error_);
}
/**
@return le nom a utiliser pour le renommage si une methode de cet objet
a precedemment renvoye QET::Rename.
*/
QString BasicMoveElementsHandler::nameForRenamingOperation() {
return(rename_);
}

View File

@@ -0,0 +1,62 @@
/*
Copyright 2006-2009 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 BASIC_MOVE_ELEMENTS_HANDLER
#define BASIC_MOVE_ELEMENTS_HANDLER
#include "moveelementshandler.h"
/**
Cette classe implemente basiquement la classe strategie MoveElementsHandler
Elle retourne toujours la meme action (parametrable) pour une methode
donnee.
*/
class BasicMoveElementsHandler : public MoveElementsHandler {
Q_OBJECT
// constructeurs, destructeur
public:
BasicMoveElementsHandler(QObject * = 0);
virtual ~BasicMoveElementsHandler();
private:
BasicMoveElementsHandler(const BasicMoveElementsHandler &);
// methodes
public:
virtual void setActionIfItemAlreadyExists(QET::Action);
virtual void setActionIfItemIsNotReadable(QET::Action);
virtual void setActionIfItemIsNotWritable(QET::Action);
virtual void setActionIfItemTriggersAnError(QET::Action);
virtual void setNameForRenamingOperation(const QString &);
virtual QET::Action categoryAlreadyExists(ElementsCategory *src, ElementsCategory *dst);
virtual QET::Action elementAlreadyExists(ElementDefinition *src, ElementDefinition *dst);
virtual QET::Action categoryIsNotReadable(ElementsCategory *);
virtual QET::Action elementIsNotReadable(ElementDefinition *);
virtual QET::Action categoryIsNotWritable(ElementsCategory *);
virtual QET::Action elementIsNotWritable(ElementDefinition *);
virtual QET::Action errorWithACategory(ElementsCategory *, const QString &);
virtual QET::Action errorWithAnElement(ElementDefinition *, const QString &);
virtual QString nameForRenamingOperation();
// attributs
private:
QET::Action already_exists_;
QET::Action not_readable_;
QET::Action not_writable_;
QET::Action error_;
QString rename_;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -18,7 +18,6 @@
#include <QPainter>
#include "borderinset.h"
#include "qetapp.h"
#include "qetdiagrameditor.h"
#include "math.h"
/**
@@ -28,16 +27,17 @@
*/
BorderInset::BorderInset(QObject *parent) : QObject(parent) {
// dimensions par defaut du schema
importBorder(QETDiagramEditor::defaultBorderProperties());
importBorder(BorderProperties());
// contenu par defaut du cartouche
importInset(QETDiagramEditor::defaultInsetProperties());
importInset(InsetProperties());
// hauteur du cartouche
inset_height = 50.0;
display_inset = true;
display_border = true;
setFolioData(1, 1);
updateRectangles();
}
@@ -94,9 +94,10 @@ InsetProperties BorderInset::exportInset() {
void BorderInset::importInset(const InsetProperties &ip) {
bi_author = ip.author;
bi_date = ip.date;
bi_title = ip.title;
setTitle(ip.title);
bi_folio = ip.folio;
bi_filename = ip.filename;
emit(needFolioData());
}
/**
@@ -158,6 +159,8 @@ void BorderInset::displayRows(bool dr) {
/**
@param db true pour afficher la bordure du schema, false sinon
Note : si l'affichage de la bordure est ainsi desactivee, les lignes et
colonnes ne seront pas dessinees.
*/
void BorderInset::displayBorder(bool db) {
bool change = (db != display_border);
@@ -208,10 +211,10 @@ void BorderInset::draw(QPainter *qp, qreal x, qreal y) {
// dessine le cadre
if (display_border) qp -> drawRect(diagram);
qp -> setFont(QFont(QETApp::diagramTextsFont(), qp -> font().pointSize()));
qp -> setFont(QFont(QETApp::diagramTextsFont(), QETApp::diagramTextsSize()));
// dessine la case vide qui apparait des qu'il y a un entete
if (display_columns || display_rows) {
if (display_border && (display_columns || display_rows)) {
qp -> setBrush(Qt::white);
QRectF first_rectangle(
diagram.topLeft().x(),
@@ -223,7 +226,7 @@ void BorderInset::draw(QPainter *qp, qreal x, qreal y) {
}
// dessine la numerotation des colonnes
if (display_columns) {
if (display_border && display_columns) {
for (int i = 1 ; i <= nb_columns ; ++ i) {
QRectF numbered_rectangle = QRectF(
diagram.topLeft().x() + (rows_header_width + ((i - 1) * columns_width)),
@@ -237,7 +240,7 @@ void BorderInset::draw(QPainter *qp, qreal x, qreal y) {
}
// dessine la numerotation des lignes
if (display_rows) {
if (display_border && display_rows) {
QString row_string("A");
for (int i = 1 ; i <= nb_rows ; ++ i) {
QRectF lettered_rectangle = QRectF(
@@ -258,19 +261,19 @@ void BorderInset::draw(QPainter *qp, qreal x, qreal y) {
qp -> drawRect(inset);
qp -> drawRect(inset_author);
qp -> drawText(inset_author, Qt::AlignVCenter | Qt::AlignLeft, tr(" Auteur : ") + bi_author);
qp -> drawText(inset_author, Qt::AlignVCenter | Qt::AlignLeft, QString(tr(" Auteur : %1", "inset content")).arg(bi_author));
qp -> drawRect(inset_date);
qp -> drawText(inset_date, Qt::AlignVCenter | Qt::AlignLeft, tr(" Date : ") + bi_date.toString("dd/MM/yyyy"));
qp -> drawText(inset_date, Qt::AlignVCenter | Qt::AlignLeft, QString(tr(" Date : %1", "inset content")).arg(bi_date.toString("dd/MM/yyyy")));
qp -> drawRect(inset_title);
qp -> drawText(inset_title, Qt::AlignVCenter | Qt::AlignCenter, tr("Titre du document : ") + bi_title);
qp -> drawText(inset_title, Qt::AlignVCenter | Qt::AlignCenter, QString(tr("Titre du document : %1", "inset content")).arg(bi_title));
qp -> drawRect(inset_file);
qp -> drawText(inset_file, Qt::AlignVCenter | Qt::AlignLeft, tr(" Fichier : ") + bi_filename);
qp -> drawText(inset_file, Qt::AlignVCenter | Qt::AlignLeft, QString(tr(" Fichier : %1", "inset content")).arg(bi_filename));
qp -> drawRect(inset_folio);
qp -> drawText(inset_folio, Qt::AlignVCenter | Qt::AlignLeft, tr(" Folio : ") + bi_folio);
qp -> drawText(inset_folio, Qt::AlignVCenter | Qt::AlignLeft, QString(tr(" Folio : %1", "inset content")).arg(bi_final_folio));
}
qp -> restore();
@@ -439,3 +442,20 @@ QString BorderInset::incrementLetters(const QString &string) {
}
}
}
/**
@param index numero du schema (de 1 a total)
@param total nombre total de schemas dans le projet
*/
void BorderInset::setFolioData(int index, int total) {
if (index < 1 || total < 1 || index > total) return;
// memorise les informations
folio_index_ = index;
folio_total_ = total;
// regenere le contenu du champ folio
bi_final_folio = bi_folio;
bi_final_folio.replace("%id", QString::number(folio_index_));
bi_final_folio.replace("%total", QString::number(folio_total_));
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -130,9 +130,15 @@ class BorderInset : public QObject {
/// @param date le nouveau contenu du champ "Date"
void setDate (const QDate &date) { bi_date = date; }
/// @param title le nouveau contenu du champ "Titre"
void setTitle (const QString &title) { bi_title = title; }
void setTitle (const QString &title) {
if (bi_title != title) {
bi_title = title;
emit(diagramTitleChanged(title));
}
}
/// @param folio le nouveau contenu du champ "Folio"
void setFolio (const QString &folio) { bi_folio = folio; }
void setFolioData(int, int);
/// @param filename le nouveau contenu du champ "Fichier"
void setFileName (const QString &filename) { bi_filename = filename; }
@@ -164,6 +170,17 @@ class BorderInset : public QObject {
*/
void displayChanged();
/**
Signal emis lorsque le titre du schema change
*/
void diagramTitleChanged(const QString &);
/**
Signal emis lorsque le cartouche requiert une mise a jour des donnees
utilisees pour generer le folio.
*/
void needFolioData();
// attributs
private:
// informations du cartouche
@@ -171,6 +188,9 @@ class BorderInset : public QObject {
QDate bi_date;
QString bi_title;
QString bi_folio;
QString bi_final_folio;
int folio_index_;
int folio_total_;
QString bi_filename;
// dimensions du cadre (lignes et colonnes)

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -18,9 +18,21 @@
#include "borderproperties.h"
/**
Constructeur
Constructeur. Initialise un objet BorderProperties avec les proprietes par
defaut suivantes :
* 17 colonnes affichees de 60.0 px de large pour 20.0px de haut
* 8 lignes affichees de 80.0 px de haut pour 20.0px de large
*/
BorderProperties::BorderProperties() {
BorderProperties::BorderProperties() :
columns_count(17),
columns_width(60.0),
columns_header_height(20.0),
display_columns(true),
rows_count(8),
rows_height(80.0),
rows_header_width(20.0),
display_rows(true)
{
}
/**
@@ -53,3 +65,58 @@ bool BorderProperties::operator==(const BorderProperties &bp) {
bool BorderProperties::operator!=(const BorderProperties &bp) {
return(!(*this == bp));
}
/**
Exporte les dimensions sous formes d'attributs XML ajoutes a l'element e.
@param e Element XML auquel seront ajoutes des attributs
*/
void BorderProperties::toXml(QDomElement &e) const {
e.setAttribute("cols", columns_count);
e.setAttribute("colsize", QString("%1").arg(columns_width));
e.setAttribute("rows", rows_count);
e.setAttribute("rowsize", QString("%1").arg(rows_height));
e.setAttribute("displaycols", display_columns ? "true" : "false");
e.setAttribute("displayrows", display_rows ? "true" : "false");
}
/**
Importe les dimensions a partir des attributs XML de l'element e
@param e Element XML dont les attributs seront lus
*/
void BorderProperties::fromXml(QDomElement &e) {
if (e.hasAttribute("cols")) columns_count = e.attribute("cols").toInt();
if (e.hasAttribute("colsize")) columns_width = e.attribute("colsize").toInt();
if (e.hasAttribute("rows")) rows_count = e.attribute("rows").toInt();
if (e.hasAttribute("rowsize")) rows_height = e.attribute("rowsize").toInt();
if (e.hasAttribute("displaycols")) display_columns = e.attribute("displaycols") == "true";
if (e.hasAttribute("displayrows")) display_rows = e.attribute("displayrows") == "true";
}
/**
Exporte les dimensions dans une configuration.
@param settings Parametres a ecrire
@param prefix prefixe a ajouter devant les noms des parametres
*/
void BorderProperties::toSettings(QSettings &settings, const QString &prefix) const {
settings.setValue(prefix + "cols", columns_count);
settings.setValue(prefix + "colsize", columns_width);
settings.setValue(prefix + "displaycols", display_columns);
settings.setValue(prefix + "rows", rows_count);
settings.setValue(prefix + "rowsize", rows_height);
settings.setValue(prefix + "displayrows", display_rows);
}
/**
Importe les dimensions depuis une configuration.
@param settings Parametres a lire
@param prefix prefixe a ajouter devant les noms des parametres
*/
void BorderProperties::fromSettings(QSettings &settings, const QString &prefix) {
columns_count = settings.value(prefix + "cols", columns_count).toInt();
columns_width = qRound(settings.value(prefix + "colsize", columns_width).toDouble());
display_columns = settings.value(prefix + "displaycols", display_columns).toBool();
rows_count = settings.value(prefix + "rows", rows_count).toInt();
rows_height = qRound(settings.value(prefix + "rowsize", rows_height).toDouble());
display_rows = settings.value(prefix + "displayrows", display_rows).toBool();
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -18,6 +18,7 @@
#ifndef BORDER_PROPERTIES_H
#define BORDER_PROPERTIES_H
#include <QtCore>
#include <QtXml>
/**
Cette classe est un conteneur pour les dimensions et proprietes d'affichage
d'un schema : affichage, nombre et dimensions des colonnes et lignes, ...
@@ -31,6 +32,11 @@ class BorderProperties {
bool operator==(const BorderProperties &);
bool operator!=(const BorderProperties &);
void toXml(QDomElement &) const;
void fromXml(QDomElement &);
void toSettings(QSettings &, const QString & = QString()) const;
void fromSettings(QSettings &, const QString & = QString());
// attributs
int columns_count; ///< Nombre de colonnes
qreal columns_width; ///< Largeur des colonnes

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -59,10 +59,10 @@ const BorderProperties &BorderPropertiesWidget::borderProperties() {
void BorderPropertiesWidget::setEditedBorder(const BorderProperties &bp) {
border_ = bp;
columns_count -> setValue(border_.columns_count);
columns_width -> setValue(border_.columns_width);
columns_width -> setValue(qRound(border_.columns_width));
display_columns -> setChecked(border_.display_columns);
rows_count -> setValue(border_.rows_count);
rows_height -> setValue(border_.rows_height);
rows_height -> setValue(qRound(border_.rows_height));
display_rows -> setChecked(border_.display_rows);
}
@@ -85,10 +85,10 @@ void BorderPropertiesWidget::build() {
columns_width = new QSpinBox(diagram_size_box);
columns_width -> setMinimum(qRound(BorderInset::minColumnsWidth()));
columns_width -> setSingleStep(10);
columns_width -> setPrefix(tr("\327"));
columns_width -> setSuffix(tr("px"));
columns_width -> setPrefix(tr("\327", "multiplication symbol"));
columns_width -> setSuffix(tr("px", "unit for cols width"));
display_columns = new QCheckBox(tr("Afficher les en-têtes"), diagram_size_box);
display_columns = new QCheckBox(tr("Afficher les en-t\352tes"), diagram_size_box);
// lignes : nombre et largeur
QLabel *ds2 = new QLabel(tr("Lignes :"));
@@ -99,10 +99,10 @@ void BorderPropertiesWidget::build() {
rows_height = new QSpinBox(diagram_size_box);
rows_height -> setMinimum(qRound(BorderInset::minRowsHeight()));
rows_height -> setSingleStep(10);
rows_height -> setPrefix(tr("\327"));
rows_height -> setSuffix(tr("px"));
rows_height -> setPrefix(tr("\327", "multiplication symbol"));
rows_height -> setSuffix(tr("px", "unit for rows height"));
display_rows = new QCheckBox(tr("Afficher les en-têtes"), diagram_size_box);
display_rows = new QCheckBox(tr("Afficher les en-t\352tes"), diagram_size_box);
// layout
diagram_size_box_layout -> addWidget(ds1, 0, 0);

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -937,7 +937,7 @@ QDomElement Conductor::toXml(QDomDocument &d, QHash<Terminal *, int> &table_adr_
}
// exporte la "configuration" du conducteur
properties_.toXml(d, e);
properties_.toXml(e);
return(e);
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -159,19 +159,18 @@ void SingleLineProperties::drawNeutral(QPainter *painter, QET::ConductorSegmentT
}
/**
exporte les parametres du conducteur unifilaire sous formes d'attributs XML
Exporte les parametres du conducteur unifilaire sous formes d'attributs XML
ajoutes a l'element e.
@param d Document XML ; utilise pour ajouter (potentiellement) des elements XML
@param e Element XML auquel seront ajoutes des attributs
*/
void SingleLineProperties::toXml(QDomDocument &, QDomElement &e) const {
void SingleLineProperties::toXml(QDomElement &e) const {
e.setAttribute("ground", hasGround ? "true" : "false");
e.setAttribute("neutral", hasNeutral ? "true" : "false");
e.setAttribute("phase", phases);
}
/**
importe les parametres du conducteur unifilaire a partir des attributs XML
Importe les parametres du conducteur unifilaire a partir des attributs XML
de l'element e
@param e Element XML dont les attributs seront lus
*/
@@ -182,22 +181,21 @@ void SingleLineProperties::fromXml(QDomElement &e) {
}
/**
exporte les parametres du conducteur sous formes d'attributs XML
Exporte les parametres du conducteur sous formes d'attributs XML
ajoutes a l'element e.
@param d Document XML ; utilise pour ajouter (potentiellement) des elements XML
@param e Element XML auquel seront ajoutes des attributs
*/
void ConductorProperties::toXml(QDomDocument &d, QDomElement &e) const {
void ConductorProperties::toXml(QDomElement &e) const {
e.setAttribute("type", typeToString(type));
if (type == Single) {
singleLineProperties.toXml(d, e);
singleLineProperties.toXml(e);
} else if (type == Multi) {
e.setAttribute("num", text);
}
}
/**
importe les parametres du conducteur unifilaire a partir des attributs XML
Importe les parametres du conducteur unifilaire a partir des attributs XML
de l'element e
@param e Element XML dont les attributs seront lus
*/
@@ -217,7 +215,7 @@ void ConductorProperties::fromXml(QDomElement &e) {
/**
@param settings Parametres a ecrire
@param prefix prefix a ajouter devant les noms des parametres
@param prefix prefixe a ajouter devant les noms des parametres
*/
void ConductorProperties::toSettings(QSettings &settings, const QString &prefix) const {
settings.setValue(prefix + "type", typeToString(type));
@@ -227,7 +225,7 @@ void ConductorProperties::toSettings(QSettings &settings, const QString &prefix)
/**
@param settings Parametres a lire
@param prefix prefix a ajouter devant les noms des parametres
@param prefix prefixe a ajouter devant les noms des parametres
*/
void ConductorProperties::fromSettings(QSettings &settings, const QString &prefix) {
QString setting_type = settings.value(prefix + "type", typeToString(Multi)).toString();

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -31,7 +31,7 @@ class SingleLineProperties {
void setPhasesCount(int);
unsigned short int phasesCount();
void draw(QPainter *, QET::ConductorSegmentType, const QRectF &);
void toXml(QDomDocument &, QDomElement &) const;
void toXml(QDomElement &) const;
void fromXml(QDomElement &);
void toSettings(QSettings &, const QString & = QString()) const;
void fromSettings(QSettings &, const QString & = QString());
@@ -87,7 +87,7 @@ class ConductorProperties {
SingleLineProperties singleLineProperties;
// methodes
void toXml(QDomDocument &, QDomElement &) const;
void toXml(QDomElement &) const;
void fromXml(QDomElement &);
void toSettings(QSettings &, const QString & = QString()) const;
void fromSettings(QSettings &, const QString & = QString());

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -19,7 +19,6 @@
#define CONDUCTOR_PROPERTIES_WIDGET_H
#include "conductorproperties.h"
#include <QWidget>
/**
Ce widget permet a l utilisateur d'editer les proprietes d'un conducteur.
Par proprietes, on entend non pas le trajet effectue par le conducteur mais

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -24,12 +24,12 @@
*/
ConfigDialog::ConfigDialog(QWidget *parent) : QDialog(parent) {
setWindowTitle(tr("Configurer QElectroTech"));
setWindowTitle(tr("Configurer QElectroTech", "window title"));
// liste des pages
pages_list = new QListWidget();
pages_list -> setViewMode(QListView::IconMode);
pages_list -> setIconSize(QSize(48, 48));
pages_list -> setIconSize(QSize(110, 110));
pages_list -> setMovement(QListView::Static);
pages_list -> setMinimumWidth(135);
pages_list -> setMaximumWidth(135);
@@ -37,6 +37,7 @@ ConfigDialog::ConfigDialog(QWidget *parent) : QDialog(parent) {
// pages
pages_widget = new QStackedWidget();
addPage(new GeneralConfigurationPage());
addPage(new NewDiagramPage());
buildPagesList();

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -28,10 +28,6 @@
@param parent QWidget parent
*/
NewDiagramPage::NewDiagramPage(QWidget *parent) : ConfigPage(parent) {
// acces a la configuration de QElectroTech
QSettings &settings = QETApp::settings();
// dimensions par defaut d'un schema
bpw = new BorderPropertiesWidget(QETDiagramEditor::defaultBorderProperties());
@@ -39,14 +35,12 @@ NewDiagramPage::NewDiagramPage(QWidget *parent) : ConfigPage(parent) {
ipw = new InsetPropertiesWidget(QETDiagramEditor::defaultInsetProperties(), true);
// proprietes par defaut des conducteurs
ConductorProperties cp;
cp.fromSettings(settings, "diagrameditor/defaultconductor");
cpw = new ConductorPropertiesWidget(cp);
cpw = new ConductorPropertiesWidget(QETDiagramEditor::defaultConductorProperties());
cpw -> setContentsMargins(0, 0, 0, 0);
QVBoxLayout *vlayout1 = new QVBoxLayout();
QLabel *title = new QLabel(tr("Nouveau sch\351ma"));
QLabel *title = new QLabel(this -> title());
vlayout1 -> addWidget(title);
QFrame *horiz_line = new QFrame();
@@ -78,28 +72,10 @@ void NewDiagramPage::applyConf() {
QSettings &settings = QETApp::settings();
// dimensions des nouveaux schemas
BorderProperties border = bpw -> borderProperties();
settings.setValue("diagrameditor/defaultcols", border.columns_count);
settings.setValue("diagrameditor/defaultcolsize", border.columns_width);
settings.setValue("diagrameditor/defaultdisplaycols", border.display_columns);
settings.setValue("diagrameditor/defaultrows", border.rows_count);
settings.setValue("diagrameditor/defaultrowsize", border.rows_height);
settings.setValue("diagrameditor/defaultdisplayrows", border.display_rows);
bpw -> borderProperties().toSettings(settings, "diagrameditor/default");
// proprietes du cartouche
InsetProperties inset = ipw-> insetProperties();
settings.setValue("diagrameditor/defaulttitle", inset.title);
settings.setValue("diagrameditor/defaultauthor", inset.author);
settings.setValue("diagrameditor/defaultfilename", inset.filename);
settings.setValue("diagrameditor/defaultfolio", inset.folio);
QString date_setting_value;
if (inset.useDate == InsetProperties::UseDateValue) {
if (inset.date.isNull()) date_setting_value = "null";
else date_setting_value = inset.date.toString("yyyyMMdd");
} else {
date_setting_value = "now";
}
settings.setValue("diagrameditor/defaultdate", date_setting_value);
ipw-> insetProperties().toSettings(settings, "diagrameditor/default");
// proprietes par defaut des conducteurs
cpw -> conductorProperties().toSettings(settings, "diagrameditor/defaultconductor");
@@ -107,10 +83,90 @@ void NewDiagramPage::applyConf() {
/// @return l'icone de cette page
QIcon NewDiagramPage::icon() const {
return(QIcon(":/ico/conf_new_diagram.png"));
return(QIcon(":/ico/conf_new_diagram_110.png"));
}
/// @return le titre de cette page
QString NewDiagramPage::title() const {
return(tr("Nouveau sch\351ma"));
return(tr("Nouveau sch\351ma", "configuration page title"));
}
/**
Constructeur
@param parent QWidget parent
*/
GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) : ConfigPage(parent) {
// acces a la configuration de QElectroTech
QSettings &settings = QETApp::settings();
bool tabbed = settings.value("diagrameditor/viewmode", "windowed") == "tabbed";
bool integrate_elements = settings.value("diagrameditor/integrate-elements", true).toBool();
projects_view_mode_ = new QGroupBox(tr("Projets"), this);
windowed_mode_ = new QRadioButton(tr("Utiliser des fen\352tres"), projects_view_mode_);
tabbed_mode_ = new QRadioButton(tr("Utiliser des onglets"), projects_view_mode_);
warning_view_mode_ = new QLabel(tr("Ces param\350tres s'appliqueront d\350s la prochaine ouverture d'un \351diteur de sch\351mas."));
elements_management_ = new QGroupBox(tr("Gestion des \351l\351ments"), this);
integrate_elements_ = new QCheckBox(tr("Int\351grer automatiquement les \351l\351ments dans les projets (recommand\351)"), elements_management_);
if (tabbed) {
tabbed_mode_ -> setChecked(true);
} else {
windowed_mode_ -> setChecked(true);
}
integrate_elements_ -> setChecked(integrate_elements);
QVBoxLayout *projects_view_mode_layout = new QVBoxLayout();
projects_view_mode_layout -> addWidget(windowed_mode_);
projects_view_mode_layout -> addWidget(tabbed_mode_);
projects_view_mode_layout -> addWidget(warning_view_mode_);
projects_view_mode_ -> setLayout(projects_view_mode_layout);
QVBoxLayout *elements_management_layout = new QVBoxLayout();
elements_management_layout -> addWidget(integrate_elements_);
elements_management_ -> setLayout(elements_management_layout);
QVBoxLayout *vlayout1 = new QVBoxLayout();
QLabel *title_label_ = new QLabel(title());
vlayout1 -> addWidget(title_label_);
QFrame *horiz_line_ = new QFrame();
horiz_line_ -> setFrameShape(QFrame::HLine);
vlayout1 -> addWidget(horiz_line_);
vlayout1 -> addWidget(projects_view_mode_);
vlayout1 -> addWidget(elements_management_);
vlayout1 -> addStretch();
setLayout(vlayout1);
}
/// Destructeur
GeneralConfigurationPage::~GeneralConfigurationPage() {
}
/**
Applique la configuration de cette page
*/
void GeneralConfigurationPage::applyConf() {
QSettings &settings = QETApp::settings();
QString view_mode = tabbed_mode_ -> isChecked() ? "tabbed" : "windowed";
settings.setValue("diagrameditor/viewmode", view_mode) ;
settings.setValue("diagrameditor/integrate-elements", integrate_elements_ -> isChecked());
}
/// @return l'icone de cette page
QIcon GeneralConfigurationPage::icon() const {
return(QIcon(":/ico/settings.png"));
}
/// @return le titre de cette page
QString GeneralConfigurationPage::title() const {
return(tr("G\351n\351ral", "configuration page title"));
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -21,7 +21,6 @@
class BorderPropertiesWidget;
class ConductorPropertiesWidget;
class InsetPropertiesWidget;
/**
Cette classe abstraite contient les methodes que toutes les pages de
configuration doivent implementer.
@@ -68,4 +67,34 @@ class NewDiagramPage : public ConfigPage {
InsetPropertiesWidget *ipw; ///< Widget d'edition des proprietes par defaut du cartouche
ConductorPropertiesWidget *cpw; ///< Widget d'edition des proprietes par defaut des conducteurs
};
/**
Cette classe represente la page de configuration generale.
*/
class GeneralConfigurationPage : public ConfigPage {
Q_OBJECT
// constructeurs, destructeur
public:
GeneralConfigurationPage(QWidget * = 0);
virtual ~GeneralConfigurationPage();
private:
GeneralConfigurationPage(const GeneralConfigurationPage &);
// methodes
public:
void applyConf();
QString title() const;
QIcon icon() const;
// attributs
public:
QLabel *title_label_;
QFrame *horiz_line_;
QGroupBox *projects_view_mode_;
QRadioButton *windowed_mode_;
QRadioButton *tabbed_mode_;
QLabel *warning_view_mode_;
QGroupBox *elements_management_;
QCheckBox *integrate_elements_;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -19,72 +19,103 @@
#include "elementtextitem.h"
#include "diagram.h"
#include "qetapp.h"
#include "partline.h"
#include "elementdefinition.h"
#include <iostream>
/**
Constructeur de la classe ElementPerso. Permet d'instancier un element
utilisable comme un element fixe a la difference que l'element perso lit
sa description (noms, dessin, comportement) dans un fichier XML a fournir
en parametre.
@param nom_fichier Le chemin du fichier XML decrivant l'element
Constructeur de la classe CustomElement. Permet d'instancier un element
utilisable comme un element fixe a la difference que l'element perso est
construit a partir d'une description au format XML. Celle-ci est recuperee
a l'emplacement indique.
@param location Emplacement de la definition d'element a utiliser
@param qgi Le QGraphicsItem parent de cet element
@param s Le Schema affichant cet element
@param etat Un pointeur facultatif vers un entier. La valeur de cet entier
@param state Un pointeur facultatif vers un entier. La valeur de cet entier
sera changee de maniere a refleter le deroulement de l'instanciation :
- 0 : L'instanciation a reussi
- 1 : Le fichier n'existe pas
- 2 : Le fichier n'a pu etre ouvert
- 3 : Le fichier n'est pas un document XML
- 4 : Le document XML n'a pas une "definition" comme racine
- 1 : l'emplacement n'a pas permis d'acceder a une definition d'element
- 2 : la definition n'etait pas lisible
- 3 : la definition n'etait pas valide / exploitable / utilisable
- 4 : Le document XML n'est pas un element "definition"
- 5 : Les attributs de la definition ne sont pas presents et / ou valides
- 6 : La definition est vide
- 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
- 8 : Aucune partie du dessin n'a pu etre chargee
*/
CustomElement::CustomElement(QString &nom_fichier, QGraphicsItem *qgi, Diagram *s, int *etat) : FixedElement(qgi, s) {
nomfichier = nom_fichier;
// pessimisme inside : par defaut, ca foire
elmt_etat = -1;
// le fichier doit exister
QFileInfo infos_file(nomfichier);
if (!infos_file.exists() || !infos_file.isFile()) {
if (etat != NULL) *etat = 1;
elmt_etat = 1;
CustomElement::CustomElement(const ElementsLocation &location, QGraphicsItem *qgi, Diagram *s, int *state) :
FixedElement(qgi, s),
elmt_state(-1),
location_(location)
{
// recupere la definition de l'element
ElementsCollectionItem *element_item = QETApp::collectionItem(location);
ElementDefinition *element_definition;
if (
!element_item ||\
!element_item -> isElement() ||\
!(element_definition = qobject_cast<ElementDefinition *>(element_item))
) {
if (state) *state = 1;
elmt_state = 1;
return;
}
// le fichier doit etre lisible
QFile fichier(nomfichier);
if (!fichier.open(QIODevice::ReadOnly)) {
if (etat != NULL) *etat = 2;
elmt_etat = 2;
if (!element_definition -> isReadable()) {
if (state) *state = 2;
elmt_state = 2;
return;
}
// le fichier doit etre un document XML
QDomDocument document_xml;
if (!document_xml.setContent(&fichier)) {
if (etat != NULL) *etat = 3;
elmt_etat = 3;
if (element_definition -> isNull()) {
if (state) *state = 3;
elmt_state = 3;
return;
}
// la racine est supposee etre une definition d'element
QDomElement racine = document_xml.documentElement();
if (racine.tagName() != "definition" || racine.attribute("type") != "element") {
if (etat != NULL) *etat = 4;
elmt_etat = 4;
return;
buildFromXml(element_definition -> xml(), &elmt_state);
if (state) *state = elmt_state;
if (elmt_state) return;
if (state) *state = 0;
elmt_state = 0;
}
CustomElement::CustomElement(const QDomElement &xml_def_elmt, QGraphicsItem *qgi, Diagram *s, int *state) : FixedElement(qgi, s) {
int elmt_state = -1;
buildFromXml(xml_def_elmt, &elmt_state);
if (state) *state = elmt_state;
}
/**
Construit l'element personnalise a partir d'un element XML representant sa
definition.
@param xml_def_elmt
@param state Un pointeur facultatif vers un entier. La valeur de cet entier
sera changee de maniere a refleter le deroulement de l'instanciation :
- 0 : La construction s'est bien passee
- 4 : Le document XML n'est pas un element "definition"
- 5 : Les attributs de la definition ne sont pas presents et / ou valides
- 6 : La definition est vide
- 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
- 8 : Aucune partie du dessin n'a pu etre chargee
@return true si le chargement a reussi, false sinon
*/
bool CustomElement::buildFromXml(const QDomElement &xml_def_elmt, int *state) {
if (xml_def_elmt.tagName() != "definition" || xml_def_elmt.attribute("type") != "element") {
if (state) *state = 4;
return(false);
}
// verifie basiquement que la version actuelle est capable de lire ce fichier
if (racine.hasAttribute("version")) {
if (xml_def_elmt.hasAttribute("version")) {
bool conv_ok;
qreal element_version = racine.attribute("version").toDouble(&conv_ok);
qreal element_version = xml_def_elmt.attribute("version").toDouble(&conv_ok);
if (conv_ok && QET::version.toDouble() < element_version) {
std::cerr << qPrintable(
QObject::tr("Avertissement : l'\351l\351ment ") + nom_fichier
+ QObject::tr(" a \351t\351 enregistr\351 avec une version"
QObject::tr("Avertissement : l'\351l\351ment "
" a \351t\351 enregistr\351 avec une version"
" ult\351rieure de QElectroTech.")
) << std::endl;
}
@@ -93,32 +124,30 @@ CustomElement::CustomElement(QString &nom_fichier, QGraphicsItem *qgi, Diagram *
// ces attributs doivent etre presents et valides
int w, h, hot_x, hot_y;
if (
!QET::attributeIsAnInteger(racine, QString("width"), &w) ||\
!QET::attributeIsAnInteger(racine, QString("height"), &h) ||\
!QET::attributeIsAnInteger(racine, QString("hotspot_x"), &hot_x) ||\
!QET::attributeIsAnInteger(racine, QString("hotspot_y"), &hot_y) ||\
!validOrientationAttribute(racine)
!QET::attributeIsAnInteger(xml_def_elmt, QString("width"), &w) ||\
!QET::attributeIsAnInteger(xml_def_elmt, QString("height"), &h) ||\
!QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_x"), &hot_x) ||\
!QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_y"), &hot_y) ||\
!validOrientationAttribute(xml_def_elmt)
) {
if (etat != NULL) *etat = 5;
elmt_etat = 5;
return;
if (state) *state = 5;
return(false);
}
// on peut d'ores et deja specifier la taille et le hotspot
setSize(w, h);
setHotspot(QPoint(hot_x, hot_y));
setInternalConnections(racine.attribute("ic") == "true");
setInternalConnections(xml_def_elmt.attribute("ic") == "true");
// la definition est supposee avoir des enfants
if (racine.firstChild().isNull()) {
if (etat != NULL) *etat = 6;
elmt_etat = 6;
return;
if (xml_def_elmt.firstChild().isNull()) {
if (state) *state = 6;
return(false);
}
// initialisation du QPainter (pour dessiner l'element)
QPainter qp;
qp.begin(&dessin);
qp.begin(&drawing);
QPen t;
t.setColor(Qt::black);
t.setWidthF(1.0);
@@ -126,12 +155,12 @@ CustomElement::CustomElement(QString &nom_fichier, QGraphicsItem *qgi, Diagram *
qp.setPen(t);
// extrait les noms de la definition XML
names.fromXml(racine);
setToolTip(nom());
names.fromXml(xml_def_elmt);
setToolTip(name());
// parcours des enfants de la definition : parties du dessin
int nb_elements_parses = 0;
for (QDomNode node = racine.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
int parsed_elements_count = 0;
for (QDomNode node = xml_def_elmt.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
QDomElement elmts = node.toElement();
if (elmts.isNull()) continue;
if (elmts.tagName() == "description") {
@@ -140,11 +169,10 @@ CustomElement::CustomElement(QString &nom_fichier, QGraphicsItem *qgi, Diagram *
for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
QDomElement qde = n.toElement();
if (qde.isNull()) continue;
if (parseElement(qde, qp)) ++ nb_elements_parses;
if (parseElement(qde, qp)) ++ parsed_elements_count;
else {
if (etat != NULL) *etat = 7;
elmt_etat = 7;
return;
if (state) *state = 7;
return(false);
}
}
}
@@ -154,17 +182,13 @@ CustomElement::CustomElement(QString &nom_fichier, QGraphicsItem *qgi, Diagram *
qp.end();
// il doit y avoir au moins un element charge
if (!nb_elements_parses) {
if (etat != NULL) *etat = 8;
elmt_etat = 8;
return;
if (!parsed_elements_count) {
if (state) *state = 8;
return(false);
} else {
if (state) *state = 0;
return(true);
}
// fermeture du fichier
fichier.close();
if (etat != NULL) *etat = 0;
elmt_etat = 0;
}
/**
@@ -188,7 +212,7 @@ QList<Conductor *> CustomElement::conductors() const {
/**
@return Le nombre de bornes que l'element possede
*/
int CustomElement::nbTerminals() const {
int CustomElement::terminalsCount() const {
return(list_terminals.size());
}
@@ -198,7 +222,7 @@ int CustomElement::nbTerminals() const {
@param options Les options graphiques
*/
void CustomElement::paint(QPainter *qp, const QStyleOptionGraphicsItem *) {
dessin.play(qp);
drawing.play(qp);
}
/**
@@ -217,6 +241,7 @@ void CustomElement::paint(QPainter *qp, const QStyleOptionGraphicsItem *) {
bool CustomElement::parseElement(QDomElement &e, QPainter &qp) {
if (e.tagName() == "terminal") return(parseTerminal(e));
else if (e.tagName() == "line") return(parseLine(e, qp));
else if (e.tagName() == "rect") return(parseRect(e, qp));
else if (e.tagName() == "ellipse") return(parseEllipse(e, qp));
else if (e.tagName() == "circle") return(parseCircle(e, qp));
else if (e.tagName() == "arc") return(parseArc(e, qp));
@@ -244,9 +269,125 @@ bool CustomElement::parseLine(QDomElement &e, QPainter &qp) {
if (!QET::attributeIsAReal(e, QString("y1"), &y1)) return(false);
if (!QET::attributeIsAReal(e, QString("x2"), &x2)) return(false);
if (!QET::attributeIsAReal(e, QString("y2"), &y2)) return(false);
QET::EndType first_end = QET::endTypeFromString(e.attribute("end1"));
QET::EndType second_end = QET::endTypeFromString(e.attribute("end2"));
qreal length1, length2;
if (!QET::attributeIsAReal(e, QString("length1"), &length1)) length1 = 1.5;
if (!QET::attributeIsAReal(e, QString("length2"), &length2)) length2 = 1.5;
qp.save();
setPainterStyle(e, qp);
qp.drawLine(QLineF(x1, y1, x2, y2));
QPen t = qp.pen();
t.setJoinStyle(Qt::MiterJoin);
qp.setPen(t);
//qp.drawLine(QLineF(x1, y1, x2, y2));
QLineF line(x1, y1, x2, y2);
QPointF point1(line.p1());
QPointF point2(line.p2());
qreal line_length(line.length());
qreal pen_width = qp.pen().widthF();
// determine s'il faut dessiner les extremites
bool draw_1st_end, draw_2nd_end;
qreal reduced_line_length = line_length - (length1 * PartLine::requiredLengthForEndType(first_end));
draw_1st_end = first_end && reduced_line_length >= 0;
if (draw_1st_end) {
reduced_line_length -= (length2 * PartLine::requiredLengthForEndType(second_end));
} else {
reduced_line_length = line_length - (length2 * PartLine::requiredLengthForEndType(second_end));
}
draw_2nd_end = second_end && reduced_line_length >= 0;
// dessine la premiere extremite
QPointF start_point, stop_point;
if (draw_1st_end) {
QList<QPointF> four_points1(PartLine::fourEndPoints(point1, point2, length1));
if (first_end == QET::Circle) {
qp.drawEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
start_point = four_points1[1];
} else if (first_end == QET::Diamond) {
qp.drawPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3]);
start_point = four_points1[1];
} else if (first_end == QET::Simple) {
qp.drawPolyline(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
start_point = point1;
} else if (first_end == QET::Triangle) {
qp.drawPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3]);
start_point = four_points1[0];
}
// ajuste le depart selon l'epaisseur du trait
if (pen_width && (first_end == QET::Simple || first_end == QET::Circle)) {
start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
}
} else {
start_point = point1;
}
// dessine la seconde extremite
if (draw_2nd_end) {
QList<QPointF> four_points2(PartLine::fourEndPoints(point2, point1, length2));
if (second_end == QET::Circle) {
qp.drawEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
stop_point = four_points2[1];
} else if (second_end == QET::Diamond) {
qp.drawPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1]);
stop_point = four_points2[1];
} else if (second_end == QET::Simple) {
qp.drawPolyline(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
stop_point = point2;
} else if (second_end == QET::Triangle) {
qp.drawPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
stop_point = four_points2[0];
}
// ajuste l'arrivee selon l'epaisseur du trait
if (pen_width && (second_end == QET::Simple || second_end == QET::Circle)) {
stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
}
} else {
stop_point = point2;
}
qp.drawLine(start_point, stop_point);
qp.restore();
return(true);
}
/**
Analyse un element XML suppose representer un rectangle. Si l'analyse
reussit, le rectangle est ajoute au dessin.
Le rectangle est defini par les attributs suivants :
- x : abscisse du coin superieur gauche du rectangle
- y : ordonnee du coin superieur gauche du rectangle
- width : largeur du rectangle
- height : hauteur du rectangle
@param e L'element XML a analyser
@param qp Le QPainter a utiliser pour dessiner l'element perso
@return true si l'analyse reussit, false sinon
*/
bool CustomElement::parseRect(QDomElement &e, QPainter &qp) {
// verifie la presence des attributs obligatoires
double rect_x, rect_y, rect_w, rect_h;
if (!QET::attributeIsAReal(e, QString("x"), &rect_x)) return(false);
if (!QET::attributeIsAReal(e, QString("y"), &rect_y)) return(false);
if (!QET::attributeIsAReal(e, QString("width"), &rect_w)) return(false);
if (!QET::attributeIsAReal(e, QString("height"), &rect_h)) return(false);
qp.save();
setPainterStyle(e, qp);
// force le type de jointures pour les rectangles
QPen p = qp.pen();
p.setJoinStyle(Qt::MiterJoin);
qp.setPen(p);
qp.drawRect(QRectF(rect_x, rect_y, rect_w, rect_h));
qp.restore();
return(true);
}
@@ -262,7 +403,6 @@ bool CustomElement::parseLine(QDomElement &e, QPainter &qp) {
@param e L'element XML a analyser
@param qp Le QPainter a utiliser pour dessiner l'element perso
@return true si l'analyse reussit, false sinon
@todo utiliser des attributs plus coherents : x et y = centre, rayon = vrai rayon
*/
bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) {
// verifie la presence des attributs obligatoires
@@ -289,7 +429,6 @@ bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) {
@param e L'element XML a analyser
@param qp Le QPainter a utiliser pour dessiner l'element perso
@return true si l'analyse reussit, false sinon
@todo utiliser des attributs plus coherents : x et y = centre
*/
bool CustomElement::parseEllipse(QDomElement &e, QPainter &qp) {
// verifie la presence des attributs obligatoires
@@ -405,23 +544,23 @@ bool CustomElement::parseText(QDomElement &e, QPainter &qp) {
- une taille
- le fait de subir les rotations de l'element ou non
@param e L'element XML a analyser
@param s Le schema sur lequel l'element perso sera affiche
@return true si l'analyse reussit, false sinon
@return Un pointeur vers l'objet ElementTextItem ainsi cree si l'analyse reussit, 0 sinon
*/
bool CustomElement::parseInput(QDomElement &e) {
ElementTextItem *CustomElement::parseInput(QDomElement &e) {
qreal pos_x, pos_y;
int size;
if (
!QET::attributeIsAReal(e, "x", &pos_x) ||\
!QET::attributeIsAReal(e, "y", &pos_y) ||\
!QET::attributeIsAnInteger(e, "size", &size)
) return(false);
) return(0);
ElementTextItem *eti = new ElementTextItem(e.attribute("text"), this);
eti -> setFont(QFont(QETApp::diagramTextsFont(), size));
eti -> setPos(pos_x, pos_y);
eti -> setOriginalPos(QPointF(pos_x, pos_y));
if (e.attribute("rotate") == "true") eti -> setFollowParentRotations(true);
return(true);
return(eti);
}
/**
@@ -432,23 +571,23 @@ bool CustomElement::parseInput(QDomElement &e) {
- orientation : orientation de la borne = Nord (n), Sud (s), Est (e) ou Ouest (w)
@param e L'element XML a analyser
@param s Le schema sur lequel l'element perso sera affiche
@return true si l'analyse reussit, false sinon
@return Un pointeur vers l'objet Terminal ainsi cree, 0 sinon
*/
bool CustomElement::parseTerminal(QDomElement &e) {
Terminal *CustomElement::parseTerminal(QDomElement &e) {
// verifie la presence et la validite des attributs obligatoires
double terminalx, terminaly;
QET::Orientation terminalo;
if (!QET::attributeIsAReal(e, QString("x"), &terminalx)) return(false);
if (!QET::attributeIsAReal(e, QString("y"), &terminaly)) return(false);
if (!e.hasAttribute("orientation")) return(false);
if (!QET::attributeIsAReal(e, QString("x"), &terminalx)) return(0);
if (!QET::attributeIsAReal(e, QString("y"), &terminaly)) return(0);
if (!e.hasAttribute("orientation")) return(0);
if (e.attribute("orientation") == "n") terminalo = QET::North;
else if (e.attribute("orientation") == "s") terminalo = QET::South;
else if (e.attribute("orientation") == "e") terminalo = QET::East;
else if (e.attribute("orientation") == "w") terminalo = QET::West;
else return(false);
list_terminals << new Terminal(terminalx, terminaly, terminalo, this, qobject_cast<Diagram *>(scene()));
return(true);
else return(0);
Terminal *new_terminal = new Terminal(terminalx, terminaly, terminalo, this, qobject_cast<Diagram *>(scene()));
list_terminals << new_terminal;
return(new_terminal);
}
/**
@@ -481,7 +620,7 @@ void CustomElement::setQPainterAntiAliasing(QPainter &qp, bool aa) {
@param e Element XML
@return true si l'attribut "orientation" est valide, false sinon
*/
bool CustomElement::validOrientationAttribute(QDomElement &e) {
bool CustomElement::validOrientationAttribute(const QDomElement &e) {
return(ori.fromString(e.attribute("orientation")));
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -15,13 +15,14 @@
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ELEMENTPERSO_H
#define ELEMENTPERSO_H
#ifndef CUSTOM_ELEMENT_H
#define CUSTOM_ELEMENT_H
#include "fixedelement.h"
#include <QtGui>
#include "nameslist.h"
class CustomElementPart;
#include "elementslocation.h"
class ElementTextItem;
class Terminal;
/**
Cette classe represente un element electrique. Elle est utilisable
comme un element fixe. La difference est que l'element perso lit
@@ -29,65 +30,69 @@ class CustomElementPart;
en parametre.
*/
class CustomElement : public FixedElement {
Q_OBJECT
// constructeurs, destructeur
public:
CustomElement(QString &, QGraphicsItem * = 0, Diagram * = 0, int * = NULL);
CustomElement(const ElementsLocation &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
CustomElement(const QDomElement &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
virtual ~CustomElement();
friend class CustomElementPart;
private:
CustomElement(const CustomElement &);
// attributs
private:
int elmt_etat; // contient le code d'erreur si l'instanciation a echoue ou 0 si l'instanciation s'est bien passe
protected:
int elmt_state; // contient le code d'erreur si l'instanciation a echoue ou 0 si l'instanciation s'est bien passe
NamesList names;
QString nomfichier;
QPicture dessin;
ElementsLocation location_;
QPicture drawing;
QList<Terminal *> list_terminals;
// methodes
public:
virtual QList<Terminal *> terminals() const;
virtual QList<Conductor *> conductors() const;
virtual int nbTerminals() const;
virtual int terminalsCount() const;
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *);
QString typeId() const;
QString fichier() const;
ElementsLocation location() const;
bool isNull() const;
int etat() const;
QString nom() const;
int state() const;
QString name() const;
private:
bool parseElement(QDomElement &, QPainter &);
bool parseLine(QDomElement &, QPainter &);
bool parseEllipse(QDomElement &, QPainter &);
bool parseCircle(QDomElement &, QPainter &);
bool parseArc(QDomElement &, QPainter &);
bool parsePolygon(QDomElement &, QPainter &);
bool parseText(QDomElement &, QPainter &);
bool parseInput(QDomElement &);
bool parseTerminal(QDomElement &);
void setQPainterAntiAliasing(QPainter &, bool);
bool validOrientationAttribute(QDomElement &);
void setPainterStyle(QDomElement &, QPainter &);
protected:
virtual bool buildFromXml(const QDomElement &, int * = 0);
virtual bool parseElement(QDomElement &, QPainter &);
virtual bool parseLine(QDomElement &, QPainter &);
virtual bool parseRect(QDomElement &, QPainter &);
virtual bool parseEllipse(QDomElement &, QPainter &);
virtual bool parseCircle(QDomElement &, QPainter &);
virtual bool parseArc(QDomElement &, QPainter &);
virtual bool parsePolygon(QDomElement &, QPainter &);
virtual bool parseText(QDomElement &, QPainter &);
virtual ElementTextItem *parseInput(QDomElement &);
virtual Terminal *parseTerminal(QDomElement &);
virtual void setQPainterAntiAliasing(QPainter &, bool);
virtual bool validOrientationAttribute(const QDomElement &);
virtual void setPainterStyle(QDomElement &, QPainter &);
};
/**
@return L'ID du type de l'element ; pour un CustomElement, cela revient au
nom du fichier
@see fichier()
@see location()
*/
inline QString CustomElement::typeId() const {
return(nomfichier);
return(location_.path());
}
/**
@return L'adresse du fichier contenant la description XML de cet element
*/
inline QString CustomElement::fichier() const {
return(nomfichier);
inline ElementsLocation CustomElement::location() const {
return(location_);
}
/**
@@ -95,7 +100,7 @@ inline QString CustomElement::fichier() const {
description XML a echoue
*/
inline bool CustomElement::isNull() const {
return(elmt_etat != 0);
return(elmt_state);
}
/**
@@ -110,15 +115,15 @@ inline bool CustomElement::isNull() const {
- 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
- 8 : Aucune partie du dessin n'a pu etre chargee
*/
inline int CustomElement::etat() const {
return(elmt_etat);
inline int CustomElement::state() const {
return(elmt_state);
}
/**
@return Le nom de l'element
*/
inline QString CustomElement::nom() const {
return(names.name(QFileInfo(nomfichier).baseName()));
inline QString CustomElement::name() const {
return(names.name(location_.baseName()));
}
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#include "customelement.h"
#include "diagram.h"
#include "exportdialog.h"
#include "ghostelement.h"
#include "diagramcommands.h"
#include "diagramcontent.h"
@@ -37,7 +38,9 @@ Diagram::Diagram(QObject *parent) :
draw_grid(true),
use_border(true),
moved_elements_fetched(false),
draw_terminals(true)
draw_terminals(true),
project_(0),
read_only_(false)
{
undo_stack = new QUndoStack();
qgi_manager = new QGIManager(this);
@@ -51,9 +54,6 @@ Diagram::Diagram(QObject *parent) :
conductor_setter -> setPen(t);
conductor_setter -> setLine(QLineF(QPointF(0.0, 0.0), QPointF(0.0, 0.0)));
connect(this, SIGNAL(selectionChanged()), this, SLOT(slot_checkSelectionEmptinessChange()));
// lit les caracteristiques des conducteurs par defaut dans la configuration
defaultConductorProperties.fromSettings(QETApp::settings(), "diagrameditor/defaultconductor");
}
/**
@@ -77,6 +77,7 @@ Diagram::~Diagram() {
foreach(QGraphicsItem *qgi_d, deletable_items) {
delete qgi_d;
}
// qDebug() << "Suppression du schema" << ((void*)this);
}
/**
@@ -125,15 +126,17 @@ void Diagram::drawBackground(QPainter *p, const QRectF &r) {
@param e QKeyEvent decrivant l'evenement clavier
*/
void Diagram::keyPressEvent(QKeyEvent *e) {
QPointF movement;
switch(e -> key()) {
case Qt::Key_Left: movement = QPointF(-xGrid, 0.0); break;
case Qt::Key_Right: movement = QPointF(+xGrid, 0.0); break;
case Qt::Key_Up: movement = QPointF(0.0, -yGrid); break;
case Qt::Key_Down: movement = QPointF(0.0, +yGrid); break;
}
if (!movement.isNull() && !focusItem()) {
moveElements(movement);
if (!isReadOnly()) {
QPointF movement;
switch(e -> key()) {
case Qt::Key_Left: movement = QPointF(-xGrid, 0.0); break;
case Qt::Key_Right: movement = QPointF(+xGrid, 0.0); break;
case Qt::Key_Up: movement = QPointF(0.0, -yGrid); break;
case Qt::Key_Down: movement = QPointF(0.0, +yGrid); break;
}
if (!movement.isNull() && !focusItem()) {
moveElements(movement);
}
}
QGraphicsScene::keyPressEvent(e);
}
@@ -143,16 +146,18 @@ void Diagram::keyPressEvent(QKeyEvent *e) {
@param e QKeyEvent decrivant l'evenement clavier
*/
void Diagram::keyReleaseEvent(QKeyEvent *e) {
// detecte le relachement d'une touche de direction ( = deplacement d'elements)
if (
(e -> key() == Qt::Key_Left || e -> key() == Qt::Key_Right ||\
e -> key() == Qt::Key_Up || e -> key() == Qt::Key_Down) &&\
!current_movement.isNull() && !e -> isAutoRepeat()
) {
// cree un objet d'annulation pour le mouvement qui vient de se finir
undoStack().push(new MoveElementsCommand(this, selectedContent(), current_movement));
invalidateMovedElements();
current_movement = QPointF();
if (!isReadOnly()) {
// detecte le relachement d'une touche de direction ( = deplacement d'elements)
if (
(e -> key() == Qt::Key_Left || e -> key() == Qt::Key_Right ||\
e -> key() == Qt::Key_Up || e -> key() == Qt::Key_Down) &&\
!current_movement.isNull() && !e -> isAutoRepeat()
) {
// cree un objet d'annulation pour le mouvement qui vient de se finir
undoStack().push(new MoveElementsCommand(this, selectedContent(), current_movement));
invalidateMovedElements();
current_movement = QPointF();
}
}
QGraphicsScene::keyReleaseEvent(e);
}
@@ -227,6 +232,14 @@ QSize Diagram::imageSize() const {
return(QSizeF(image_width, image_height).toSize());
}
/**
@return true si le schema est considere comme vide, false sinon.
Un schema vide ne contient ni element, ni conducteur, ni champ de texte
*/
bool Diagram::isEmpty() const {
return(!items().count());
}
/**
Exporte tout ou partie du schema
@param diagram Booleen (a vrai par defaut) indiquant si le XML genere doit
@@ -258,7 +271,7 @@ QDomDocument Diagram::toXml(bool diagram) {
// type de conducteur par defaut
QDomElement default_conductor = document.createElement("defaultconductor");
defaultConductorProperties.toXml(document, default_conductor);
defaultConductorProperties.toXml(default_conductor);
racine.appendChild(default_conductor);
}
document.appendChild(racine);
@@ -324,20 +337,38 @@ QDomDocument Diagram::toXml(bool diagram) {
}
/**
Importe le diagram decrit dans un document XML. Si une position est
Importe le schema decrit dans un document XML. Si une position est
precisee, les elements importes sont positionnes de maniere a ce que le
coin superieur gauche du plus petit rectangle pouvant les entourant tous
(le bounding rect) soit a cette position.
@param document Le document XML a analyser
@param position La position du diagram importe
@param position La position du schema importe
@param consider_informations Si vrai, les informations complementaires
(auteur, titre, ...) seront prises en compte
@param content_ptr si ce pointeur vers un DiagramContentn'est pas NULL, il
@param content_ptr si ce pointeur vers un DiagramContent n'est pas NULL, il
sera rempli avec le contenu ajoute au schema par le fromXml
@return true si l'import a reussi, false sinon
*/
bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_informations, DiagramContent *content_ptr) {
QDomElement root = document.documentElement();
return(fromXml(root, position, consider_informations, content_ptr));
}
/**
Importe le schema decrit dans un element XML. Si une position est
precisee, les elements importes sont positionnes de maniere a ce que le
coin superieur gauche du plus petit rectangle pouvant les entourant tous
(le bounding rect) soit a cette position.
@param document Le document XML a analyser
@param position La position du schema importe
@param consider_informations Si vrai, les informations complementaires
(auteur, titre, ...) seront prises en compte
@param content_ptr si ce pointeur vers un DiagramContent n'est pas NULL, il
sera rempli avec le contenu ajoute au schema par le fromXml
@return true si l'import a reussi, false sinon
*/
bool Diagram::fromXml(QDomElement &document, QPointF position, bool consider_informations, DiagramContent *content_ptr) {
QDomElement root = document;
// le premier element doit etre un schema
if (root.tagName() != "diagram") return(false);
@@ -390,7 +421,10 @@ bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_in
}
// si la racine n'a pas d'enfant : le chargement est fini (schema vide)
if (root.firstChild().isNull()) return(true);
if (root.firstChild().isNull()) {
write(document);
return(true);
}
// chargement de tous les elements du fichier XML
QList<Element *> added_elements;
@@ -400,13 +434,17 @@ bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_in
// cree un element dont le type correspond a l'id type
QString type_id = e.attribute("type");
QString chemin_fichier = QETApp::realPath(type_id);
CustomElement *nvel_elmt = new CustomElement(chemin_fichier);
ElementsLocation element_location = ElementsLocation(type_id);
if (type_id.startsWith("embed://")) element_location.setProject(project_);
CustomElement *nvel_elmt = new CustomElement(element_location);
if (nvel_elmt -> isNull()) {
QString debug_message = QString("Le chargement de la description de l'element %1 a echoue avec le code d'erreur %2").arg(chemin_fichier).arg(nvel_elmt -> etat());
QString debug_message = QString("Le chargement de la description de l'element %1 a echoue avec le code d'erreur %2").arg(element_location.path()).arg(nvel_elmt -> state());
qDebug() << debug_message;
delete nvel_elmt;
qDebug(debug_message.toLatin1().data());
continue;
qDebug() << "Utilisation d'un GhostElement en lieu et place de cet element.";
nvel_elmt = new GhostElement(element_location);
}
// charge les caracteristiques de l'element
@@ -484,7 +522,7 @@ bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_in
added_conductors << c;
}
}
} else qDebug() << "Le chargement du conductor" << id_p1 << id_p2 << "a echoue";
} else qDebug() << "Le chargement du conducteur" << id_p1 << id_p2 << "a echoue";
}
// remplissage des listes facultatives
@@ -494,9 +532,52 @@ bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_in
content_ptr -> textFields = added_texts;
}
write(document);
return(true);
}
/**
Enregistre le schema XML dans son document XML interne et emet le signal
written().
*/
void Diagram::write() {
qDebug() << qPrintable(QString("Diagram::write() : saving changes from diagram \"%1\" [%2]").arg(title()).arg(QET::pointerString(this)));
write(toXml().documentElement());
undoStack().setClean();
}
/**
Enregistre un element XML dans son document XML interne et emet le signal
written().
@param element xml a enregistrer
*/
void Diagram::write(const QDomElement &element) {
xml_document.clear();
xml_document.appendChild(xml_document.importNode(element, true));
emit(written());
}
/**
@return true si la fonction write a deja ete appele (pour etre plus exact :
si le document XML utilise en interne n'est pas vide), false sinon
*/
bool Diagram::wasWritten() const {
return(!xml_document.isNull());
}
/**
@return le schema en XML tel qu'il doit etre enregistre dans le fichier projet
@param xml_doc document XML a utiliser pour creer l'element
*/
QDomElement Diagram::writeXml(QDomDocument &xml_doc) const {
// si le schema n'a pas ete enregistre explicitement, on n'ecrit rien
if (!wasWritten()) return(QDomElement());
QDomElement diagram_elmt = xml_document.documentElement();
QDomNode new_node = xml_doc.importNode(diagram_elmt, true);
return(new_node.toElement());
}
/**
Gere le fait qu'un texte du schema ait ete modifie
@param text_item Texte modifie
@@ -536,6 +617,26 @@ QRectF Diagram::border() const {
);
}
/**
@return le titre du cartouche
*/
QString Diagram::title() const {
return(border_and_inset.title());
}
/**
@return la liste des elements de ce schema
*/
QList<CustomElement *> Diagram::customElements() const {
QList<CustomElement *> elements_list;
foreach(QGraphicsItem *qgi, items()) {
if (CustomElement *elmt = qgraphicsitem_cast<CustomElement *>(qgi)) {
elements_list << elmt;
}
}
return(elements_list);
}
/// oublie la liste des elements et conducteurs en mouvement
void Diagram::invalidateMovedElements() {
if (!moved_elements_fetched) return;
@@ -617,6 +718,20 @@ void Diagram::moveElements(const QPointF &diff, QGraphicsItem *dontmove) {
}
}
/**
Permet de savoir si un element est utilise sur un schema
@param location Emplacement d'un element
@return true si l'element location est utilise sur ce schema, false sinon
*/
bool Diagram::usesElement(const ElementsLocation &location) {
foreach(CustomElement *element, customElements()) {
if (element -> location() == location) {
return(true);
}
}
return(false);
}
/**
Definit s'il faut afficher ou non les bornes
@param dt true pour afficher les bornes, false sinon
@@ -649,6 +764,38 @@ bool Diagram::clipboardMayContainDiagram() {
return(may_be_diagram);
}
/**
@return le projet auquel ce schema appartient ou 0 s'il s'agit d'un schema
independant.
*/
QETProject *Diagram::project() const {
return(project_);
}
/**
@param project le nouveau projet auquel ce schema appartient ou 0 s'il
s'agit d'un schema independant. Indiquer 0 pour rendre ce schema independant.
*/
void Diagram::setProject(QETProject *project) {
project_ = project;
}
/**
@return true si le schema est en lecture seule
*/
bool Diagram::isReadOnly() const {
return(read_only_);
}
/**
@param read_only true pour passer le schema en lecture seule, false sinon
*/
void Diagram::setReadOnly(bool read_only) {
if (read_only_ != read_only) {
read_only_ = read_only;
emit(readOnlyChanged(read_only_));
}
}
/**
@return Le contenu du schema. Les conducteurs sont tous places dans
conductorsToMove.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -19,15 +19,17 @@
#define SCHEMA_H
#include <QtGui>
#include <QtXml>
#include "qetdiagrameditor.h"
#include "borderinset.h"
#include "qgimanager.h"
#include "conductorproperties.h"
class Element;
class CustomElement;
class Terminal;
class Conductor;
class DiagramTextItem;
class DiagramContent;
class QETProject;
class ElementsLocation;
/**
Cette classe represente un schema electrique.
Elle gere les differents elements et conducteurs qui le composent
@@ -78,6 +80,9 @@ class Diagram : public QGraphicsScene {
QGIManager *qgi_manager;
QUndoStack *undo_stack;
bool draw_terminals;
QDomDocument xml_document;
QETProject *project_;
bool read_only_;
// methodes
protected:
@@ -88,6 +93,14 @@ class Diagram : public QGraphicsScene {
public:
static bool clipboardMayContainDiagram();
// fonctions relatives au projet parent
QETProject *project() const;
void setProject(QETProject *);
// fonctions relatives a la lecture seule
bool isReadOnly() const;
void setReadOnly(bool);
// fonctions relatives a la pose de conducteurs
void setConductor(bool);
void setConductorStart (QPointF);
@@ -96,6 +109,11 @@ class Diagram : public QGraphicsScene {
// fonctions relatives a l'import / export XML
QDomDocument toXml(bool = true);
bool fromXml(QDomDocument &, QPointF = QPointF(), bool = true, DiagramContent * = NULL);
bool fromXml(QDomElement &, QPointF = QPointF(), bool = true, DiagramContent * = NULL);
void write();
void write(const QDomElement &);
bool wasWritten() const;
QDomElement writeXml(QDomDocument &) const;
// fonctions relatives aux options graphiques
void setDisplayGrid(bool);
@@ -109,9 +127,13 @@ class Diagram : public QGraphicsScene {
void setDrawTerminals(bool);
QRectF border() const;
QString title() const;
bool toPaintDevice(QPaintDevice &, int = -1, int = -1, Qt::AspectRatioMode = Qt::KeepAspectRatio);
QSize imageSize() const;
bool isEmpty() const;
QList<CustomElement *> customElements() const;
void invalidateMovedElements();
void fetchMovedElements();
const QSet<Element *> &elementsToMove();
@@ -122,6 +144,7 @@ class Diagram : public QGraphicsScene {
DiagramContent content() const;
DiagramContent selectedContent();
void moveElements(const QPointF &, QGraphicsItem * = NULL);
bool usesElement(const ElementsLocation &);
QUndoStack &undoStack();
QGIManager &qgiManager();
@@ -139,6 +162,8 @@ class Diagram : public QGraphicsScene {
vice-versa.
*/
void selectionEmptinessChanged();
void written();
void readOnlyChanged(bool);
};
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -33,7 +33,7 @@ AddElementCommand::AddElementCommand(
const QPointF &p,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("ajouter 1 ") + elmt -> nom(), parent),
QUndoCommand(QString(QObject::tr("ajouter 1 %1", "undo caption - %1 is an element name")).arg(elmt -> name()), parent),
element(elmt),
diagram(d),
position(p)
@@ -66,7 +66,7 @@ void AddElementCommand::redo() {
@param parent QUndoCommand parent
*/
AddTextCommand::AddTextCommand(Diagram *dia, DiagramTextItem *text, const QPointF &pos, QUndoCommand *parent) :
QUndoCommand(QObject::tr("Ajouter un champ de texte"), parent),
QUndoCommand(QObject::tr("Ajouter un champ de texte", "undo caption"), parent),
textitem(text),
diagram(dia),
position(pos)
@@ -113,7 +113,7 @@ AddConductorCommand::AddConductorCommand(
Conductor *c,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("ajouter un conducteur"), parent),
QUndoCommand(QObject::tr("ajouter un conducteur", "undo caption"), parent),
conductor(c),
diagram(d)
{
@@ -153,7 +153,14 @@ DeleteElementsCommand::DeleteElementsCommand(
removed_content(content),
diagram(dia)
{
setText(QObject::tr("supprimer ") + removed_content.sentence(DiagramContent::All));
setText(
QString(
QObject::tr(
"supprimer %1",
"undo caption - %1 is a sentence listing the removed content"
)
).arg(removed_content.sentence(DiagramContent::All))
);
diagram -> qgiManager().manage(removed_content.items(DiagramContent::All));
}
@@ -220,7 +227,14 @@ PasteDiagramCommand::PasteDiagramCommand(
first_redo(true)
{
setText(QObject::tr("coller ") + content.sentence(filter));
setText(
QString(
QObject::tr(
"coller %1",
"undo caption - %1 is a sentence listing the content to paste"
).arg(content.sentence(filter))
)
);
diagram -> qgiManager().manage(content.items(filter));
}
@@ -280,7 +294,14 @@ CutDiagramCommand::CutDiagramCommand(
) :
DeleteElementsCommand(dia, content, parent)
{
setText(QObject::tr("couper ") + content.sentence(DiagramContent::All));
setText(
QString(
QObject::tr(
"couper %1",
"undo caption - %1 is a sentence listing the content to cut"
).arg(content.sentence(DiagramContent::All))
)
);
}
/// Destructeur
@@ -306,7 +327,21 @@ MoveElementsCommand::MoveElementsCommand(
movement(m),
first_redo(true)
{
setText(QObject::tr("d\351placer ") + content_to_move.sentence(DiagramContent::Elements|DiagramContent::TextFields|DiagramContent::ConductorsToUpdate|DiagramContent::ConductorsToMove));
QString moved_content_sentence = content_to_move.sentence(
DiagramContent::Elements |
DiagramContent::TextFields |
DiagramContent::ConductorsToUpdate |
DiagramContent::ConductorsToMove
);
setText(
QString(
QObject::tr(
"d\351placer %1",
"undo caption - %1 is a sentence listing the moved content"
).arg(moved_content_sentence)
)
);
}
/// Destructeur
@@ -367,7 +402,7 @@ ChangeDiagramTextCommand::ChangeDiagramTextCommand(
const QString &after,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modifier le texte"), parent),
QUndoCommand(QObject::tr("modifier le texte", "undo caption"), parent),
text_item(dti),
text_before(before),
text_after(after),
@@ -400,9 +435,17 @@ void ChangeDiagramTextCommand::redo() {
@param parent QUndoCommand parent
*/
RotateElementsCommand::RotateElementsCommand(const QHash<Element *, QET::Orientation> &elements, QUndoCommand *parent) :
QUndoCommand(QObject::tr("pivoter ") + QET::ElementsAndConductorsSentence(elements.count(), 0), parent),
QUndoCommand(parent),
elements_to_rotate(elements)
{
setText(
QString(
QObject::tr(
"pivoter %1",
"undo caption - %1 is a sentence listing the rotated content"
)
).arg(QET::ElementsAndConductorsSentence(elements.count(), 0))
);
}
/// Destructeur
@@ -439,7 +482,7 @@ ChangeConductorCommand::ChangeConductorCommand(
Qt::Corner path_t,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modifier un conducteur"), parent),
QUndoCommand(QObject::tr("modifier un conducteur", "undo caption"), parent),
conductor(c),
old_profile(old_p),
new_profile(new_p),
@@ -472,9 +515,15 @@ ResetConductorCommand::ResetConductorCommand(
const QHash<Conductor *, ConductorProfilesGroup> &cp,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("R\351initialiser ") + QET::ElementsAndConductorsSentence(0, cp.count()), parent),
QUndoCommand(parent),
conductors_profiles(cp)
{
setText(
QObject::tr(
"R\351initialiser %1",
"undo caption - %1 is a sentence listing the reset content"
).arg(QET::ElementsAndConductorsSentence(0, cp.count()))
);
}
/// Destructeur
@@ -508,7 +557,7 @@ ChangeInsetCommand::ChangeInsetCommand(
const InsetProperties &new_ip,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modifier le cartouche"), parent),
QUndoCommand(QObject::tr("modifier le cartouche", "undo caption"), parent),
diagram(d),
old_inset(old_ip),
new_inset(new_ip)
@@ -537,7 +586,7 @@ void ChangeInsetCommand::redo() {
@param parent QUndoCommand parent
*/
ChangeBorderCommand::ChangeBorderCommand(Diagram *dia, const BorderProperties &old_bp, const BorderProperties &new_bp, QUndoCommand *parent) :
QUndoCommand(QObject::tr("modifier les dimensions du sch\351ma"), parent),
QUndoCommand(QObject::tr("modifier les dimensions du sch\351ma", "undo caption"), parent),
diagram(dia),
old_properties(old_bp),
new_properties(new_bp)
@@ -564,7 +613,7 @@ void ChangeBorderCommand::redo() {
@param parent QUndoCommand parent
*/
ChangeConductorPropertiesCommand::ChangeConductorPropertiesCommand(Conductor *c, QUndoCommand *parent) :
QUndoCommand(QObject::tr("modifier les propri\351t\351s d'un conducteur"), parent),
QUndoCommand(QObject::tr("modifier les propri\351t\351s d'un conducteur", "undo caption"), parent),
conductor(c),
old_settings_set(false),
new_settings_set(false)

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -16,7 +16,9 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "diagramprintdialog.h"
#include "qetprintpreviewdialog.h"
#include <math.h>
#include "diagramschooser.h"
/**
Constructeur
@@ -24,52 +26,52 @@
@param printer Imprimante a utiliser
@param parent Widget parent du dialogue
*/
DiagramPrintDialog::DiagramPrintDialog(Diagram *dia, QWidget *parent) :
DiagramPrintDialog::DiagramPrintDialog(QETProject *project, QWidget *parent) :
QWidget(parent),
diagram(dia),
dialog(0)
project_(project),
dialog_(0)
{
// initialise l'imprimante
printer = new QPrinter();
printer_ = new QPrinter();
// orientation paysage par defaut
printer -> setOrientation(QPrinter::Landscape);
printer_ -> setOrientation(QPrinter::Landscape);
}
/**
Destructeur
*/
DiagramPrintDialog::~DiagramPrintDialog() {
delete dialog;
delete printer;
delete dialog_;
delete printer_;
}
/**
Definit le nom du PDF si l'utilisateur choisit une sortie vers un PDF
*/
void DiagramPrintDialog::setPDFName(const QString &name) {
pdf_name = name;
void DiagramPrintDialog::setFileName(const QString &name) {
file_name_ = name;
}
/**
@return le nom du PDF
*/
QString DiagramPrintDialog::PDFName() const {
return(pdf_name);
QString DiagramPrintDialog::fileName() const {
return(file_name_);
}
/**
Definit le nom du document
*/
void DiagramPrintDialog::setDocName(const QString &name) {
doc_name = name;
doc_name_ = name;
}
/**
@return le nom du document
*/
QString DiagramPrintDialog::docName() const {
return(doc_name);
return(doc_name_);
}
/**
@@ -77,31 +79,38 @@ QString DiagramPrintDialog::docName() const {
*/
void DiagramPrintDialog::exec() {
#ifndef Q_OS_WIN32
if (!pdf_name.isEmpty()) printer -> setOutputFileName(pdf_name);
if (!doc_name.isEmpty()) printer -> setDocName(doc_name);
#endif
// prise en compte du nom du document
if (!doc_name_.isEmpty()) printer_ -> setDocName(doc_name_);
// affichage du dialogue d'impression standard
QPrintDialog print_dialog(printer, parentWidget());
print_dialog.setWindowTitle(tr("Options d'impression"));
print_dialog.setEnabledOptions(QAbstractPrintDialog::PrintToFile | QAbstractPrintDialog::PrintShowPageSize);
// affichage d'un premier dialogue demandant a l'utilisateur le type
// d'impression qu'il souhaite effectuer
buildPrintTypeDialog();
if (dialog_ -> exec() == QDialog::Rejected) return;
if (print_dialog.exec() == QDialog::Rejected) return;
// parametrage de l'imprimante en fonction du type d'impression choisi
if (printer_choice_ -> isChecked()) {
// affichage du dialogue d'impression standard pour parametrer l'imprimante
QPrintDialog print_dialog(printer_, parentWidget());
print_dialog.setWindowTitle(tr("Options d'impression", "window title"));
print_dialog.setEnabledOptions(QAbstractPrintDialog::PrintShowPageSize);
if (print_dialog.exec() == QDialog::Rejected) return;
} else if (pdf_choice_ -> isChecked()) {
printer_ -> setOutputFormat(QPrinter::PdfFormat);
printer_ -> setOutputFileName(filepath_field_ -> text());
} else {
printer_ -> setOutputFormat(QPrinter::PostScriptFormat);
printer_ -> setOutputFileName(filepath_field_ -> text());
}
/*
Apres l'execution de ce premier dialogue, on connait le format papier a
utiliser, son orientation et on est sur que tout cela est supporte par
l'imprimante.
On peut donc en deduire le nombre de pages a imprimer
*/
// affichage d'un second dialogue, non standard, pour connaitre les pages a imprimer
buildDialog();
if (dialog -> exec() == QDialog::Rejected) return;
// Apercu avant impression
QETPrintPreviewDialog preview_dialog(project_, printer_, parentWidget());
connect(&preview_dialog, SIGNAL(paintRequested(const QList<Diagram *> &, bool, QPrinter *)), this, SLOT(print(const QList<Diagram *> &, bool, QPrinter *)));
DiagramsChooser *dc = preview_dialog.diagramsChooser();
dc -> setSelectedAllDiagrams();
if (preview_dialog.exec() == QDialog::Rejected) return;
// effectue l'impression en elle-meme
print();
print(dc -> selectedDiagrams(), preview_dialog.fitDiagramsToPages(), printer_);
}
/**
@@ -109,8 +118,8 @@ void DiagramPrintDialog::exec() {
@return Le nombre de pages necessaires pour imprimer le schema
avec l'orientation et le format papier utilise dans l'imprimante en cours.
*/
int DiagramPrintDialog::pagesCount(bool fullpage) const {
return(horizontalPagesCount(fullpage) * verticalPagesCount(fullpage));
int DiagramPrintDialog::pagesCount(Diagram *diagram, bool fullpage) const {
return(horizontalPagesCount(diagram, fullpage) * verticalPagesCount(diagram, fullpage));
}
/**
@@ -118,9 +127,9 @@ int DiagramPrintDialog::pagesCount(bool fullpage) const {
@return La largeur du "poster" en nombre de pages pour imprimer le schema
avec l'orientation et le format papier utilise dans l'imprimante en cours.
*/
int DiagramPrintDialog::horizontalPagesCount(bool fullpage) const {
int DiagramPrintDialog::horizontalPagesCount(Diagram *diagram, bool fullpage) const {
// note : pageRect et Paper Rect tiennent compte de l'orientation du papier
QRect printable_area = fullpage ? printer -> paperRect() : printer -> pageRect();
QRect printable_area = fullpage ? printer_ -> paperRect() : printer_ -> pageRect();
QRect diagram_rect = diagram -> border().toRect();
int h_pages_count = int(ceil(qreal(diagram_rect.width()) / qreal(printable_area.width())));
@@ -132,9 +141,9 @@ int DiagramPrintDialog::horizontalPagesCount(bool fullpage) const {
@return La largeur du "poster" en nombre de pages pour imprimer le schema
avec l'orientation et le format papier utilise dans l'imprimante en cours.
*/
int DiagramPrintDialog::verticalPagesCount(bool fullpage) const {
int DiagramPrintDialog::verticalPagesCount(Diagram *diagram, bool fullpage) const {
// note : pageRect et Paper Rect tiennent compte de l'orientation du papier
QRect printable_area = fullpage ? printer -> paperRect() : printer -> pageRect();
QRect printable_area = fullpage ? printer_ -> paperRect() : printer_ -> pageRect();
QRect diagram_rect = diagram -> border().toRect();
int v_pages_count = int(ceil(qreal(diagram_rect.height()) / qreal(printable_area.height())));
@@ -142,128 +151,184 @@ int DiagramPrintDialog::verticalPagesCount(bool fullpage) const {
}
/**
Construit un dialogue non standard pour demander les pages a imprimer a l'utilisateur
Construit un dialogue non standard pour demander a l'utilisateur quelle type
d'impression il souhaite effectuer : PDF, PS ou imprimante physique
*/
void DiagramPrintDialog::buildDialog() {
dialog = new QDialog(parentWidget());
dialog -> setMinimumWidth(460);
dialog -> setWindowTitle(tr("Options d'impression"));
options_label = new QLabel();
use_full_page = new QCheckBox(tr("Utiliser toute la feuille"));
use_full_page_label_ = new QLabel(tr(
"Si cette option est coch\351e, les marges de la feuille seront "
"ignor\351es et toute sa surface sera utilis\351e pour l'impression. "
"Cela peut ne pas \352tre support\351 par votre imprimante."
));
use_full_page_label_ -> setWordWrap(true);
use_full_page_label_ -> setContentsMargins(20, 0, 0, 0);
fit_diagram_to_page = new QCheckBox(tr("Adapter le sch\351ma \340 la page"));
fit_diagram_to_page_label_ = new QLabel(tr(
"Si cette option est coch\351e, le sch\351ma sera agrandi ou "
"r\351tr\351ci de fa\347on \340 remplir toute la surface imprimable "
"d'une et une seule page."
));
fit_diagram_to_page_label_ -> setWordWrap(true);
fit_diagram_to_page_label_ -> setContentsMargins(20, 0, 0, 0);
fit_diagram_to_page -> setChecked(true);
range_from_label = new QLabel(tr("Pages \340 imprimer : plage de "));
start_page = new QSpinBox();
to_label = new QLabel(tr(" \340 "));
end_page = new QSpinBox();
buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
void DiagramPrintDialog::buildPrintTypeDialog() {
// initialisation des widgets
dialog_ = new QDialog(parentWidget());
printtype_label_ = new QLabel(tr("Quel type d'impression d\351sirez-vous effectuer ?"));
printer_icon_ = new QLabel();
pdf_icon_ = new QLabel();
ps_icon_ = new QLabel();
printtype_choice_ = new QButtonGroup();
printer_choice_ = new QRadioButton("Impression sur une imprimante physique");
pdf_choice_ = new QRadioButton("Impression vers un fichier au format PDF");
ps_choice_ = new QRadioButton("Impression vers un fichier au format PostScript (PS)");
filepath_field_ = new QLineEdit();
browse_button_ = new QPushButton("...");
buttons_ = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
QHBoxLayout *pages_layout = new QHBoxLayout();
pages_layout -> addWidget(range_from_label);
pages_layout -> addWidget(start_page);
pages_layout -> addWidget(to_label);
pages_layout -> addWidget(end_page);
pages_layout -> addStretch();
dialog_ -> setWindowTitle(tr("Choix du type d'impression"));
printer_icon_ -> setPixmap(QPixmap(":/ico/printtype_printer.png"));
pdf_icon_ -> setPixmap(QPixmap(":/ico/printtype_pdf.png"));
ps_icon_ -> setPixmap(QPixmap(":/ico/printtype_ps.png"));
printtype_choice_ -> addButton(printer_choice_);
printtype_choice_ -> addButton(pdf_choice_);
printtype_choice_ -> addButton(ps_choice_);
printer_choice_ -> setChecked(true);
if (!file_name_.isEmpty()) filepath_field_ -> setText(file_name_ + ".pdf");
QVBoxLayout *dialog_layout = new QVBoxLayout(dialog);
dialog_layout -> addWidget(options_label);
dialog_layout -> addWidget(use_full_page);
dialog_layout -> addWidget(use_full_page_label_);
dialog_layout -> addWidget(fit_diagram_to_page);
dialog_layout -> addWidget(fit_diagram_to_page_label_);
dialog_layout -> addLayout(pages_layout);
dialog_layout -> addStretch();
dialog_layout -> addWidget(buttons);
// connexions signaux / slots
connect(printer_choice_, SIGNAL(toggled(bool)), this, SLOT(updatePrintTypeDialog()));
connect(pdf_choice_, SIGNAL(toggled(bool)), this, SLOT(updatePrintTypeDialog()));
connect(ps_choice_, SIGNAL(toggled(bool)), this, SLOT(updatePrintTypeDialog()));
connect(browse_button_, SIGNAL(clicked(bool)), this, SLOT(browseFilePrintTypeDialog()));
connect(buttons_, SIGNAL(accepted()), this, SLOT(acceptPrintTypeDialog()));
connect(buttons_, SIGNAL(rejected()), dialog_, SLOT(reject()));
connect(use_full_page, SIGNAL(stateChanged(int)), this, SLOT(updateDialog()));
connect(fit_diagram_to_page, SIGNAL(stateChanged(int)), this, SLOT(updateDialog()));
connect(start_page, SIGNAL(valueChanged(int)), this, SLOT(checkStartPage()));
connect(end_page, SIGNAL(valueChanged(int)), this, SLOT(checkEndPage()));
connect(buttons, SIGNAL(accepted()), dialog, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), dialog, SLOT(reject()));
// organisation graphique
glayout0_ = new QGridLayout();
hlayout0_ = new QHBoxLayout();
vlayout0_ = new QVBoxLayout();
updateDialog();
hlayout0_ -> addWidget(filepath_field_);
hlayout0_ -> addWidget(browse_button_);
glayout0_ -> addWidget(printer_icon_, 0, 0);
glayout0_ -> addWidget(printer_choice_, 0, 1);
glayout0_ -> addWidget(pdf_icon_, 1, 0);
glayout0_ -> addWidget(pdf_choice_, 1, 1);
glayout0_ -> addWidget(ps_icon_, 2, 0);
glayout0_ -> addWidget(ps_choice_, 2, 1);
glayout0_ -> addLayout(hlayout0_, 3, 1);
vlayout0_ -> addWidget(printtype_label_);
vlayout0_ -> addLayout(glayout0_);
vlayout0_ -> addWidget(buttons_);
dialog_ -> setLayout(vlayout0_);
updatePrintTypeDialog();
}
/**
Assure la coherence du dialogue
Assure la coherence du dialogue permettant le choix du type d'impression
*/
void DiagramPrintDialog::updateDialog() {
int pages_count;
// si on adapte le schema a la page, alors il n'y a qu'une page a imprimer
if (fit_diagram_to_page -> isChecked()) {
pages_count = 1;
void DiagramPrintDialog::updatePrintTypeDialog() {
// imprime-t-on vers un fichier ?
bool file_print = !(printer_choice_ -> isChecked());
// on n'active le champ fichier que pour les impressions vers un fichier
filepath_field_ -> setEnabled(file_print);
browse_button_ -> setEnabled(file_print);
// on corrige eventuellement l'extension du fichier deja selectionne
if (file_print) {
QString filepath = filepath_field_ -> text();
if (!filepath.isEmpty()) {
if (pdf_choice_ -> isChecked() && filepath.endsWith(".ps")) {
QRegExp re("\\.ps$", Qt::CaseInsensitive);
filepath.replace(re, ".pdf");
filepath_field_ -> setText(filepath);
} else if (ps_choice_ -> isChecked() && filepath.endsWith(".pdf")) {
QRegExp re("\\.pdf$", Qt::CaseInsensitive);
filepath.replace(re, ".ps");
filepath_field_ -> setText(filepath);
}
}
}
}
/**
Verifie l'etat du dialogue permettant le choix du type d'impression lorsque
l'utilisateur le valide.
*/
void DiagramPrintDialog::acceptPrintTypeDialog() {
bool file_print = !(printer_choice_ -> isChecked());
if (file_print) {
// un fichier doit avoir ete entre
if (filepath_field_ -> text().isEmpty()) {
QMessageBox::information(
parentWidget(),
tr("Fichier manquant", "message box title"),
tr("Vous devez indiquer le chemin du fichier PDF/PS \340 cr\351er.", "message box content")
);
} else dialog_ -> accept();
} else {
pages_count = pagesCount(use_full_page -> isChecked());
}
options_label -> setText(tr("Nombre total de pages : ") + QString("%1").arg(pages_count));
setPagesRangeVisible(pages_count > 1);
start_page -> setRange(1, pages_count);
end_page -> setRange(1, pages_count);
end_page -> setValue(pages_count);
}
/**
S'assure que la premiere page ne soit pas superieure a la derniere page
*/
void DiagramPrintDialog::checkStartPage() {
if (start_page -> value() > end_page -> value()) {
start_page -> blockSignals(true);
start_page -> setValue(end_page -> value());
start_page -> blockSignals(false);
// une imprimante doit avoir ete selectionnee
/// @todo
dialog_ -> accept();
}
}
/**
S'assure que la derniere page ne soit pas inferieure a la premiere page
Permet a l'utilisateur de choisir un fichier
*/
void DiagramPrintDialog::checkEndPage() {
if (end_page -> value() < start_page -> value()) {
end_page -> blockSignals(true);
end_page -> setValue(start_page -> value());
end_page -> blockSignals(false);
void DiagramPrintDialog::browseFilePrintTypeDialog() {
QString extension;
QString filter;
if (printer_choice_ -> isChecked()) return;
else if (pdf_choice_ -> isChecked()) {
extension = ".pdf";
filter = tr("Fichiers PDF (*.pdf)", "file filter");
}
else if (ps_choice_ -> isChecked()) {
extension = ".ps";
filter = tr("Fichiers PostScript (*.ps)", "file filter");
}
QString filepath = QFileDialog::getSaveFileName(
parentWidget(),
QString(),
filepath_field_ -> text(),
filter
);
if (!filepath.isEmpty()) {
if (!filepath.endsWith(extension)) filepath += extension;
filepath_field_ -> setText(filepath);
}
}
/**
@param visible true pour afficher les pages, false sinon
*/
void DiagramPrintDialog::setPagesRangeVisible(bool visible) {
range_from_label -> setVisible(visible);
start_page -> setVisible(visible);
to_label -> setVisible(visible);
end_page -> setVisible(visible);
}
/**
Effectue l'impression elle-meme
@param diagrams Schemas a imprimer
@param fit_page Booleen indiquant s'il faut adapter les schemas aux pages
ou non
@param printer L'imprimante a utiliser
*/
void DiagramPrintDialog::print() {
// recupere les informations collectees dans le second dialogue
bool full_page = use_full_page -> isChecked();
bool fit_page = fit_diagram_to_page -> isChecked();
int first_page = start_page -> value();
int last_page = end_page -> value();
// parametre l'imprimante
printer -> setFullPage(full_page);
void DiagramPrintDialog::print(const QList<Diagram *> &diagrams, bool fit_page, QPrinter */*printer*/) {
//qDebug() << "Demande d'impression de " << diagrams.count() << "schemas.";
// QPainter utiliser pour effectuer le rendu
QPainter qp(printer);
QPainter qp(printer_);
// cas special : il n'y a aucun schema a imprimer
if (!diagrams.count()) {
qp.end();
return;
}
// imprime les schemas
for (int i = 0 ; i < diagrams.count() ; ++ i) {
printDiagram(diagrams[i], fit_page, &qp, printer_);
if (i != diagrams.count() - 1) {
printer_ -> newPage();
}
}
}
/**
Imprime un schema
@param diagram Schema a imprimer
@param fit_page True pour adapter les schemas aux pages, false sinon
@param qp QPainter a utiliser (deja initialise sur printer)
@param printer Imprimante a utiliser
*/
void DiagramPrintDialog::printDiagram(Diagram *diagram, bool fit_page, QPainter *qp, QPrinter *printer) {
//qDebug() << printer -> paperSize() << printer -> paperRect() << diagram -> title();
// l'imprimante utilise-t-elle toute la feuille ?
bool full_page = printer -> fullPage ();
// impression physique (!= fichier PDF)
if (printer -> outputFileName().isEmpty()) {
@@ -275,15 +340,19 @@ void DiagramPrintDialog::print() {
if (fit_page) {
// impression adaptee sur une seule page
diagram -> render(&qp, QRectF(), diagram -> border(), Qt::KeepAspectRatio);
diagram -> render(qp, QRectF(), diagram -> border(), Qt::KeepAspectRatio);
} else {
// impression sur une ou plusieurs pages
QRect diagram_rect = diagram -> border().toRect();
QRect diagram_rect = diagram -> border().adjusted(0.0, 0.0, 1.0, 1.0).toAlignedRect();
QRect printed_area = full_page ? printer -> paperRect() : printer -> pageRect();
//qDebug() << "impression sur une ou plusieurs pages";
//qDebug() << " schema :" << diagram_rect;
//qDebug() << " page :" << printed_area;
int used_width = printed_area.width();
int used_height = printed_area.height();
int h_pages_count = horizontalPagesCount(full_page);
int v_pages_count = verticalPagesCount(full_page);
int h_pages_count = horizontalPagesCount(diagram, full_page);
int v_pages_count = verticalPagesCount(diagram, full_page);
QVector< QVector< QRect > > pages_grid;
// le schema est imprime sur une matrice de feuilles
@@ -312,18 +381,20 @@ void DiagramPrintDialog::print() {
QVector<QRect> pages_to_print;
for (int i = 0 ; i < v_pages_count ; ++ i) {
for (int j = 0 ; j < h_pages_count ; ++ j) {
int page_number = (i * h_pages_count) + j + 1;
if (page_number >= first_page && page_number <= last_page) {
//int page_number = (i * h_pages_count) + j + 1;
//if (page_number >= first_page && page_number <= last_page) {
pages_to_print << pages_grid.at(i).at(j);
}
//}
}
}
//qDebug() << " " << pages_to_print.count() << " pages a imprimer :";
// parcourt les pages pour impression
for (int i = 0 ; i < pages_to_print.count() ; ++ i) {
QRect current_rect(pages_to_print.at(i));
//qDebug() << " " << current_rect;
diagram -> render(
&qp,
qp,
QRect(QPoint(0,0), current_rect.size()),
current_rect.translated(diagram_rect.topLeft()),
Qt::KeepAspectRatio

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -14,11 +14,11 @@
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DIAGRAM_PRINT_DIALOG_H
#define DIAGRAM_PRINT_DIALOG_H
#include <QtGui>
#include "qetproject.h"
#include "diagram.h"
/**
Cette classe represente le dialogue de configuration de l'impression d'un
@@ -29,48 +29,55 @@ class DiagramPrintDialog : public QWidget {
Q_OBJECT
// Constructeurs, destructeur
public:
DiagramPrintDialog(Diagram *, QWidget * = 0);
DiagramPrintDialog(QETProject *, QWidget * = 0);
virtual ~DiagramPrintDialog();
private:
DiagramPrintDialog(const DiagramPrintDialog &);
// methodes
public:
void setPDFName(const QString &);
QString PDFName() const;
void setFileName(const QString &);
QString fileName() const;
void setDocName(const QString &);
QString docName() const;
int pagesCount(bool = false) const;
int horizontalPagesCount(bool = false) const;
int verticalPagesCount(bool = false) const;
int pagesCount(Diagram *, bool = false) const;
int horizontalPagesCount(Diagram *, bool = false) const;
int verticalPagesCount(Diagram *, bool = false) const;
void exec();
private:
void buildPrintTypeDialog();
void buildDialog();
void print();
private slots:
void updateDialog();
void checkStartPage();
void checkEndPage();
void setPagesRangeVisible(bool);
void print(const QList<Diagram *> &, bool, QPrinter *);
void printDiagram(Diagram *, bool, QPainter *, QPrinter * = 0);
void updatePrintTypeDialog();
void acceptPrintTypeDialog();
void browseFilePrintTypeDialog();
// attributs
private:
Diagram *diagram;
QPrinter *printer;
QString doc_name;
QString pdf_name;
QDialog *dialog;
QLabel *options_label;
QLabel *range_from_label;
QLabel *to_label;
QCheckBox *use_full_page;
QLabel *use_full_page_label_;
QCheckBox *fit_diagram_to_page;
QLabel *fit_diagram_to_page_label_;
QSpinBox *start_page;
QSpinBox *end_page;
QDialogButtonBox *buttons;
QETProject *project_;
QPrinter *printer_;
QString doc_name_;
QString file_name_;
/// Attributs relatifs au 1er dialogue
QDialog *dialog_;
QLabel *printtype_label_;
QGridLayout *glayout0_;
QVBoxLayout *vlayout0_;
QHBoxLayout *hlayout0_;
QLabel *printer_icon_;
QLabel *pdf_icon_;
QLabel *ps_icon_;
QButtonGroup *printtype_choice_;
QRadioButton *printer_choice_;
QRadioButton *pdf_choice_;
QRadioButton *ps_choice_;
QLineEdit *filepath_field_;
QPushButton *browse_button_;
QDialogButtonBox *buttons_;
};
#endif

159
sources/diagramschooser.cpp Normal file
View File

@@ -0,0 +1,159 @@
#include "diagramschooser.h"
#include "qetproject.h"
#include "diagram.h"
/**
Constructeur
@param project Projet dont il faut afficher les schemas
@param parent QWidget parent de ce widget
*/
DiagramsChooser::DiagramsChooser(QETProject *project, QWidget *parent) :
QFrame(parent),
project_(project),
vlayout0_(0)
{
setFrameShadow(QFrame::Sunken);
setFrameShape(QFrame::StyledPanel);
setLineWidth(3);
setMidLineWidth(3);
updateList();
}
/**
Destructeur
*/
DiagramsChooser::~DiagramsChooser() {
}
/**
@return le projet dont ce widget affiche les schemas
*/
QETProject *DiagramsChooser::project() const {
return(project_);
}
/**
@return la liste des schemas selectionnes
*/
QList<Diagram *> DiagramsChooser::selectedDiagrams() const {
QList<Diagram *> selected_diagrams;
foreach(Diagram *diagram, project_ -> diagrams()) {
QCheckBox *check_box = diagrams_[diagram];
if (check_box && check_box -> isChecked()) {
selected_diagrams << diagram;
}
}
return(selected_diagrams);
}
/**
@return la liste des schemas qui ne sont pas selectionnes
*/
QList<Diagram *> DiagramsChooser::nonSelectedDiagrams() const {
QList<Diagram *> selected_diagrams;
foreach(Diagram *diagram, diagrams_.keys()) {
if (!(diagrams_[diagram] -> isChecked())) {
selected_diagrams << diagram;
}
}
return(selected_diagrams);
}
/**
@param diagram Un schema cense etre present dans ce widget
*/
bool DiagramsChooser::diagramIsSelected(Diagram *const diagram) const {
QCheckBox *checkbox = diagrams_.value(diagram);
if (!checkbox) return(false);
return(checkbox -> isChecked());
}
/**
Selectionne les schemas contenus dans la liste diagrams_list
@param diagrams_list Liste de schemas a selectionner
@param select true pour selectionne les schemas de la liste, false pour les
deselectionner
@param reset true pour deselectionner tous les schemas avant de
selectionner ceux de la liste
*/
void DiagramsChooser::setSelectedDiagrams(const QList<Diagram *> &diagrams_list, bool select, bool reset) {
// evite d'emettre une rafale de signaux pour cette operation
blockSignals(true);
// deselectionne tous les schemas si demande
if (reset) {
foreach(QCheckBox *check_box, diagrams_.values()) {
check_box -> setChecked(false);
}
}
int changes = 0;
QCheckBox *check_box;
foreach(Diagram *diagram, diagrams_list) {
if ((check_box = diagrams_[diagram])) {
if (check_box -> isChecked() != select) {
check_box -> setChecked(select);
++ changes;
}
}
}
blockSignals(false);
if (reset || changes) {
emit(selectionChanged());
}
}
/**
Selectionne ou deselectionne tous les schemas
@param select true pour selectionne les schemas de la liste, false pour les
deselectionner
*/
void DiagramsChooser::setSelectedAllDiagrams(bool select) {
blockSignals(true);
foreach(QCheckBox *check_box, diagrams_.values()) {
check_box -> setChecked(select);
}
blockSignals(false);
emit(selectionChanged());
}
/**
Met a jour la liste des schemas du projet
*/
void DiagramsChooser::updateList() {
if (!project_) return;
// retient la liste des schemas deja selectionnes
QList<Diagram *> selected_diagrams = selectedDiagrams();
// detruit les checkbox existantes
QList<QCheckBox *> checkboxes = diagrams_.values();
qDeleteAll(checkboxes.begin(), checkboxes.end());
buildLayout();
// recree les checkbox necessaires
foreach(Diagram *diagram, project_ -> diagrams()) {
// titre du schema
QString diagram_title = diagram -> title();
if (diagram_title.isEmpty()) diagram_title = tr("Sch\351ma sans titre");
QCheckBox *checkbox = new QCheckBox(diagram_title);
checkbox -> setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum));
checkbox -> setChecked(selected_diagrams.contains(diagram));
connect(checkbox, SIGNAL(toggled(bool)), this, SIGNAL(selectionChanged()));
diagrams_.insert(diagram, checkbox);
vlayout0_ -> addWidget(checkbox, 0, Qt::AlignLeft | Qt::AlignTop);
}
vlayout0_ -> addStretch();
}
/**
Met en place la disposition du widget
*/
void DiagramsChooser::buildLayout() {
if (vlayout0_) return;
vlayout0_ = new QVBoxLayout();
setLayout(vlayout0_);
}

61
sources/diagramschooser.h Normal file
View File

@@ -0,0 +1,61 @@
/*
Copyright 2006-2009 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 DIAGRAMS_CHOOSER_H
#define DIAGRAMS_CHOOSER_H
#include <QtGui>
class QETProject;
class Diagram;
/**
Cette classe represente un widget permettant de choisir 0 a n schemas parmi
ceux d'un projet.
*/
class DiagramsChooser : public QFrame {
Q_OBJECT
// constructeurs, destructeur
public:
DiagramsChooser(QETProject *, QWidget * = 0);
virtual ~DiagramsChooser();
private:
DiagramsChooser(const DiagramsChooser &);
// methodes
public:
QETProject *project() const;
QList<Diagram *> selectedDiagrams() const;
QList<Diagram *> nonSelectedDiagrams() const;
bool diagramIsSelected(Diagram * const) const;
void setSelectedDiagrams(const QList<Diagram *> &, bool = true, bool = true);
void setSelectedAllDiagrams(bool = true);
public slots:
void updateList();
signals:
void selectionChanged();
private:
void buildLayout();
// attributs
private:
QETProject *project_;
QVBoxLayout *vlayout0_;
QHash<Diagram *, QCheckBox *> diagrams_;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -28,7 +28,7 @@ DiagramTextItem::DiagramTextItem(QGraphicsItem *parent, QGraphicsScene *scene) :
QGraphicsTextItem(parent, scene)
{
setDefaultTextColor(Qt::black);
setFont(QFont(QETApp::diagramTextsFont(), 9));
setFont(QFont(QETApp::diagramTextsFont(), QETApp::diagramTextsSize()));
setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
}
@@ -44,7 +44,7 @@ DiagramTextItem::DiagramTextItem(const QString &text, QGraphicsItem *parent, QGr
previous_text(text)
{
setDefaultTextColor(Qt::black);
setFont(QFont(QETApp::diagramTextsFont(), 9));
setFont(QFont(QETApp::diagramTextsFont(), QETApp::diagramTextsSize()));
setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -18,48 +18,53 @@
#include "diagramview.h"
#include "diagram.h"
#include "customelement.h"
#include "exportdialog.h"
#include "diagramprintdialog.h"
#include "conductor.h"
#include "diagramcommands.h"
#include "conductorpropertieswidget.h"
#include "insetpropertieswidget.h"
#include "qetapp.h"
#include "qetproject.h"
#include "borderpropertieswidget.h"
#include "integrationmoveelementshandler.h"
#include "qetdiagrameditor.h"
/**
Constructeur
@param parent Le QWidget parent de cette vue de schema
*/
DiagramView::DiagramView(QWidget *parent) : QGraphicsView(parent), is_adding_text(false) {
DiagramView::DiagramView(Diagram *diagram, QWidget *parent) : QGraphicsView(parent), is_adding_text(false) {
setAttribute(Qt::WA_DeleteOnClose, true);
setInteractive(true);
setCacheMode(QGraphicsView::CacheBackground);
setOptimizationFlags(QGraphicsView::DontSavePainterState|QGraphicsView::DontAdjustForAntialiasing);
// active l'antialiasing
setRenderHint(QPainter::Antialiasing, true);
setRenderHint(QPainter::TextAntialiasing, true);
setRenderHint(QPainter::SmoothPixmapTransform, true);
setScene(scene = new Diagram(this));
scene = diagram ? diagram : new Diagram(this);
setScene(scene);
scene -> undoStack().setClean();
setDragMode(RubberBandDrag);
setAcceptDrops(true);
setWindowIcon(QIcon(":/ico/qet-16.png"));
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
setResizeAnchor(QGraphicsView::AnchorUnderMouse);
setAlignment(Qt::AlignLeft | Qt::AlignTop);
setSelectionMode();
adjustSceneRect();
updateWindowTitle();
context_menu = new QMenu(this);
paste_here = new QAction(QIcon(":/ico/paste.png"), tr("Coller ici"), this);
paste_here = new QAction(QIcon(":/ico/paste.png"), tr("Coller ici", "context menu action"), this);
connect(paste_here, SIGNAL(triggered()), this, SLOT(pasteHere()));
connect(scene, SIGNAL(selectionEmptinessChanged()), this, SIGNAL(selectionChanged()));
connect(scene, SIGNAL(readOnlyChanged(bool)), this, SLOT(applyReadOnly()));
connect(&(scene -> border_and_inset), SIGNAL(borderChanged(QRectF, QRectF)), this, SLOT(adjustSceneRect()));
connect(&(scene -> border_and_inset), SIGNAL(displayChanged()), this, SLOT(adjustSceneRect()));
connect(&(scene -> border_and_inset), SIGNAL(diagramTitleChanged(const QString &)), this, SLOT(updateWindowTitle()));
connect(&(scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(updateWindowTitle()));
connect(this, SIGNAL(aboutToAddElement()), this, SLOT(addDroppedElement()), Qt::QueuedConnection);
}
/**
@@ -98,6 +103,7 @@ void DiagramView::selectInvert() {
Supprime les composants selectionnes
*/
void DiagramView::deleteSelection() {
if (scene -> isReadOnly()) return;
DiagramContent removed_content = scene -> selectedContent();
scene -> clearSelection();
scene -> undoStack().push(new DeleteElementsCommand(scene, removed_content));
@@ -108,6 +114,7 @@ void DiagramView::deleteSelection() {
Pivote les composants selectionnes
*/
void DiagramView::rotateSelection() {
if (scene -> isReadOnly()) return;
QHash<Element *, QET::Orientation> elements_to_rotate;
foreach (QGraphicsItem *item, scene -> selectedItems()) {
if (Element *e = qgraphicsitem_cast<Element *>(item)) {
@@ -123,8 +130,11 @@ void DiagramView::rotateSelection() {
@param e le QDragEnterEvent correspondant au drag'n drop tente
*/
void DiagramView::dragEnterEvent(QDragEnterEvent *e) {
if (e -> mimeData() -> hasFormat("text/plain")) e -> acceptProposedAction();
else e-> ignore();
if (e -> mimeData() -> hasFormat("application/x-qet-element-uri")) {
e -> acceptProposedAction();
} else {
e -> ignore();
}
}
/**
@@ -144,18 +154,23 @@ void DiagramView::dragMoveEvent(QDragMoveEvent *e) {
}
/**
Gere les depots (drop) acceptes sur le Diagram
Gere les depots (drop) acceptes sur le schema. Cette methode emet le signal
aboutToAddElement si l'element depose est accessible.
@param e le QDropEvent correspondant au drag'n drop effectue
*/
void DiagramView::dropEvent(QDropEvent *e) {
QString fichier = e -> mimeData() -> text();
int etat;
Element *el = new CustomElement(fichier, 0, 0, &etat);
if (etat) delete el;
else {
diagram() -> undoStack().push(new AddElementCommand(diagram(), el, mapToScene(e -> pos())));
adjustSceneRect();
}
// recupere l'emplacement de l'element depuis le drag'n drop
QString elmt_path = e -> mimeData() -> text();
ElementsLocation location(ElementsLocation::locationFromString(elmt_path));
// verifie qu'il existe un element correspondant a cet emplacement
ElementsCollectionItem *dropped_item = QETApp::collectionItem(location);
if (!dropped_item) return;
next_location_ = location;
next_position_ = e-> pos();
emit(aboutToAddElement());
}
/**
@@ -163,6 +178,7 @@ void DiagramView::dropEvent(QDropEvent *e) {
*/
void DiagramView::setVisualisationMode() {
setDragMode(ScrollHandDrag);
applyReadOnly();
setInteractive(false);
emit(modeChanged());
}
@@ -173,6 +189,7 @@ void DiagramView::setVisualisationMode() {
void DiagramView::setSelectionMode() {
setDragMode(RubberBandDrag);
setInteractive(true);
applyReadOnly();
emit(modeChanged());
}
@@ -238,6 +255,8 @@ void DiagramView::copy() {
@param clipboard_mode Type de presse-papier a prendre en compte
*/
void DiagramView::paste(const QPointF &pos, QClipboard::Mode clipboard_mode) {
if (scene -> isReadOnly()) return;
QString texte_presse_papier = QApplication::clipboard() -> text(clipboard_mode);
if ((texte_presse_papier).isEmpty()) return;
@@ -270,7 +289,7 @@ void DiagramView::mousePressEvent(QMouseEvent *e) {
if (e -> buttons() == Qt::MidButton) {
paste(mapToScene(e -> pos()), QClipboard::Selection);
} else {
if (is_adding_text && e -> buttons() == Qt::LeftButton) {
if (!scene -> isReadOnly() && is_adding_text && e -> buttons() == Qt::LeftButton) {
addDiagramTextAtPos(mapToScene(e -> pos()));
is_adding_text = false;
}
@@ -278,199 +297,6 @@ void DiagramView::mousePressEvent(QMouseEvent *e) {
}
}
/**
Ouvre un fichier *.qet dans cette DiagramView
@param n_fichier Nom du fichier a ouvrir
@param erreur Si le pointeur est specifie, cet entier est mis a 0 en cas de reussite de l'ouverture, 1 si le fichier n'existe pas, 2 si le fichier n'est pas lisible, 3 si le fichier n'est pas un element XML, 4 si l'ouverture du fichier a echoue pour une autre raison (c'est pas ca qui manque ^^)
@return true si l'ouverture a reussi, false sinon
*/
bool DiagramView::open(QString n_fichier, int *erreur) {
// verifie l'existence du fichier
if (!QFileInfo(n_fichier).exists()) {
if (erreur != NULL) *erreur = 1;
return(false);
}
// ouvre le fichier
QFile fichier(n_fichier);
if (!fichier.open(QIODevice::ReadOnly)) {
if (erreur != NULL) *erreur = 2;
return(false);
}
// lit son contenu dans un QDomDocument
QDomDocument document;
if (!document.setContent(&fichier)) {
if (erreur != NULL) *erreur = 3;
fichier.close();
return(false);
}
fichier.close();
/**
La notion de projet (ensemble de documents [schemas, nomenclatures,
...] et d'elements) n'est pas encore geree.
Toutefois, pour gerer au mieux la transition de la 0.1 a la 0.2,
les schemas enregistres (element XML "diagram") sont integres dans un
pseudo projet (element XML "project").
S'il y a plusieurs schemas dans un projet, tous les schemas seront
ouverts comme etant des fichiers separes
*/
// repere les schemas dans le fichier
QDomElement root = document.documentElement();
// cas 1 : l'element racine est un "diagram" : un seul schema, pas de probleme
if (root.tagName() == "diagram") {
// construit le schema a partir du QDomDocument
QDomDocument &doc = document;
if (scene -> fromXml(doc)) {
if (erreur != NULL) *erreur = 0;
file_name = n_fichier;
scene -> undoStack().setClean();
updateWindowTitle();
return(true);
} else {
if (erreur != NULL) *erreur = 4;
return(false);
}
// cas 2 : l'element racine est un "project"
} else if (root.tagName() == "project") {
// verifie basiquement que la version actuelle est capable de lire ce fichier
if (root.hasAttribute("version")) {
bool conv_ok;
qreal diagram_version = root.attribute("version").toDouble(&conv_ok);
if (conv_ok && QET::version.toDouble() < diagram_version) {
QMessageBox::warning(
this,
tr("Avertissement"),
tr("Ce document semble avoir \351t\351 enregistr\351 avec une "
"version ult\351rieure de QElectroTech. Il est possible que "
"l'ouverture de tout ou partie de ce document \351choue.")
);
}
}
// compte le nombre de schemas dans le projet
QList<QDomElement> diagrams;
QDomNodeList diagram_nodes = root.elementsByTagName("diagram");
for (uint i = 0 ; i < diagram_nodes.length() ; ++ i) {
if (diagram_nodes.at(i).isElement()) {
diagrams << diagram_nodes.at(i).toElement();
}
}
// il n'y aucun schema la-dedans
if (!diagrams.count()) {
if (erreur != NULL) *erreur = 4;
return(false);
} else {
bool keep_doc_name = diagrams.count() == 1;
bool current_dv_loaded = false;
for (int i = 0 ; i < diagrams.count() ; ++ i) {
// cree un QDomDocument representant le schema
QDomDocument diagram_doc;
diagram_doc.appendChild(diagram_doc.importNode(diagrams[i], true));
// charge le premier schema valide et cree de nouveau DiagramView pour les suivants
if (!current_dv_loaded) {
if (scene -> fromXml(diagram_doc)) {
if (keep_doc_name) file_name = n_fichier;
scene -> undoStack().setClean();
updateWindowTitle();
current_dv_loaded = true;
}
} else {
DiagramView *new_dv = new DiagramView(parentWidget());
if (new_dv -> scene -> fromXml(diagram_doc)) {
if (keep_doc_name) new_dv -> file_name = n_fichier;
new_dv -> scene -> undoStack().setClean();
new_dv -> updateWindowTitle();
diagramEditor() -> addDiagramView(new_dv);
} else {
delete(new_dv);
}
}
}
return(true);
}
} else {
if (erreur != NULL) *erreur = 4;
return(false);
}
}
/**
Gere la fermeture du schema.
@param event Le QCloseEvent decrivant l'evenement
*/
void DiagramView::closeEvent(QCloseEvent *event) {
bool retour;
// si le schema est modifie
if (!isWindowModified()) {
retour = true;
} else {
// demande d'abord a l'utilisateur s'il veut enregistrer le schema en cours
QMessageBox::StandardButton reponse = QMessageBox::question(
this,
tr("Enregistrer le sch\351ma en cours ?"),
tr("Voulez-vous enregistrer le sch\351ma ") + windowTitle() + tr(" ?"),
QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
QMessageBox::Cancel
);
switch(reponse) {
case QMessageBox::Cancel: retour = false; break; // l'utilisateur annule : echec de la fermeture
case QMessageBox::Yes: retour = save(); break; // l'utilisateur dit oui : la reussite depend de l'enregistrement
default: retour = true; // l'utilisateur dit non ou ferme le dialogue: c'est reussi
}
}
if (retour) event -> accept();
else event -> ignore();
}
/**
Methode enregistrant le schema dans le dernier nom de fichier connu.
Si aucun nom de fichier n'est connu, cette methode appelle la methode saveAs
@return true si l'enregistrement a reussi, false sinon
*/
bool DiagramView::save() {
if (file_name.isEmpty()) return(saveAs());
else return(saveDiagramToFile(file_name));
}
/**
Cette methode demande un nom de fichier a l'utilisateur pour enregistrer le schema
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 DiagramView::saveAs() {
// demande un nom de fichier a l'utilisateur pour enregistrer le schema
QString n_fichier = QFileDialog::getSaveFileName(
this,
tr("Enregistrer sous"),
(file_name.isEmpty() ? QDir::homePath() : QDir(file_name)).absolutePath(),
tr("Sch\351ma QElectroTech (*.qet)")
);
// si aucun nom n'est entre, renvoie faux.
if (n_fichier.isEmpty()) return(false);
// si le nom ne se termine pas par l'extension .qet, celle-ci est ajoutee
if (!n_fichier.endsWith(".qet", Qt::CaseInsensitive)) n_fichier += ".qet";
// tente d'enregistrer le fichier
bool resultat_enregistrement = saveDiagramToFile(n_fichier);
// si l'enregistrement reussit, le nom du fichier est conserve
if (resultat_enregistrement) {
file_name = n_fichier;
updateWindowTitle();
}
// retourne un booleen representatif de la reussite de l'enregistrement
return(resultat_enregistrement);
}
/**
Gere les actions liees a la rollette de la souris
@param e QWheelEvent decrivant l'evenement rollette
@@ -489,70 +315,28 @@ void DiagramView::wheelEvent(QWheelEvent *e) {
}
/**
Methode privee gerant l'enregistrement du fichier XML. S'il n'est pas possible
d'ecrire dans le fichier, cette fonction affiche un message d'erreur et renvoie false.
Autrement, elle renvoie true.
@param n_fichier Nom du fichier dans lequel l'arbre XML doit etre ecrit
@return true si l'enregistrement a reussi, false sinon
@return le titre de cette vue ; cela correspond au titre du schema
visualise precede de la mention "Schema". Si le titre du schema est vide,
la mention "Schema sans titre" est utilisee
@see Diagram::title()
*/
bool DiagramView::saveDiagramToFile(QString &n_fichier) {
QFile fichier(n_fichier);
if (!fichier.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::warning(this, tr("Erreur"), tr("Impossible d'ecrire dans ce fichier"));
return(false);
}
QTextStream out(&fichier);
out.setCodec("UTF-8");
// l'export XML du schema est encapsule dans un pseudo-projet
QDomDocument final_document;
QDomElement project_root = final_document.createElement("project");
project_root.setAttribute("version", QET::version);
project_root.appendChild(final_document.importNode(scene -> toXml().documentElement(), true));
final_document.appendChild(project_root);
out << final_document.toString(4);
fichier.close();
scene -> undoStack().setClean();
return(true);
}
/**
Exporte le schema.
*/
void DiagramView::dialogExport() {
ExportDialog ed(scene, diagramEditor());
ed.exec();
}
/**
Imprime le schema.
*/
void DiagramView::dialogPrint() {
// determine un nom possible pour le document et le pdf
QString doc_name;
QString pdf_file_name;
if (!file_name.isEmpty()) {
doc_name = QFileInfo(file_name).fileName();
pdf_file_name = file_name;
pdf_file_name.replace(QRegExp("\\.qet$", Qt::CaseInsensitive), "");
QString DiagramView::title() const {
QString view_title;
QString diagram_title(scene -> title());
if (diagram_title.isEmpty()) {
view_title = tr("Sch\351ma sans titre");
} else {
doc_name = tr("schema");
pdf_file_name = QDir::toNativeSeparators(QDir::homePath() + "/" + tr("schema"));
view_title = QString(tr("Sch\351ma %1", "%1 is a diagram title")).arg(diagram_title);
}
pdf_file_name += ".pdf";
DiagramPrintDialog print_dialog(scene, this);
print_dialog.setDocName(doc_name);
print_dialog.setPDFName(pdf_file_name);
print_dialog.exec();
return(view_title);
}
/**
Edite les informations du schema.
*/
void DiagramView::dialogEditInfos() {
void DiagramView::editDiagramProperties() {
if (scene -> isReadOnly()) return;
// recupere le cartouche et les dimensions du schema
InsetProperties inset = scene -> border_and_inset.exportInset();
BorderProperties border = scene -> border_and_inset.exportBorder();
@@ -560,7 +344,7 @@ void DiagramView::dialogEditInfos() {
// construit le dialogue
QDialog popup(diagramEditor());
popup.setMinimumWidth(400);
popup.setWindowTitle(tr("Propri\351t\351s du sch\351ma"));
popup.setWindowTitle(tr("Propri\351t\351s du sch\351ma", "window title"));
BorderPropertiesWidget *border_infos = new BorderPropertiesWidget(border, &popup);
InsetPropertiesWidget *inset_infos = new InsetPropertiesWidget(inset, false, &popup);
@@ -603,6 +387,7 @@ bool DiagramView::hasSelectedItems() {
Ajoute une colonne au schema.
*/
void DiagramView::addColumn() {
if (scene -> isReadOnly()) return;
BorderProperties old_bp = scene -> border_and_inset.exportBorder();
BorderProperties new_bp = scene -> border_and_inset.exportBorder();
new_bp.columns_count += 1;
@@ -613,6 +398,7 @@ void DiagramView::addColumn() {
Enleve une colonne au schema.
*/
void DiagramView::removeColumn() {
if (scene -> isReadOnly()) return;
BorderProperties old_bp = scene -> border_and_inset.exportBorder();
BorderProperties new_bp = scene -> border_and_inset.exportBorder();
new_bp.columns_count -= 1;
@@ -623,6 +409,7 @@ void DiagramView::removeColumn() {
Agrandit le schema en hauteur
*/
void DiagramView::addRow() {
if (scene -> isReadOnly()) return;
BorderProperties old_bp = scene -> border_and_inset.exportBorder();
BorderProperties new_bp = scene -> border_and_inset.exportBorder();
new_bp.rows_count += 1;
@@ -633,6 +420,7 @@ void DiagramView::addRow() {
Retrecit le schema en hauteur
*/
void DiagramView::removeRow() {
if (scene -> isReadOnly()) return;
BorderProperties old_bp = scene -> border_and_inset.exportBorder();
BorderProperties new_bp = scene -> border_and_inset.exportBorder();
new_bp.rows_count -= 1;
@@ -665,12 +453,19 @@ void DiagramView::adjustSceneRect() {
Met a jour le titre du widget
*/
void DiagramView::updateWindowTitle() {
QString window_title;
if (file_name.isNull()) window_title += tr("nouveau sch\351ma");
else window_title += file_name;
window_title += "[*]";
setWindowTitle(window_title);
setWindowModified(!(scene -> undoStack().isClean()));
QString view_title(title());
// verifie si le document a ete modifie
bool modified_diagram = !(scene -> undoStack().isClean());
// specifie le titre du widget
setWindowTitle(view_title + " [*]");
setWindowModified(modified_diagram);
// emet le signal titleChanged en ajoutant manuellement [*] si le schema a ete modifie
QString emitted_title = view_title;
if (modified_diagram) emitted_title += " [*]";
emit(titleChanged(this, emitted_title));
}
/**
@@ -699,6 +494,63 @@ QRectF DiagramView::viewedSceneRect() const {
return(QRectF(scene_left_top, scene_right_bottom));
}
/**
Cette methode permet de determiner s'il faut ou non integrer au projet un
element dont on connait l'emplacement.
L'element droppe est integre a la collection du projet :
* s'il appartient a un autre projet, quelque soit la specification de
l'utilisateur a ce propos ;
* s'il appartient a la collection commune ou a la collection
personnelle ET que l'utilisateur a autorise l'integration automatique
des elements dans les projets.
@param location Emplacement de l'element
@return true si l'element doit etre integre, false sinon
*/
bool DiagramView::mustIntegrateElement(const ElementsLocation &location) const {
// l'utilisateur a-t-il autorise l'integration automatique des elements dans les projets ?
bool auto_integration_enabled = QETApp::settings().value("diagrameditor/integrate-elements", true).toBool();
// l'element appartient-il a un projet et si oui, est-ce un autre projet ?
bool elmt_from_project = location.project();
bool elmt_from_another_project = elmt_from_project && location.project() != scene -> project();
// faut-il integrer l'element ?
bool must_integrate_element = (elmt_from_another_project || (auto_integration_enabled && !elmt_from_project));
return(must_integrate_element);
}
/**
@param location Emplacement de l'element a ajouter sur le schema
@param pos Position (dans les coordonnees de la vue) a laquelle l'element sera ajoute
*/
bool DiagramView::addElementAtPos(const ElementsLocation &location, const QPoint &pos) {
// construit une instance de l'element correspondant a l'emplacement
int etat;
Element *el = new CustomElement(location, 0, 0, &etat);
if (etat) {
delete el;
return(false);
}
// pose de l'element sur le schema
diagram() -> undoStack().push(new AddElementCommand(diagram(), el, mapToScene(pos)));
return(true);
}
/**
Fait en sorte que le schema ne soit editable que s'il n'est pas en lecture
seule
*/
void DiagramView::applyReadOnly() {
if (!scene) return;
bool is_writable = !scene -> isReadOnly();
setInteractive(is_writable);
setAcceptDrops(is_writable);
}
/**
Affiche un dialogue permettant d'editer le conducteur selectionne.
Ne fait rien s'il y a 0 ou plusieurs conducteurs selectionnes.
@@ -718,6 +570,7 @@ void DiagramView::editConductor() {
@param edited_conductor Conducteur a editer
*/
void DiagramView::editConductor(Conductor *edited_conductor) {
if (scene -> isReadOnly()) return;
if (!edited_conductor) return;
// initialise l'editeur de proprietes pour le conducteur
@@ -726,7 +579,7 @@ void DiagramView::editConductor(Conductor *edited_conductor) {
// l'insere dans un dialogue
QDialog conductor_dialog(diagramEditor());
conductor_dialog.setWindowTitle(tr("\311diter les propri\351t\351s d'un conducteur"));
conductor_dialog.setWindowTitle(tr("\311diter les propri\351t\351s d'un conducteur", "window title"));
QVBoxLayout *dialog_layout = new QVBoxLayout(&conductor_dialog);
dialog_layout -> addWidget(cpw);
dialog_layout -> addStretch();
@@ -754,6 +607,7 @@ void DiagramView::editConductor(Conductor *edited_conductor) {
Reinitialise le profil des conducteurs selectionnes
*/
void DiagramView::resetConductors() {
if (scene -> isReadOnly()) return;
// recupere les conducteurs selectionnes
QSet<Conductor *> selected_conductors = scene -> selectedConductors();
@@ -780,12 +634,13 @@ void DiagramView::resetConductors() {
futurs nouveaux conducteurs
*/
void DiagramView::editDefaultConductorProperties() {
if (scene -> isReadOnly()) return;
// initialise l'editeur de proprietes pour le conducteur
ConductorPropertiesWidget *cpw = new ConductorPropertiesWidget(scene -> defaultConductorProperties);
// l'insere dans un dialogue
QDialog conductor_dialog(diagramEditor());
conductor_dialog.setWindowTitle(tr("\311diter les propri\351t\351s par d\351faut des conducteurs"));
conductor_dialog.setWindowTitle(tr("\311diter les propri\351t\351s par d\351faut des conducteurs", "window title"));
QVBoxLayout *dialog_layout = new QVBoxLayout(&conductor_dialog);
dialog_layout -> addWidget(cpw);
QDialogButtonBox *dbb = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
@@ -818,6 +673,7 @@ bool DiagramView::event(QEvent *e) {
nouveau champ de texte.
*/
void DiagramView::addText() {
if (scene -> isReadOnly()) return;
is_adding_text = true;
}
@@ -935,8 +791,36 @@ void DiagramView::mouseDoubleClickEvent(QMouseEvent *e) {
}
} else if (inset_rect.contains(click_pos) || columns_rect.contains(click_pos) || rows_rect.contains(click_pos)) {
// edite les proprietes du schema
dialogEditInfos();
editDiagramProperties();
} else {
QGraphicsView::mouseDoubleClickEvent(e);
}
}
/**
Cette methode ajoute l'element deisgne par l'emplacement location a la
position pos. Si necessaire, elle demande l'integration de l'element au
projet.
@param location emplacement d'un element a ajouter sur le schema
@param pos position voulue de l'element sur le schema
@see mustIntegrateElement
*/
void DiagramView::addDroppedElement() {
ElementsLocation location = next_location_;
QPoint pos = next_position_;
if (!mustIntegrateElement(location)) {
addElementAtPos(location, pos);
} else {
QString error_msg;
IntegrationMoveElementsHandler *integ_handler = new IntegrationMoveElementsHandler(this);
QString integ_path = scene -> project() -> integrateElement(location.toString(), integ_handler, error_msg);
delete integ_handler;
if (integ_path.isEmpty()) {
qDebug() << error_msg;
return;
}
addElementAtPos(ElementsLocation::locationFromString(integ_path), pos);
}
adjustSceneRect();
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -18,6 +18,7 @@
#ifndef DIAGRAMVIEW_H
#define DIAGRAMVIEW_H
#include <QtGui>
#include "elementslocation.h"
class Diagram;
class DiagramTextItem;
class QETDiagramEditor;
@@ -30,33 +31,26 @@ class DiagramView : public QGraphicsView {
// constructeurs, destructeur
public:
DiagramView(QWidget * = 0);
DiagramView(Diagram * = 0, QWidget * = 0);
virtual ~DiagramView();
private:
DiagramView(const DiagramView &);
// attributs
public:
/// Nom de fichier du schema edite
QString file_name;
private:
Diagram *scene;
QMenu *context_menu;
QAction *paste_here;
QPoint paste_here_pos;
bool is_adding_text;
ElementsLocation next_location_;
QPoint next_position_;
// methodes
public:
bool open(QString, int * = NULL);
void closeEvent(QCloseEvent *);
bool save();
bool saveAs();
void dialogExport();
void dialogEditInfos();
void dialogPrint();
QString title() const;
void editDiagramProperties();
void addColumn();
void removeColumn();
void addRow();
@@ -75,13 +69,14 @@ class DiagramView : public QGraphicsView {
virtual bool event(QEvent *);
private:
bool saveDiagramToFile(QString &);
void mousePressEvent(QMouseEvent *);
void dragEnterEvent(QDragEnterEvent *);
void dragLeaveEvent(QDragLeaveEvent *);
void dragMoveEvent(QDragMoveEvent *);
void dropEvent(QDropEvent *);
QRectF viewedSceneRect() const;
bool mustIntegrateElement(const ElementsLocation &) const;
bool addElementAtPos(const ElementsLocation &, const QPoint &);
signals:
/// Signal emis lorsque la selection change
@@ -90,6 +85,10 @@ class DiagramView : public QGraphicsView {
void modeChanged();
/// Signal emis lorsqu'un texte a ete pose
void textAdded(bool);
/// Signal emis lorsque le titre du schema change
void titleChanged(DiagramView *, const QString &);
/// Signal emis avant l'integration d'un element
void aboutToAddElement();
public slots:
void selectNothing();
@@ -115,6 +114,8 @@ class DiagramView : public QGraphicsView {
void editDefaultConductorProperties();
private slots:
void addDroppedElement();
void adjustGridToZoom();
void applyReadOnly();
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -74,6 +74,7 @@ class CustomElementGraphicPart : public CustomElementPart {
/// Destructeur
virtual ~CustomElementGraphicPart() {
if (style_editor -> parentWidget()) return; // l'editeur de style sera supprime par son parent
delete style_editor;
};

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -29,7 +29,7 @@ DeletePartsCommand::DeletePartsCommand(
const QList<QGraphicsItem *> parts,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("suppression"), parent),
QUndoCommand(QObject::tr("suppression", "undo caption"), parent),
deleted_parts(parts),
editor_scene(scene)
{
@@ -59,6 +59,94 @@ void DeletePartsCommand::redo() {
}
}
/*** CutPartsCommand ***/
/**
Constructeur
@param scene ElementScene concernee
@param parts Liste des parties collees
@param parent QUndoCommand parent
*/
PastePartsCommand::PastePartsCommand(
ElementView *view,
const ElementContent &c,
QUndoCommand *parent
) :
QUndoCommand(parent),
content_(c),
editor_view_(view),
editor_scene_(view -> scene()),
uses_offset(false),
first_redo(true)
{
setText(QObject::tr("coller"));
editor_scene_ -> qgiManager().manage(content_);
}
/// Destructeur
PastePartsCommand::~PastePartsCommand() {
editor_scene_ -> qgiManager().release(content_);
}
/// annule le coller
void PastePartsCommand::undo() {
// enleve les parties
foreach(QGraphicsItem *part, content_) editor_scene_ -> removeItem(part);
if (uses_offset) {
editor_view_ -> offset_paste_count_ = old_offset_paste_count_;
editor_view_ -> start_top_left_corner_ = old_start_top_left_corner_;
}
editor_view_ -> adjustSceneRect();
}
/// refait le coller
void PastePartsCommand::redo() {
if (first_redo) first_redo = false;
else {
// pose les parties
foreach(QGraphicsItem *part, content_) editor_scene_ -> addItem(part);
if (uses_offset) {
editor_view_ -> offset_paste_count_ = new_offset_paste_count_;
editor_view_ -> start_top_left_corner_ = new_start_top_left_corner_;
}
}
foreach(QGraphicsItem *part, content_) part -> setSelected(true);
editor_view_ -> adjustSceneRect();
}
/**
Indique a cet objet d'annulation que le c/c a annuler ou refaire etait un
c/c avec decalage ; il faut plus d'informations pour annuler ce type de
collage.
*/
void PastePartsCommand::setOffset(int old_offset_pc, const QPointF &old_start_tlc, int new_offset_pc, const QPointF &new_start_tlc) {
old_offset_paste_count_ = old_offset_pc;
old_start_top_left_corner_ = old_start_tlc;
new_offset_paste_count_ = new_offset_pc;
new_start_top_left_corner_ = new_start_tlc;
uses_offset = true;
}
/*** CutPartsCommand ***/
/**
Constructeur
@param scene ElementScene concernee
@param parts Liste des parties coupees
@param parent QUndoCommand parent
*/
CutPartsCommand::CutPartsCommand(
ElementScene *scene,
const QList<QGraphicsItem *> parts,
QUndoCommand *parent
) :
DeletePartsCommand(scene, parts, parent)
{
setText(QString(QObject::tr("couper des parties", "undo caption")));
}
/// Destructeur
CutPartsCommand::~CutPartsCommand() {
}
/*** MovePartsCommand ***/
/**
Constructeur
@@ -73,7 +161,7 @@ MovePartsCommand::MovePartsCommand(
const QList<QGraphicsItem *> parts,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("d\351placement"), parent),
QUndoCommand(QObject::tr("d\351placement", "undo caption"), parent),
movement(m),
first_redo(true)
{
@@ -114,7 +202,7 @@ AddPartCommand::AddPartCommand(
QGraphicsItem *p,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("ajout ") + name, parent),
QUndoCommand(QString(QObject::tr("ajout %1", "undo caption")).arg(name), parent),
part(p),
editor_scene(scene),
first_redo(true)
@@ -161,7 +249,7 @@ ChangePartCommand::ChangePartCommand(
const QVariant &new_v,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modification ") + name, parent),
QUndoCommand(QString(QObject::tr("modification %1", "undo caption")).arg(name), parent),
cep(part),
property(prop),
old_value(old_v),
@@ -196,7 +284,7 @@ ChangePolygonPointsCommand::ChangePolygonPointsCommand(
const QVector<QPointF> &n_points,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modification points polygone"), parent),
QUndoCommand(QObject::tr("modification points polygone", "undo caption"), parent),
polygon(p),
old_points(o_points),
new_points(n_points)
@@ -236,7 +324,7 @@ ChangeHotspotCommand::ChangeHotspotCommand(
const QPoint &o,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modification dimensions/hotspot"), parent),
QUndoCommand(QObject::tr("modification dimensions/hotspot", "undo caption"), parent),
element(element_scene),
size_before(size_1),
size_after(size_2),
@@ -297,7 +385,7 @@ ChangeNamesCommand::ChangeNamesCommand(
const NamesList &after,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modification noms"), parent),
QUndoCommand(QObject::tr("modification noms", "undo caption"), parent),
names_before(before),
names_after(after),
element(element_scene)
@@ -331,7 +419,7 @@ ChangeOrientationsCommand::ChangeOrientationsCommand(
const OrientationSet &after,
QUndoCommand *parent
) :
QUndoCommand(QObject::tr("modification orientations"), parent),
QUndoCommand(QObject::tr("modification orientations", "undo caption"), parent),
ori_before(before),
ori_after(after),
element(element_scene)
@@ -375,16 +463,16 @@ ChangeZValueCommand::ChangeZValueCommand(
// choisit le nom en fonction du traitement
if (option == BringForward) {
setText(QObject::tr("amener au premier plan"));
setText(QObject::tr("amener au premier plan", "undo caption"));
applyBringForward(items_list);
} else if (option == Raise) {
setText(QObject::tr("rapprocher"));
setText(QObject::tr("rapprocher", "undo caption"));
applyRaise(items_list);
} else if (option == Lower) {
setText(QObject::tr("\351loigner"));
setText(QObject::tr("\351loigner", "undo caption"));
applyLower(items_list);
} else if (option == SendBackward) {
setText(QObject::tr("envoyer au fond"));
setText(QObject::tr("envoyer au fond", "undo caption"));
applySendBackward(items_list);
}
}
@@ -483,7 +571,7 @@ void ChangeZValueCommand::applySendBackward(const QList<QGraphicsItem *> &items_
@param parent QUndoCommand parent
*/
AllowInternalConnectionsCommand::AllowInternalConnectionsCommand(ElementScene *elmt, bool allow, QUndoCommand *parent) :
QUndoCommand(QObject::tr("modification connexions internes"), parent),
QUndoCommand(QObject::tr("modification connexions internes", "undo caption"), parent),
element(elmt),
ic(allow)
{

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -19,7 +19,9 @@
#define EDITOR_COMMANDS_H
#include "customelementpart.h"
#include "partpolygon.h"
#include "elementview.h"
#include "elementscene.h"
#include "elementcontent.h"
#include "qgimanager.h"
#include <QtGui>
/**
@@ -47,6 +49,52 @@ class DeletePartsCommand : public QUndoCommand {
ElementScene *editor_scene;
};
/**
Cette classe represente l'action de coller quelque chose dans un element
*/
class PastePartsCommand : public QUndoCommand {
// constructeurs, destructeur
public:
PastePartsCommand(ElementView *, const ElementContent &, QUndoCommand * = 0);
virtual ~PastePartsCommand();
private:
PastePartsCommand(const PastePartsCommand &);
// methodes
public:
virtual void undo();
virtual void redo();
virtual void setOffset(int, const QPointF &, int, const QPointF &);
// attributs
private:
/// contenu ajoute
ElementContent content_;
/// schema sur lequel on colle les elements et conducteurs
ElementView *editor_view_;
ElementScene *editor_scene_;
/// Informations pour annuler un c/c avec decalage
int old_offset_paste_count_;
QPointF old_start_top_left_corner_;
int new_offset_paste_count_;
QPointF new_start_top_left_corner_;
bool uses_offset;
/// booleen pour empecher le premier appel a redo
bool first_redo;
};
/**
Cette classe represente l'action de supprimer des parties d'un element
*/
class CutPartsCommand : public DeletePartsCommand {
// constructeurs, destructeur
public:
CutPartsCommand(ElementScene *, const QList<QGraphicsItem *>, QUndoCommand * = 0);
virtual ~CutPartsCommand();
private:
CutPartsCommand(const CutPartsCommand &);
};
/**
Cette classe represente l'action de deplacer une ou plusieurs
parties lors de l'edition d'un element

View File

@@ -0,0 +1,30 @@
/*
Copyright 2006-2009 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 ELEMENT_CONTENT_H
#define ELEMENT_CONTENT_H
#include <QList>
class QGraphicsItem;
/**
Lors de son edition dans l'editeur d'element, un element est decompose en
parties graphiques. La classe ElementContent represente un ensemble de parties
graphiques constituant tout ou partie d'un element.
Note : pour le moment, ElementContent est un typedef pour QList\<QGraphicsItem *\>
@see la documentation Qt de la classe QList
*/
typedef QList<QGraphicsItem *> ElementContent;
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -22,7 +22,7 @@ class QETElementEditor;
class ElementScene;
class CustomElementPart;
/**
Cette classe est la classe de base pour les editeurs de aprties dans
Cette classe est la classe de base pour les editeurs de parties dans
l'editeur d'element. Elle fournit des methodes pour acceder facilement
a l'editeur, a la pile d'annulation, a la scene d'edition ou encore pour
ajouter facilement une annulation de type ChangePartCommand.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "qetelementeditor.h"
#include <cmath>
#include "partline.h"
#include "partrectangle.h"
#include "partellipse.h"
#include "partcircle.h"
#include "partpolygon.h"
@@ -28,9 +29,7 @@
#include "partarc.h"
#include "hotspoteditor.h"
#include "editorcommands.h"
const int ElementScene::xGrid = 10;
const int ElementScene::yGrid = 10;
#include "elementcontent.h"
/**
Constructeur
@@ -47,6 +46,8 @@ ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
element_editor(editor)
{
current_polygon = NULL;
setGrid(1, 1);
initPasteArea();
undo_stack.setClean();
}
@@ -68,6 +69,13 @@ void ElementScene::slot_addLine() {
behavior = Line;
}
/**
Passe la scene en mode "ajout de rectangle"
*/
void ElementScene::slot_addRectangle() {
behavior = Rectangle;
}
/**
Passe la scene en mode "ajout de cercle"
*/
@@ -104,7 +112,6 @@ void ElementScene::slot_addTerminal() {
behavior = Terminal;
}
/**
Passe la scene en mode "ajout d'arc de cercle"
*/
@@ -124,7 +131,17 @@ void ElementScene::slot_addTextField() {
@param e objet decrivant l'evenement
*/
void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
QPointF event_pos = e -> scenePos();
if (mustSnapToGrid(e)) snapToGrid(event_pos);
if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL;
if (behavior == PasteArea) {
QRectF current_rect(paste_area_ -> rect());
current_rect.moveCenter(event_pos);
paste_area_ -> setRect(current_rect);
return;
}
QRectF temp_rect;
qreal radius;
QPointF temp_point;
@@ -132,21 +149,26 @@ void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
if (e -> buttons() & Qt::LeftButton) {
switch(behavior) {
case Line:
current_line -> setLine(QLineF(current_line -> line().p1(), e -> scenePos()));
current_line -> setLine(QLineF(current_line -> line().p1(), event_pos));
break;
case Rectangle:
temp_rect = current_rectangle -> rect();
temp_rect.setBottomRight(event_pos);
current_rectangle -> setRect(temp_rect);
break;
case Ellipse:
temp_rect = current_ellipse -> rect();
temp_rect.setBottomRight(e -> scenePos());
temp_rect.setBottomRight(event_pos);
current_ellipse -> setRect(temp_rect);
break;
case Arc:
temp_rect = current_arc -> rect();
temp_rect.setBottomRight(e -> scenePos());
temp_rect.setBottomRight(event_pos);
current_arc -> setRect(temp_rect);
break;
case Circle:
temp_rect = current_circle -> rect();
temp_point = e -> scenePos() - current_circle -> mapToScene(temp_rect.center());
temp_point = event_pos - current_circle -> mapToScene(temp_rect.center());
radius = sqrt(pow(temp_point.x(), 2) + pow(temp_point.y(), 2));
temp_rect = QRectF(
temp_rect.center() - QPointF(radius, radius),
@@ -158,17 +180,35 @@ void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
if (current_polygon == NULL) break;
temp_polygon = current_polygon -> polygon();
temp_polygon.pop_back();
temp_polygon << e -> scenePos();
temp_polygon << event_pos;
current_polygon -> setPolygon(temp_polygon);
break;
case Normal:
default:
QGraphicsScene::mouseMoveEvent(e);
QList<QGraphicsItem *> selected_items = selectedItems();
if (!selected_items.isEmpty()) {
// mouvement de souris realise depuis le dernier press event
QPointF mouse_movement = e -> scenePos() - moving_press_pos;
// application de ce mouvement a la fsi_pos enregistre dans le dernier press event
QPointF new_fsi_pos = fsi_pos + mouse_movement;
// snap eventuel de la nouvelle fsi_pos
if (mustSnapToGrid(e)) snapToGrid(new_fsi_pos);
// difference entre la fsi_pos finale et la fsi_pos courante = mouvement a appliquer
QPointF current_fsi_pos = selected_items.first() -> scenePos();
QPointF final_movement = new_fsi_pos - current_fsi_pos;
foreach(QGraphicsItem *qgi, selected_items) {
qgi -> moveBy(final_movement.x(), final_movement.y());
}
}
}
} else if (behavior == Polygon && current_polygon != NULL) {
temp_polygon = current_polygon -> polygon();
temp_polygon.pop_back();
temp_polygon << e -> scenePos();
temp_polygon << event_pos;
current_polygon -> setPolygon(temp_polygon);
} else QGraphicsScene::mouseMoveEvent(e);
}
@@ -178,27 +218,34 @@ void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
@param e objet decrivant l'evenement
*/
void ElementScene::mousePressEvent(QGraphicsSceneMouseEvent *e) {
QPointF event_pos = e -> scenePos();
if (mustSnapToGrid(e)) snapToGrid(event_pos);
if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL;
QPolygonF temp_polygon;
if (e -> button() & Qt::LeftButton) {
switch(behavior) {
case Line:
current_line = new PartLine(element_editor, 0, this);
current_line -> setLine(QLineF(e -> scenePos(), e -> scenePos()));
current_line -> setLine(QLineF(event_pos, event_pos));
break;
case Rectangle:
current_rectangle = new PartRectangle(element_editor, 0, this);
current_rectangle -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
break;
case Ellipse:
current_ellipse = new PartEllipse(element_editor, 0, this);
current_ellipse -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0)));
current_ellipse -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
current_ellipse -> setProperty("antialias", true);
break;
case Arc:
current_arc = new PartArc(element_editor, 0, this);
current_arc -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0)));
current_arc -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
current_arc -> setProperty("antialias", true);
break;
case Circle:
current_circle = new PartCircle(element_editor, 0, this);
current_circle -> setRect(QRectF(e -> scenePos(), QSizeF(0.0, 0.0)));
current_circle -> setRect(QRectF(event_pos, QSizeF(0.0, 0.0)));
current_circle -> setProperty("antialias", true);
break;
case Polygon:
@@ -207,14 +254,23 @@ void ElementScene::mousePressEvent(QGraphicsSceneMouseEvent *e) {
temp_polygon = QPolygonF(0);
} else temp_polygon = current_polygon -> polygon();
// au debut, on insere deux points
if (!temp_polygon.count()) temp_polygon << e -> scenePos();
temp_polygon << e -> scenePos();
if (!temp_polygon.count()) temp_polygon << event_pos;
temp_polygon << event_pos;
current_polygon -> setPolygon(temp_polygon);
break;
case Normal:
default:
QGraphicsScene::mousePressEvent(e);
if (!selectedItems().isEmpty()) fsi_pos = selectedItems().first() -> scenePos();
// gestion des deplacements de parties
if (!selectedItems().isEmpty()) {
fsi_pos = selectedItems().first() -> scenePos();
moving_press_pos = e -> scenePos();
moving_parts_ = true;
} else {
fsi_pos = QPoint();
moving_press_pos = QPoint();
moving_parts_ = false;
}
}
} else QGraphicsScene::mousePressEvent(e);
}
@@ -224,71 +280,97 @@ void ElementScene::mousePressEvent(QGraphicsSceneMouseEvent *e) {
@param e objet decrivant l'evenement
*/
void ElementScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
QPointF event_pos = e -> scenePos();
if (mustSnapToGrid(e)) snapToGrid(event_pos);
PartTerminal *terminal;
PartText *text;
PartTextField *textfield;
if (behavior != Polygon && current_polygon != NULL) current_polygon = NULL;
if (behavior == PasteArea) {
defined_paste_area_ = paste_area_ -> rect();
removeItem(paste_area_);
emit(pasteAreaDefined(defined_paste_area_));
behavior = Normal;
return;
}
if (e -> button() & Qt::LeftButton) {
switch(behavior) {
case Line:
if (qgiManager().manages(current_line)) break;
undo_stack.push(new AddPartCommand(tr("ligne"), this, current_line));
emit(partsAdded());
endCurrentBehavior(e);
break;
case Rectangle:
if (qgiManager().manages(current_rectangle)) break;
current_rectangle -> setRect(current_rectangle -> rect().normalized());
undo_stack.push(new AddPartCommand(tr("rectangle"), this, current_rectangle));
emit(partsAdded());
endCurrentBehavior(e);
break;
case Ellipse:
if (qgiManager().manages(current_ellipse)) break;
current_ellipse -> setRect(current_ellipse -> rect().normalized());
undo_stack.push(new AddPartCommand(tr("ellipse"), this, current_ellipse));
emit(partsAdded());
endCurrentBehavior(e);
break;
case Arc:
if (qgiManager().manages(current_arc)) break;
current_arc-> setRect(current_arc -> rect().normalized());
undo_stack.push(new AddPartCommand(tr("arc"), this, current_arc));
emit(partsAdded());
endCurrentBehavior(e);
break;
case Circle:
if (qgiManager().manages(current_circle)) break;
current_circle -> setRect(current_circle -> rect().normalized());
undo_stack.push(new AddPartCommand(tr("cercle"), this, current_circle));
emit(partsAdded());
endCurrentBehavior(e);
break;
case Terminal:
terminal = new PartTerminal(element_editor, 0, this);
terminal -> setPos(e -> scenePos());
terminal -> setPos(event_pos);
undo_stack.push(new AddPartCommand(tr("borne"), this, terminal));
emit(partsAdded());
endCurrentBehavior(e);
break;
case Text:
text = new PartText(element_editor, 0, this);
text -> setPos(e -> scenePos());
text -> setPos(event_pos);
undo_stack.push(new AddPartCommand(tr("texte"), this, text));
emit(partsAdded());
endCurrentBehavior(e);
break;
case TextField:
textfield = new PartTextField(element_editor, 0, this);
textfield -> setPos(e -> scenePos());
textfield -> setPos(event_pos);
undo_stack.push(new AddPartCommand(tr("champ de texte"), this, textfield));
emit(partsAdded());
endCurrentBehavior(e);
break;
case Normal:
default:
QGraphicsScene::mouseReleaseEvent(e);
// detecte les deplacements de parties
if (!selectedItems().isEmpty()) {
if (!selectedItems().isEmpty() && moving_parts_) {
QPointF movement = selectedItems().first() -> scenePos() - fsi_pos;
if (!movement.isNull()) {
undo_stack.push(new MovePartsCommand(movement, this, selectedItems()));
}
}
QGraphicsScene::mouseReleaseEvent(e);
moving_parts_ = false;
}
} else if (e -> button() & Qt::RightButton) {
if (behavior == Polygon && current_polygon != NULL) {
behavior = Normal;
undo_stack.push(new AddPartCommand(tr("polygone"), this, current_polygon));
current_polygon = NULL;
emit(partsAdded());
emit(needNormalMode());
endCurrentBehavior(e);
} else QGraphicsScene::mouseReleaseEvent(e);
} else QGraphicsScene::mouseReleaseEvent(e);
}
@@ -317,6 +399,10 @@ void ElementScene::drawBackground(QPainter *p, const QRectF &r) {
p -> setBrush(Qt::NoBrush);
p -> drawRect(drawable_area);
// on dessine un point de la grille sur 10
int drawn_x_grid = x_grid * 10;
int drawn_y_grid = y_grid * 10;
if (r.width() < 2500 && r.height() < 2500) {
// dessine les points de la grille
p -> setPen(Qt::black);
@@ -325,12 +411,12 @@ void ElementScene::drawBackground(QPainter *p, const QRectF &r) {
qreal limite_y = r.y() + r.height();
int g_x = (int)ceil(r.x());
while (g_x % xGrid) ++ g_x;
while (g_x % drawn_x_grid) ++ g_x;
int g_y = (int)ceil(r.y());
while (g_y % yGrid) ++ g_y;
while (g_y % drawn_y_grid) ++ g_y;
for (int gx = g_x ; gx < limite_x ; gx += xGrid) {
for (int gy = g_y ; gy < limite_y ; gy += yGrid) {
for (int gx = g_x ; gx < limite_x ; gx += drawn_x_grid) {
for (int gy = g_y ; gy < limite_y ; gy += drawn_y_grid) {
p -> drawPoint(gx, gy);
}
}
@@ -358,11 +444,50 @@ void ElementScene::drawForeground(QPainter *p, const QRectF &) {
p -> restore();
}
/**
A partir d'un evenement souris, cette methode regarde si la touche shift est
enfoncee ou non. Si oui, elle laisse le comportement en cours (cercle,
texte, polygone, ...). Si non, elle repasse en mode normal / selection.
@param e objet decrivant l'evenement souris
*/
void ElementScene::endCurrentBehavior(const QGraphicsSceneMouseEvent *event) {
if (!(event -> modifiers() & Qt::ShiftModifier)) {
// la touche Shift n'est pas enfoncee : on demande le mode normal
behavior = Normal;
emit(needNormalMode());
}
}
/**
@return la taille horizontale de la grille
*/
int ElementScene::xGrid() const {
return(x_grid);
}
/**
@return la taille verticale de la grille
*/
int ElementScene::yGrid() const {
return(y_grid);
}
/**
@param x_grid Taille horizontale de la grille
@param y_grid Taille verticale de la grille
*/
void ElementScene::setGrid(int x_g, int y_g) {
x_grid = x_g ? x_g : 1;
y_grid = y_g ? y_g : 1;
}
/**
Exporte l'element en XML
@param diagram Booleen (a vrai par defaut) indiquant si le XML genere doit
representer tout l'element ou seulement les elements selectionnes
@return un document XML decrivant l'element
*/
const QDomDocument ElementScene::toXml() const {
const QDomDocument ElementScene::toXml(bool all_parts) const {
// document XML
QDomDocument xml_document;
@@ -383,6 +508,8 @@ const QDomDocument ElementScene::toXml() const {
QDomElement description = xml_document.createElement("description");
// description de l'element
foreach(QGraphicsItem *qgi, zItems(true)) {
// si l'export ne concerne que la selection, on ignore les parties non selectionnees
if (!all_parts && !qgi -> isSelected()) continue;
if (CustomElementPart *ce = dynamic_cast<CustomElementPart *>(qgi)) {
if (ce -> isUseless()) continue;
description.appendChild(ce -> toXml(xml_document));
@@ -395,91 +522,90 @@ const QDomDocument ElementScene::toXml() const {
}
/**
Lit un element depuis un document XML
@param xml_document un document XML decrivant l'element
@param xml_document un document XML decrivant un element
@return le boundingRect du contenu de l'element
*/
void ElementScene::fromXml(const QDomDocument &xml_document) {
QRectF ElementScene::boundingRectFromXml(const QDomDocument &xml_document) {
// charge les parties depuis le document XML
ElementContent loaded_content = loadContent(xml_document);
if (loaded_content.isEmpty()) return(QRectF());
// calcule le boundingRect
QRectF bounding_rect = elementContentBoundingRect(loaded_content);
// detruit les parties chargees
qDeleteAll(loaded_content);
return(bounding_rect);
}
/**
Importe l'element decrit dans un document XML. Si une position est
precisee, les elements importes sont positionnes de maniere a ce que le
coin superieur gauche du plus petit rectangle pouvant les entourant tous
(le bounding rect) soit a cette position.
@param xml_document un document XML decrivant l'element
@param position La position des parties importees
@param consider_informations Si vrai, les informations complementaires
(dimensions, hotspot, etc.) seront prises en compte
@param content_ptr si ce pointeur vers un ElementContent est different de 0,
il sera rempli avec le contenu ajoute a l'element par le fromXml
@return true si l'import a reussi, false sinon
*/
void ElementScene::fromXml(
const QDomDocument &xml_document,
const QPointF &position,
bool consider_informations,
ElementContent *content_ptr
) {
QString error_message;
bool state = true;
// la racine est supposee etre une definition d'element
QDomElement root = xml_document.documentElement();
if (root.tagName() != "definition" || root.attribute("type") != "element") {
state = false;
error_message = tr("Ce document XML n'est pas une definition d'\351l\351ment.");
}
// dimensions et hotspot
if (state) {
// ces attributs doivent etre presents et valides
int w, h, hot_x, hot_y;
if (
!QET::attributeIsAnInteger(root, QString("width"), &w) ||\
!QET::attributeIsAnInteger(root, QString("height"), &h) ||\
!QET::attributeIsAnInteger(root, QString("hotspot_x"), &hot_x) ||\
!QET::attributeIsAnInteger(root, QString("hotspot_y"), &hot_y)
) {
state = false;
error_message = tr("Les dimensions ou le point de saisie ne sont pas valides.");
} else {
setWidth(w);
setHeight(h);
setHotspot(QPoint(hot_x, hot_y));
}
}
// orientations et connexions internes
if (state) {
internal_connections = (root.attribute("ic") == "true");
if (!ori.fromString(root.attribute("orientation"))) {
state = false;
error_message = tr("Les orientations ne sont pas valides.");
}
}
// extrait les noms de la definition XML
if (state) {
_names.fromXml(root);
// prend en compte les informations de l'element
if (consider_informations) {
state = applyInformations(xml_document, &error_message);
}
// parcours des enfants de la definition : parties de l'element
if (state) {
for (QDomNode node = root.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
QDomElement elmts = node.toElement();
if (elmts.isNull()) continue;
if (elmts.tagName() == "description") {
// gestion de la description graphique de l'element
// = parcours des differentes parties du dessin
int z = 1;
for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
QDomElement qde = n.toElement();
if (qde.isNull()) continue;
CustomElementPart *cep;
if (qde.tagName() == "line") cep = new PartLine (element_editor, 0, this);
else if (qde.tagName() == "ellipse") cep = new PartEllipse (element_editor, 0, this);
else if (qde.tagName() == "circle") cep = new PartCircle (element_editor, 0, this);
else if (qde.tagName() == "polygon") cep = new PartPolygon (element_editor, 0, this);
else if (qde.tagName() == "terminal") cep = new PartTerminal (element_editor, 0, this);
else if (qde.tagName() == "text") cep = new PartText (element_editor, 0, this);
else if (qde.tagName() == "input") cep = new PartTextField(element_editor, 0, this);
else if (qde.tagName() == "arc") cep = new PartArc (element_editor, 0, this);
else continue;
if (QGraphicsItem *qgi = dynamic_cast<QGraphicsItem *>(cep)) qgi -> setZValue(z++);
cep -> fromXml(qde);
}
}
ElementContent loaded_content = loadContent(xml_document, &error_message);
if (position != QPointF()) {
addContentAtPos(loaded_content, position, &error_message);
} else {
addContent(loaded_content, &error_message);
}
// renvoie le contenu ajoute a l'element
if (content_ptr) {
*content_ptr = loaded_content;
}
}
}
/**
@return le rectangle representant les limites de l'element.
Ce rectangle a pour dimensions la taille de l'element et pour coin
superieur gauche les coordonnees opposees du hotspot.
*/
QRectF ElementScene::borderRect() const {
return(QRectF(-_hotspot, QSizeF(width(), height())));
}
/**
@return un rectangle englobant toutes les parties ainsi que le
"bounding rect" de l'element
*/
QRectF ElementScene::sceneContent() const {
return(itemsBoundingRect().unite(QRectF(-_hotspot, QSizeF(width(), height()))));
return(itemsBoundingRect().unite(borderRect()));
}
/**
@return true si toutes les parties graphiques composant l'element sont
integralement contenues dans le rectangle representant les limites de
l'element.
*/
bool ElementScene::borderContainsEveryParts() const {
return(borderRect().contains(itemsBoundingRect()));
}
/**
@@ -496,6 +622,64 @@ QGIManager &ElementScene::qgiManager() {
return(qgi_manager);
}
/**
@return true si le presse-papier semble contenir un element
*/
bool ElementScene::clipboardMayContainElement() {
QString clipboard_text = QApplication::clipboard() -> text().trimmed();
bool may_be_element = clipboard_text.startsWith("<definition") && clipboard_text.endsWith("</definition>");
return(may_be_element);
}
/**
@param clipboard_content chaine de caractere, provenant vraisemblablement du
presse-papier.
@return true si clipboard_content a ete copie depuis cet element.
*/
bool ElementScene::wasCopiedFromThisElement(const QString &clipboard_content) {
return(clipboard_content == last_copied_);
}
/**
Gere le fait de couper la selection = l'exporter en XML dans le
presse-papier puis la supprimer.
*/
void ElementScene::cut() {
copy();
QList<QGraphicsItem *> cut_content = selectedItems();
clearSelection();
undoStack().push(new CutPartsCommand(this, cut_content));
}
/**
Gere le fait de copier la selection = l'exporter en XML dans le
presse-papier.
*/
void ElementScene::copy() {
// accede au presse-papier
QClipboard *clipboard = QApplication::clipboard();
// genere la description XML de la selection
QString clipboard_content = toXml(false).toString(4);
// met la description XML dans le presse-papier
if (clipboard -> supportsSelection()) {
clipboard -> setText(clipboard_content, QClipboard::Selection);
}
clipboard -> setText(clipboard_content);
// retient le dernier contenu copie
last_copied_ = clipboard_content;
}
/**
Gere le fait de coller le contenu du presse-papier = l'importer dans le
presse-papier a une position donnee.
*/
void ElementScene::paste() {
}
/**
Selectionne tout
*/
@@ -538,7 +722,7 @@ void ElementScene::slot_editSizeHotSpot() {
// cree un dialogue
QDialog dialog_sh(element_editor);
dialog_sh.setModal(true);
dialog_sh.setWindowTitle(tr("\311diter la taille et le point de saisie"));
dialog_sh.setWindowTitle(tr("\311diter la taille et le point de saisie", "window title"));
QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog_sh);
// ajoute un HotspotEditor au dialogue
@@ -578,7 +762,7 @@ void ElementScene::slot_editOrientations() {
QDialog dialog_ori(element_editor);
dialog_ori.setModal(true);
dialog_ori.setMinimumSize(400, 260);
dialog_ori.setWindowTitle(tr("\311diter les orientations"));
dialog_ori.setWindowTitle(tr("\311diter les orientations", "window title"));
QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog_ori);
// ajoute un champ explicatif au dialogue
@@ -624,7 +808,7 @@ void ElementScene::slot_editNames() {
QDialog dialog(element_editor);
dialog.setModal(true);
dialog.setMinimumSize(400, 330);
dialog.setWindowTitle(tr("\311diter les noms"));
dialog.setWindowTitle(tr("\311diter les noms", "window title"));
QVBoxLayout *dialog_layout = new QVBoxLayout(&dialog);
// ajoute un champ explicatif au dialogue
@@ -716,6 +900,30 @@ QList<QGraphicsItem *> ElementScene::zItems(bool include_terminals) const {
return(all_items_list);
}
/**
@return les parties graphiques selectionnees
*/
ElementContent ElementScene::selectedContent() const {
ElementContent content;
foreach(QGraphicsItem *qgi, zItems(true)) {
if (qgi -> isSelected()) content << qgi;
}
return(content);
}
/**
@param to_paste Rectangle englobant les parties a coller
@return le rectangle ou il faudra coller ces parties
*/
void ElementScene::getPasteArea(const QRectF &to_paste) {
// on le dessine sur la scene
paste_area_ -> setRect(to_paste);
addItem(paste_area_);
// on passe la scene en mode "recherche de zone pour copier/coller"
behavior = PasteArea;
}
/**
Supprime les parties de l'element et les objets d'annulations.
Les autres caracteristiques sont conservees.
@@ -729,3 +937,200 @@ void ElementScene::reset() {
qgiManager().release(qgi);
}
}
/**
@param content Contenu ( = parties) d'un element
@return le boundingRect de ces parties, exprime dans les coordonnes de la
scene
*/
QRectF ElementScene::elementContentBoundingRect(const ElementContent &content) {
QRectF bounding_rect;
foreach(QGraphicsItem *qgi, content) {
bounding_rect |= qgi -> sceneBoundingRect();
}
return(bounding_rect);
}
/**
Applique les informations (dimensions, hostpot, orientations, connexions
internes et noms) contenu dans un document XML.
@param xml_document Document XML a analyser
@param error_message pointeur vers une QString ; si error_message est
different de 0, un message d'erreur sera stocke dedans si necessaire
@return true si la lecture et l'application des informations s'est bien
passee, false sinon.
*/
bool ElementScene::applyInformations(const QDomDocument &xml_document, QString *error_message) {
// la racine est supposee etre une definition d'element
QDomElement root = xml_document.documentElement();
if (root.tagName() != "definition" || root.attribute("type") != "element") {
if (error_message) {
*error_message = tr("Ce document XML n'est pas une d\351finition d'\351l\351ment.", "error message");
}
return(false);
}
// dimensions et hotspot : ces attributs doivent etre presents et valides
int w, h, hot_x, hot_y;
if (
!QET::attributeIsAnInteger(root, QString("width"), &w) ||\
!QET::attributeIsAnInteger(root, QString("height"), &h) ||\
!QET::attributeIsAnInteger(root, QString("hotspot_x"), &hot_x) ||\
!QET::attributeIsAnInteger(root, QString("hotspot_y"), &hot_y)
) {
if (error_message) {
*error_message = tr("Les dimensions ou le point de saisie ne sont pas valides.", "error message");
}
return(false);
}
//
setWidth(w);
setHeight(h);
setHotspot(QPoint(hot_x, hot_y));
// orientations
internal_connections = (root.attribute("ic") == "true");
// connexions internes
if (!ori.fromString(root.attribute("orientation"))) {
if (error_message) {
*error_message = tr("Les orientations ne sont pas valides.", "error message");
}
return(false);
}
// extrait les noms de la definition XML
_names.fromXml(root);
return(true);
}
/**
Par le document XML xml_document et retourne le contenu ( = liste de
parties) correspondant.
@param xml_document Document XML a analyser
@param error_message pointeur vers une QString ; si error_message est
different de 0, un message d'erreur sera stocke dedans si necessaire
*/
ElementContent ElementScene::loadContent(const QDomDocument &xml_document, QString *error_message) {
ElementContent loaded_parts;
// la racine est supposee etre une definition d'element
QDomElement root = xml_document.documentElement();
if (root.tagName() != "definition" || root.attribute("type") != "element") {
if (error_message) {
*error_message = tr("Ce document XML n'est pas une d\351finition d'\351l\351ment.", "error message");
}
return(loaded_parts);
}
// chargement de la description graphique de l'element
for (QDomNode node = root.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
QDomElement elmts = node.toElement();
if (elmts.isNull()) continue;
if (elmts.tagName() == "description") {
// = parcours des differentes parties du dessin
int z = 1;
for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
QDomElement qde = n.toElement();
if (qde.isNull()) continue;
CustomElementPart *cep;
if (qde.tagName() == "line") cep = new PartLine (element_editor, 0, 0);
else if (qde.tagName() == "rect") cep = new PartRectangle(element_editor, 0, 0);
else if (qde.tagName() == "ellipse") cep = new PartEllipse (element_editor, 0, 0);
else if (qde.tagName() == "circle") cep = new PartCircle (element_editor, 0, 0);
else if (qde.tagName() == "polygon") cep = new PartPolygon (element_editor, 0, 0);
else if (qde.tagName() == "terminal") cep = new PartTerminal (element_editor, 0, 0);
else if (qde.tagName() == "text") cep = new PartText (element_editor, 0, 0);
else if (qde.tagName() == "input") cep = new PartTextField(element_editor, 0, 0);
else if (qde.tagName() == "arc") cep = new PartArc (element_editor, 0, 0);
else continue;
if (QGraphicsItem *qgi = dynamic_cast<QGraphicsItem *>(cep)) {
qgi -> setZValue(z++);
loaded_parts << qgi;
}
cep -> fromXml(qde);
}
}
}
return(loaded_parts);
}
/**
Ajoute le contenu content a cet element
@param content contenu ( = liste de parties) a charger
@param error_message pointeur vers une QString ; si error_message est
different de 0, un message d'erreur sera stocke dedans si necessaire
@return Le contenu ajoute
*/
ElementContent ElementScene::addContent(const ElementContent &content, QString */*error_message*/) {
foreach(QGraphicsItem *part, content) {
addItem(part);
}
return(content);
}
/**
Ajoute le contenu content a cet element
@param content contenu ( = liste de parties) a charger
@param pos Position du coin superieur gauche du contenu apres avoir ete ajoute
@param error_message pointeur vers une QString ; si error_message est
different de 0, un message d'erreur sera stocke dedans si necessaire
@return Le contenu ajoute
*/
ElementContent ElementScene::addContentAtPos(const ElementContent &content, const QPointF &pos, QString */*error_message*/) {
// calcule le boundingRect du contenu a ajouter
QRectF bounding_rect = elementContentBoundingRect(content);
// en deduit le decalage a appliquer aux parties pour les poser au point demander
QPointF offset = pos - bounding_rect.topLeft();
// ajoute les parties avec le decalage adequat
foreach(QGraphicsItem *part, content) {
part -> setPos(part -> pos() + offset);
addItem(part);
}
return(content);
}
/**
Initialise la zone de collage
*/
void ElementScene::initPasteArea() {
paste_area_ = new QGraphicsRectItem();
paste_area_ -> setZValue(1000000);
QPen paste_area_pen;
paste_area_pen.setStyle(Qt::DashDotLine);
paste_area_pen.setColor(QColor(30, 56, 86, 255));
QBrush paste_area_brush;
paste_area_brush.setStyle(Qt::SolidPattern);
paste_area_brush.setColor(QColor(90, 167, 255, 64));
paste_area_ -> setPen(paste_area_pen);
paste_area_ -> setBrush(paste_area_brush);
}
/**
Arrondit les coordonnees du point passees en parametre de facon a ce que ce
point soit aligne sur la grille.
@param point une reference vers un QPointF. Cet objet sera modifie.
*/
void ElementScene::snapToGrid(QPointF &point) {
point.rx() = qRound(point.x() / x_grid) * x_grid;
point.ry() = qRound(point.y() / y_grid) * y_grid;
}
/**
@param e Evenement souris
@return true s'il faut utiliser le snap-to-grid
Typiquement, cette methode retourne true si l'evenement souris se produit
sans la touche Ctrl enfoncee.
*/
bool ElementScene::mustSnapToGrid(QGraphicsSceneMouseEvent *e) {
return(!(e -> modifiers() & Qt::ControlModifier));
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -22,8 +22,10 @@
#include "nameslistwidget.h"
#include "orientationsetwidget.h"
#include "qgimanager.h"
#include "elementcontent.h"
class QETElementEditor;
class PartLine;
class PartRectangle;
class PartEllipse;
class PartCircle;
class PartPolygon;
@@ -38,7 +40,7 @@ class ElementScene : public QGraphicsScene {
Q_OBJECT
// enum
enum Behavior { Normal, Line, Circle, Ellipse, Polygon, Text, Terminal, Arc, TextField };
enum Behavior { Normal, Line, Rectangle, Circle, Ellipse, Polygon, Text, Terminal, Arc, TextField, PasteArea };
// constructeurs, destructeur
public:
@@ -49,10 +51,6 @@ class ElementScene : public QGraphicsScene {
ElementScene(const ElementScene &);
// attributs
public:
static const int xGrid; ///< Taille horizontale de la grille
static const int yGrid; ///< Taille verticale de la grille
private:
/// longueur de l'element en dizaines de pixels
uint _width;
@@ -72,16 +70,31 @@ class ElementScene : public QGraphicsScene {
QUndoStack undo_stack;
/// Position du premier item selectionne (utilise pour annuler les deplacements)
QPointF fsi_pos;
QPointF moving_press_pos;
bool moving_parts_;
/// Variables relatives a la gestion du dessin des parties sur la scene
Behavior behavior;
PartLine *current_line;
PartRectangle *current_rectangle;
PartEllipse *current_ellipse;
PartCircle *current_circle;
PartPolygon *current_polygon;
PartArc *current_arc;
QETElementEditor *element_editor;
/// Variables relatives a la gestion de la zone de collage sur la scene
QGraphicsRectItem *paste_area_;
QRectF defined_paste_area_;
/// Variables relatives au copier-coller avec decalage
QString last_copied_;
///< Taille horizontale de la grille
int x_grid;
///< Taille verticale de la grille
int y_grid;
// methodes
public:
void setWidth(const uint &);
@@ -96,13 +109,26 @@ class ElementScene : public QGraphicsScene {
void setOrientations(const OrientationSet &);
bool internalConnections();
void setInternalConnections(bool);
virtual const QDomDocument toXml() const;
virtual void fromXml(const QDomDocument &);
virtual int xGrid() const;
virtual int yGrid() const;
virtual void setGrid(int, int);
virtual const QDomDocument toXml(bool = true) const;
virtual QRectF boundingRectFromXml(const QDomDocument &);
virtual void fromXml(const QDomDocument &, const QPointF & = QPointF(), bool = true, ElementContent * = 0);
virtual void reset();
virtual QList<QGraphicsItem *> zItems(bool = false) const;
virtual ElementContent selectedContent() const;
virtual void getPasteArea(const QRectF &);
QRectF borderRect() const;
QRectF sceneContent() const;
bool borderContainsEveryParts() const;
QUndoStack &undoStack();
QGIManager &qgiManager();
static bool clipboardMayContainElement();
bool wasCopiedFromThisElement(const QString &);
void cut();
void copy();
void paste();
protected:
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
@@ -110,10 +136,22 @@ class ElementScene : public QGraphicsScene {
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
virtual void drawBackground(QPainter *, const QRectF &);
virtual void drawForeground(QPainter *, const QRectF &);
virtual void endCurrentBehavior(const QGraphicsSceneMouseEvent *);
private:
QRectF elementContentBoundingRect(const ElementContent &);
bool applyInformations(const QDomDocument &, QString * = 0);
ElementContent loadContent(const QDomDocument &, QString * = 0);
ElementContent addContent(const ElementContent &, QString * = 0);
ElementContent addContentAtPos(const ElementContent &, const QPointF &, QString * = 0);
void initPasteArea();
void snapToGrid(QPointF &);
bool mustSnapToGrid(QGraphicsSceneMouseEvent *);
public slots:
void slot_move();
void slot_addLine();
void slot_addRectangle();
void slot_addCircle();
void slot_addEllipse();
void slot_addPolygon();
@@ -145,6 +183,8 @@ class ElementScene : public QGraphicsScene {
void partsRemoved();
/// Signal emis lorsque la zValue d'une ou plusieurs parties change
void partsZValueChanged();
/// Signal emis lorsque l'utilisateur a fini de choisir une zone pour un copier/coller
void pasteAreaDefined(const QRectF &);
};
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -16,6 +16,8 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementview.h"
#include "qetelementeditor.h"
#include "editorcommands.h"
/**
Constructeur
@param scene ElementScene visualisee par cette ElementView
@@ -23,12 +25,14 @@
*/
ElementView::ElementView(ElementScene *scene, QWidget *parent) :
QGraphicsView(scene, parent),
scene_(scene)
scene_(scene),
offset_paste_count_(0)
{
setInteractive(true);
setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
setResizeAnchor(QGraphicsView::AnchorUnderMouse);
zoomReset();
connect(scene_, SIGNAL(pasteAreaDefined(const QRectF &)), this, SLOT(pasteAreaDefined(const QRectF &)));
}
/// Destructeur
@@ -40,6 +44,24 @@ ElementScene *ElementView::scene() const {
return(scene_);
}
/**
@return le rectangle de l'element visualise par cet ElementView
*/
QRectF ElementView::viewedSceneRect() const {
// recupere la taille du widget viewport
QSize viewport_size = viewport() -> size();
// recupere la transformation viewport -> scene
QTransform view_to_scene = viewportTransform().inverted();
// mappe le coin superieur gauche et le coin inferieur droit de la viewport sur la scene
QPointF scene_left_top = view_to_scene.map(QPointF(0.0, 0.0));
QPointF scene_right_bottom = view_to_scene.map(QPointF(viewport_size.width(), viewport_size.height()));
// en deduit le rectangle visualise par la scene
return(QRectF(scene_left_top, scene_right_bottom));
}
/**
Definit l'ElementScene visualisee par cette ElementView
@param s l'ElementScene visualisee par cette ElementView
@@ -110,6 +132,196 @@ void ElementView::adjustSceneRect() {
scene_ -> update(old_scene_rect.united(new_scene_rect));
}
/**
Gere le fait de couper la selection = l'exporter en XML dans le
presse-papier puis la supprimer.
*/
void ElementView::cut() {
// delegue cette action a la scene
scene_ -> cut();
}
/**
Gere le fait de copier la selection = l'exporter en XML dans le
presse-papier.
*/
void ElementView::copy() {
// delegue cette action a la scene
scene_ -> copy();
offset_paste_count_ = 0;
}
/**
Gere le fait de coller le contenu du presse-papier = l'importer dans
l'element. Cette methode examine le contenu du presse-papier. Si celui-ci
semble avoir ete copie depuis cet element, il est colle a cote de sa zone
d'origine ; s'il est recolle, il sera colle un cran a cote de la zone deja
recollee, etc.
Sinon, cette methode demande a l'utilisateur de definir la zone ou le
collage devra s'effectuer.
@see pasteAreaDefined(const QRectF &)
*/
void ElementView::paste() {
QString clipboard_text = QApplication::clipboard() -> text();
if (clipboard_text.isEmpty()) return;
QDomDocument document_xml;
if (!document_xml.setContent(clipboard_text)) return;
if (scene_ -> wasCopiedFromThisElement(clipboard_text)) {
// copier/coller avec decalage
pasteWithOffset(document_xml);
} else {
// copier/coller par choix de la zone de collage
QRectF pasted_content_bounding_rect = scene_ -> boundingRectFromXml(document_xml);
if (pasted_content_bounding_rect.isEmpty()) return;
to_paste_in_area_ = clipboard_text;
getPasteArea(pasted_content_bounding_rect);
}
}
/**
Colle le contenu du presse-papier en demandant systematiquement a
l'utilisateur de choisir une zone de collage
*/
void ElementView::pasteInArea() {
QString clipboard_text = QApplication::clipboard() -> text();
if (clipboard_text.isEmpty()) return;
QDomDocument document_xml;
if (!document_xml.setContent(clipboard_text)) return;
QRectF pasted_content_bounding_rect = scene_ -> boundingRectFromXml(document_xml);
if (pasted_content_bounding_rect.isEmpty()) return;
// copier/coller par choix de la zone de collage
to_paste_in_area_ = clipboard_text;
getPasteArea(pasted_content_bounding_rect);
}
/**
Gere le fait de coller le contenu du presse-papier = l'importer dans
l'element. Cette methode examine le contenu du presse-papier. Si celui-ci
est exploitable, elle le colle a la position passee en parametre.
@see pasteAreaDefined(const QRectF &)
@param position Point de collage
*/
ElementContent ElementView::paste(const QPointF &position) {
QString clipboard_text = QApplication::clipboard() -> text();
if (clipboard_text.isEmpty()) return(ElementContent());
QDomDocument document_xml;
if (!document_xml.setContent(clipboard_text)) return(ElementContent());
// objet pour recuperer le contenu ajoute au schema par le coller
return(paste(document_xml, position));
}
/**
@param to_paste Rectangle englobant les parties a coller
*/
void ElementView::getPasteArea(const QRectF &to_paste) {
// on copie le rectangle fourni - on s'interesse a ses dimensions, pas a sa position
QRectF used_rect(to_paste);
// on lui attribue pour centre l'origine du repere
if (underMouse()) {
used_rect.moveCenter(mapToScene(mapFromGlobal(QCursor::pos())));
} else {
used_rect.moveCenter(QPointF(0.0, 0.0));
}
scene_ -> getPasteArea(used_rect);
}
/**
Slot appele lorsque la scene annonce avoir defini une zone de collage
@param target_rect Rectangle cible pour le collage
*/
ElementContent ElementView::pasteAreaDefined(const QRectF &target_rect) {
if (to_paste_in_area_.isEmpty()) return(ElementContent());
QDomDocument xml_document;
if (!xml_document.setContent(to_paste_in_area_)) {
to_paste_in_area_.clear();
return(ElementContent());
} else {
return(paste(xml_document, target_rect.topLeft()));
}
}
/**
Colle le document XML xml_document a la position pos
@param xml_document Document XML a coller
@param pos Coin superieur gauche du rectangle cible
*/
ElementContent ElementView::paste(const QDomDocument &xml_document, const QPointF &pos) {
// objet pour recuperer le contenu ajoute au schema par le coller
ElementContent content_pasted;
scene_ -> fromXml(xml_document, pos, false, &content_pasted);
// si quelque chose a effectivement ete ajoute au schema, on cree un objet d'annulation
if (content_pasted.count()) {
scene_ -> clearSelection();
PastePartsCommand *undo_object = new PastePartsCommand(this, content_pasted);
scene_ -> undoStack().push(undo_object);
}
return(content_pasted);
}
/**
Colle le document XML xml_document a la position pos
@param xml_document Document XML a coller
*/
ElementContent ElementView::pasteWithOffset(const QDomDocument &xml_document) {
// objet pour recuperer le contenu ajoute au schema par le coller
ElementContent content_pasted;
// rectangle source
QRectF pasted_content_bounding_rect = scene_ -> boundingRectFromXml(xml_document);
if (pasted_content_bounding_rect.isEmpty()) return(content_pasted);
// copier/coller avec decalage
++ offset_paste_count_;
if (offset_paste_count_ == 1) {
start_top_left_corner_ = pasted_content_bounding_rect.topLeft();
} else {
pasted_content_bounding_rect.moveTopLeft(start_top_left_corner_);
}
// on applique le decalage qui convient
QRectF final_pasted_content_bounding_rect = applyMovement(
pasted_content_bounding_rect,
QETElementEditor::pasteMovement(),
QETElementEditor::pasteOffset()
);
QPointF old_start_top_left_corner_ = start_top_left_corner_;
start_top_left_corner_ = final_pasted_content_bounding_rect.topLeft();
scene_ -> fromXml(xml_document, start_top_left_corner_, false, &content_pasted);
// si quelque chose a effectivement ete ajoute au schema, on cree un objet d'annulation
if (content_pasted.count()) {
scene_ -> clearSelection();
PastePartsCommand *undo_object = new PastePartsCommand(this, content_pasted);
undo_object -> setOffset(offset_paste_count_ - 1, old_start_top_left_corner_, offset_paste_count_, start_top_left_corner_);
scene_ -> undoStack().push(undo_object);
}
return(content_pasted);
}
/**
Gere les clics sur la vue - permet de coller lorsaue l'on enfonce le bouton
du milieu de la souris.
@param e QMouseEvent decrivant l'evenement souris
*/
void ElementView::mousePressEvent(QMouseEvent *e) {
if (e -> buttons() & Qt::MidButton) {
paste(mapToScene(e -> pos()));
}
QGraphicsView::mousePressEvent(e);
}
/**
Gere les actions liees a la rollette de la souris
@param e QWheelEvent decrivant l'evenement rollette
@@ -126,3 +338,107 @@ void ElementView::wheelEvent(QWheelEvent *e) {
QAbstractScrollArea::wheelEvent(e);
}
}
/**
Dessine l'arriere-plan de l'editeur, cad la grille.
@param p Le QPainter a utiliser pour dessiner
@param r Le rectangle de la zone a dessiner
*/
void ElementView::drawBackground(QPainter *p, const QRectF &r) {
p -> save();
// desactive tout antialiasing, sauf pour le texte
p -> setRenderHint(QPainter::Antialiasing, false);
p -> setRenderHint(QPainter::TextAntialiasing, true);
p -> setRenderHint(QPainter::SmoothPixmapTransform, false);
// dessine un fond blanc
p -> setPen(Qt::NoPen);
p -> setBrush(Qt::white);
p -> drawRect(r);
// encadre la zone dessinable de l'element
QRectF drawable_area(-scene_ -> hotspot().x(), -scene_ -> hotspot().y(), scene_ -> width(), scene_ -> height());
p -> setPen(Qt::black);
p -> setBrush(Qt::NoBrush);
p -> drawRect(drawable_area);
// determine le zoom en cours
qreal zoom_factor = matrix().m11();
// choisit la granularite de la grille en fonction du zoom en cours
int drawn_x_grid = scene_ -> xGrid();
int drawn_y_grid = scene_ -> yGrid();
bool draw_grid = true;
bool draw_cross = false;
if (zoom_factor < (4.0/3.0)) {
// pas de grille du tout
draw_grid = false;
} else if (zoom_factor < 4.0) {
// grille a 10 px
drawn_x_grid *= 10;
drawn_y_grid *= 10;
} else if (zoom_factor < 6.0) {
// grille a 2 px (avec croix)
drawn_x_grid *= 2;
drawn_y_grid *= 2;
draw_cross = true;
} else {
// grille a 1 px (avec croix)
draw_cross = true;
}
if (draw_grid) {
// dessine les points de la grille
p -> setPen(Qt::black);
p -> setBrush(Qt::NoBrush);
qreal limite_x = r.x() + r.width();
qreal limite_y = r.y() + r.height();
int g_x = (int)ceil(r.x());
while (g_x % drawn_x_grid) ++ g_x;
int g_y = (int)ceil(r.y());
while (g_y % drawn_y_grid) ++ g_y;
for (int gx = g_x ; gx < limite_x ; gx += drawn_x_grid) {
for (int gy = g_y ; gy < limite_y ; gy += drawn_y_grid) {
if (draw_cross) {
if (!(gx % 10) && !(gy % 10)) {
p -> drawLine(QLineF(gx - 0.25, gy, gx + 0.25, gy));
p -> drawLine(QLineF(gx, gy - 0.25, gx, gy + 0.25));
} else {
p -> drawPoint(gx, gy);
}
} else {
p -> drawPoint(gx, gy);
}
}
}
}
p -> restore();
}
/**
Applique le decalage offset dans le sens movement au rectangle start
@param start rectangle a decaler
@param movement Orientation du decalage a appliquer
@param offset Decalage a appliquer
*/
QRectF ElementView::applyMovement(const QRectF &start, const QET::OrientedMovement &movement, const QPointF &offset) {
// calcule le decalage a appliquer a partir de l'offset indique et du mouvement
QPointF final_offset;
if (movement == QET::ToNorthEast || movement == QET::ToEast || movement == QET::ToSouthEast) {
final_offset.rx() = start.width() + offset.x();
} else if (movement == QET::ToNorthWest || movement == QET::ToWest || movement == QET::ToSouthWest) {
final_offset.rx() = -start.width() - offset.x();
}
if (movement == QET::ToNorthWest || movement == QET::ToNorth || movement == QET::ToNorthEast) {
final_offset.ry() = -start.height() - offset.y();
} else if (movement == QET::ToSouthWest || movement == QET::ToSouth || movement == QET::ToSouthEast) {
final_offset.ry() = start.height() + offset.y();
}
// applique le decalage ainsi calcule
return(start.translated(final_offset));
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -25,6 +25,8 @@
*/
class ElementView : public QGraphicsView {
Q_OBJECT
friend class PastePartsCommand;
// constructeurs, destructeur
public:
ElementView(ElementScene *, QWidget * = 0);
@@ -37,9 +39,16 @@ class ElementView : public QGraphicsView {
public:
ElementScene *scene() const;
void setScene(ElementScene *);
QRectF viewedSceneRect() const;
protected:
bool event(QEvent *);
void mousePressEvent(QMouseEvent *);
void wheelEvent(QWheelEvent *);
virtual void drawBackground(QPainter *, const QRectF &);
private:
QRectF applyMovement(const QRectF &, const QET::OrientedMovement &, const QPointF &);
// slots
public slots:
@@ -48,9 +57,23 @@ class ElementView : public QGraphicsView {
void zoomFit();
void zoomReset();
void adjustSceneRect();
void cut();
void copy();
void paste();
void pasteInArea();
private slots:
void getPasteArea(const QRectF &);
ElementContent pasteAreaDefined(const QRectF &);
ElementContent paste(const QPointF &);
ElementContent paste(const QDomDocument &, const QPointF &);
ElementContent pasteWithOffset(const QDomDocument &);
//attributs
private:
ElementScene *scene_;
QString to_paste_in_area_;
int offset_paste_count_;
QPointF start_top_left_corner_;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -63,9 +63,9 @@ EllipseEditor::~EllipseEditor() {
*/
void EllipseEditor::updateEllipse() {
part -> setProperty("x", x -> text().toDouble());
part -> setProperty("y", x -> text().toDouble());
part -> setProperty("diameter_h", x -> text().toDouble());
part -> setProperty("diameter_v", x -> text().toDouble());
part -> setProperty("y", y -> text().toDouble());
part -> setProperty("diameter_h", h -> text().toDouble());
part -> setProperty("diameter_v", v -> text().toDouble());
}
/// Met a jour l'abscisse du centre de l'ellipse et cree un objet d'annulation

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -17,6 +17,7 @@
*/
#include "lineeditor.h"
#include "partline.h"
#include "qet.h"
/**
Constructeur
@@ -38,16 +39,46 @@ LineEditor::LineEditor(QETElementEditor *editor, PartLine *line, QWidget *parent
x2 -> setValidator(new QDoubleValidator(x2));
y2 -> setValidator(new QDoubleValidator(y2));
QGridLayout *grid = new QGridLayout(this);
grid -> addWidget(new QLabel("x1"), 0, 0);
grid -> addWidget(x1, 0, 1);
grid -> addWidget(new QLabel("y1"), 0, 2);
grid -> addWidget(y1, 0, 3);
grid -> addWidget(new QLabel("x2"), 1, 0);
grid -> addWidget(x2, 1, 1);
grid -> addWidget(new QLabel("y2"), 1, 2);
grid -> addWidget(y2, 1, 3);
end1_type = new QComboBox();
end1_type -> addItem(QIcon(":/ico/endline-none.png"), tr("Normale", "type of the 1st end of a line"), QET::None );
end1_type -> addItem(QIcon(":/ico/endline-simple.png"), tr("Fl\350che simple", "type of the 1st end of a line"), QET::Simple );
end1_type -> addItem(QIcon(":/ico/endline-triangle.png"), tr("Fl\350che triangulaire", "type of the 1st end of a line"), QET::Triangle);
end1_type -> addItem(QIcon(":/ico/endline-circle.png"), tr("Cercle", "type of the 1st end of a line"), QET::Circle );
end1_type -> addItem(QIcon(":/ico/endline-diamond.png"), tr("Carr\351", "type of the 1st end of a line"), QET::Diamond );
end2_type = new QComboBox();
end2_type -> addItem(QIcon(":/ico/endline-none.png"), tr("Normale", "type of the 2nd end of a line"), QET::None );
end2_type -> addItem(QIcon(":/ico/endline-simple.png"), tr("Fl\350che simple", "type of the 2nd end of a line"), QET::Simple );
end2_type -> addItem(QIcon(":/ico/endline-triangle.png"), tr("Fl\350che triangulaire", "type of the 2nd end of a line"), QET::Triangle);
end2_type -> addItem(QIcon(":/ico/endline-circle.png"), tr("Cercle", "type of the 2nd end of a line"), QET::Circle );
end2_type -> addItem(QIcon(":/ico/endline-diamond.png"), tr("Carr\351", "type of the 2nd end of a line"), QET::Diamond );
end1_length = new QLineEdit();
end2_length = new QLineEdit();
end1_length -> setValidator(new QDoubleValidator(end1_length));
end2_length -> setValidator(new QDoubleValidator(end2_length));
QGridLayout *grid = new QGridLayout();
grid -> addWidget(new QLabel("x1"), 0, 0);
grid -> addWidget(x1, 0, 1);
grid -> addWidget(new QLabel("y1"), 0, 2);
grid -> addWidget(y1, 0, 3);
grid -> addWidget(new QLabel("x2"), 1, 0);
grid -> addWidget(x2, 1, 1);
grid -> addWidget(new QLabel("y2"), 1, 2);
grid -> addWidget(y2, 1, 3);
QGridLayout *grid2 = new QGridLayout();
grid2 -> addWidget(new QLabel(tr("Fin 1")), 0, 0);
grid2 -> addWidget(end1_type, 0, 1);
grid2 -> addWidget(end1_length, 0, 2);
grid2 -> addWidget(new QLabel(tr("Fin 2")), 1, 0);
grid2 -> addWidget(end2_type, 1, 1);
grid2 -> addWidget(end2_length, 1, 2);
QVBoxLayout *v_layout = new QVBoxLayout(this);
v_layout -> addLayout(grid);
v_layout -> addLayout(grid2);
updateForm();
}
@@ -59,6 +90,10 @@ LineEditor::~LineEditor() {
Met a jour la ligne a partir des donnees du formulaire
*/
void LineEditor::updateLine() {
part -> setFirstEndType(static_cast<QET::EndType>(end1_type -> currentIndex()));
part -> setFirstEndLength(end1_length -> text().toDouble());
part -> setSecondEndType(static_cast<QET::EndType>(end2_type -> currentIndex()));
part -> setSecondEndLength(end2_length -> text().toDouble());
part -> setLine(
QLineF(
part -> mapFromScene(
@@ -81,6 +116,14 @@ void LineEditor::updateLineY1() { addChangePartCommand(tr("ordonn\351e point 1")
void LineEditor::updateLineX2() { addChangePartCommand(tr("abscisse point 2"), part, "x2", x2 -> text().toDouble()); }
/// Met a jour l'ordonnee du second point de la ligne et cree un objet d'annulation
void LineEditor::updateLineY2() { addChangePartCommand(tr("ordonn\351e point 2"), part, "y2", y2 -> text().toDouble()); }
/// Met a jour le type de la premiere extremite
void LineEditor::updateLineEndType1() { addChangePartCommand(tr("type fin 1"), part, "end1", end1_type -> currentIndex()); }
/// Met a jour la longueur de la premiere extremite
void LineEditor::updateLineEndLength1() { addChangePartCommand(tr("longueur fin 1"), part, "length1", end1_length -> text()); }
/// Met a jour le type de la seconde extremite
void LineEditor::updateLineEndType2() { addChangePartCommand(tr("type fin 2"), part, "end2", end2_type -> currentIndex()); }
/// Met a jour la longueur de la seconde extremite
void LineEditor::updateLineEndLength2() { addChangePartCommand(tr("longueur fin 2"), part, "length2", end2_length -> text()); }
/**
Met a jour le formulaire d'edition
@@ -93,6 +136,10 @@ void LineEditor::updateForm() {
y1 -> setText(QString("%1").arg(p1.y()));
x2 -> setText(QString("%1").arg(p2.x()));
y2 -> setText(QString("%1").arg(p2.y()));
end1_type -> setCurrentIndex(part -> firstEndType());
end1_length -> setText(QString("%1").arg(part -> firstEndLength()));
end2_type -> setCurrentIndex(part -> secondEndType());
end2_length -> setText(QString("%1").arg(part -> secondEndLength()));
activeConnections(true);
}
@@ -106,10 +153,18 @@ void LineEditor::activeConnections(bool active) {
connect(y1, SIGNAL(editingFinished()), this, SLOT(updateLineY1()));
connect(x2, SIGNAL(editingFinished()), this, SLOT(updateLineX2()));
connect(y2, SIGNAL(editingFinished()), this, SLOT(updateLineY2()));
connect(end1_type, SIGNAL(currentIndexChanged(int)), this, SLOT(updateLineEndType1()));
connect(end1_length, SIGNAL(editingFinished()), this, SLOT(updateLineEndLength1()));
connect(end2_type, SIGNAL(currentIndexChanged(int)), this, SLOT(updateLineEndType2()));
connect(end2_length, SIGNAL(editingFinished()), this, SLOT(updateLineEndLength2()));
} else {
connect(x1, SIGNAL(editingFinished()), this, SLOT(updateLineX1()));
connect(y1, SIGNAL(editingFinished()), this, SLOT(updateLineY1()));
connect(x2, SIGNAL(editingFinished()), this, SLOT(updateLineX2()));
connect(y2, SIGNAL(editingFinished()), this, SLOT(updateLineY2()));
disconnect(x1, SIGNAL(editingFinished()), this, SLOT(updateLineX1()));
disconnect(y1, SIGNAL(editingFinished()), this, SLOT(updateLineY1()));
disconnect(x2, SIGNAL(editingFinished()), this, SLOT(updateLineX2()));
disconnect(y2, SIGNAL(editingFinished()), this, SLOT(updateLineY2()));
disconnect(end1_type, SIGNAL(currentIndexChanged(int)), this, SLOT(updateLineEndType1()));
disconnect(end1_length, SIGNAL(editingFinished()), this, SLOT(updateLineEndLength1()));
disconnect(end2_type, SIGNAL(currentIndexChanged(int)), this, SLOT(updateLineEndType2()));
disconnect(end2_length, SIGNAL(editingFinished()), this, SLOT(updateLineEndLength2()));
}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -37,6 +37,8 @@ class LineEditor : public ElementItemEditor {
private:
PartLine *part;
QLineEdit *x1, *y1, *x2, *y2;
QComboBox *end1_type, *end2_type;
QLineEdit *end1_length, *end2_length;
// methodes
public slots:
@@ -45,6 +47,10 @@ class LineEditor : public ElementItemEditor {
void updateLineY1();
void updateLineX2();
void updateLineY2();
void updateLineEndType1();
void updateLineEndLength1();
void updateLineEndType2();
void updateLineEndLength2();
void updateForm();
private:

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -159,6 +159,7 @@ void PartArc::setProperty(const QString &property, const QVariant &value) {
} else if (property == "angle") {
setAngle(value.toInt());
}
update();
}
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -48,7 +48,7 @@ class PartArc : public QGraphicsEllipseItem, public CustomElementGraphicPart {
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
virtual QString name() const { return(QObject::tr("arc")); }
virtual QString name() const { return(QObject::tr("arc", "element part name")); }
virtual const QDomElement toXml(QDomDocument &) const;
virtual void fromXml(const QDomElement &);
virtual QPointF sceneTopLeft() const;

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -125,6 +125,7 @@ void PartCircle::setProperty(const QString &property, const QVariant &value) {
current_rect.setSize(QSizeF(new_diameter, new_diameter));
setRect(current_rect);
}
update();
}
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -46,7 +46,7 @@ class PartCircle : public QGraphicsEllipseItem, public CustomElementGraphicPart
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
virtual QString name() const { return(QObject::tr("cercle")); }
virtual QString name() const { return(QObject::tr("cercle", "element part name")); }
virtual const QDomElement toXml(QDomDocument &) const;
virtual void fromXml(const QDomElement &);
virtual QPointF sceneTopLeft() const;

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -129,6 +129,7 @@ void PartEllipse::setProperty(const QString &property, const QVariant &value) {
current_rect.setHeight(new_height);
setRect(current_rect);
}
update();
}
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -46,7 +46,7 @@ class PartEllipse : public QGraphicsEllipseItem, public CustomElementGraphicPart
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
virtual QString name() const { return(QObject::tr("ellipse")); }
virtual QString name() const { return(QObject::tr("ellipse", "element part name")); }
virtual const QDomElement toXml(QDomDocument &) const;
virtual void fromXml(const QDomElement &);
virtual QPointF sceneTopLeft() const;

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -25,7 +25,14 @@
@param parent Le QGraphicsItem parent de cette ligne
@param scene La scene sur laquelle figure cette ligne
*/
PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsLineItem(parent, scene), CustomElementGraphicPart(editor) {
PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
QGraphicsLineItem(parent, scene),
CustomElementGraphicPart(editor),
first_end(QET::None),
first_length(1.5),
second_end(QET::None),
second_length(1.5)
{
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
setAcceptedMouseButtons(Qt::LeftButton);
informations = new LineEditor(elementEditor(), this);
@@ -38,6 +45,20 @@ PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsSce
PartLine::~PartLine() {
}
/**
@param end_type Type d'extremite
@return Le nombre de "longueurs" requises pour dessiner une extremite de type end_type
*/
uint PartLine::requiredLengthForEndType(const QET::EndType &end_type) {
uint length_count_required = 0;
if (end_type == QET::Circle || end_type == QET::Diamond) {
length_count_required = 2;
} else if (end_type == QET::Simple || end_type == QET::Triangle) {
length_count_required = 1;
}
return(length_count_required);
}
/**
Dessine la ligne
@param painter QPainter a utiliser pour rendre le dessin
@@ -45,14 +66,91 @@ PartLine::~PartLine() {
@param widget Widget sur lequel le rendu est effectue
*/
void PartLine::paint(QPainter *painter, const QStyleOptionGraphicsItem */*q*/, QWidget */*w*/) {
// inutile de dessiner une ligne nulle
if (line().p1() == line().p2()) return;
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
t.setJoinStyle(Qt::MiterJoin);
if (isSelected()) {
t.setColor(Qt::red);
painter -> setPen(t);
}
painter -> setBrush(Qt::NoBrush);
painter -> drawLine(line());
painter -> setPen(t);
QPointF point1(line().p1());
QPointF point2(line().p2());
qreal line_length(line().length());
qreal pen_width = painter -> pen().widthF();
qreal length1 = first_length;
qreal length2 = second_length;
//debugPaint(painter);
// determine s'il faut dessiner les extremites
bool draw_1st_end, draw_2nd_end;
qreal reduced_line_length = line_length - (length1 * requiredLengthForEndType(first_end));
draw_1st_end = first_end && reduced_line_length >= 0;
if (draw_1st_end) {
reduced_line_length -= (length2 * requiredLengthForEndType(second_end));
} else {
reduced_line_length = line_length - (length2 * requiredLengthForEndType(second_end));
}
draw_2nd_end = second_end && reduced_line_length >= 0;
// dessine la premiere extremite
QPointF start_point, stop_point;
if (draw_1st_end) {
QList<QPointF> four_points1(fourEndPoints(point1, point2, length1));
if (first_end == QET::Circle) {
painter -> drawEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
start_point = four_points1[1];
} else if (first_end == QET::Diamond) {
painter -> drawPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3]);
start_point = four_points1[1];
} else if (first_end == QET::Simple) {
painter -> drawPolyline(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
start_point = point1;
} else if (first_end == QET::Triangle) {
painter -> drawPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3]);
start_point = four_points1[0];
}
// ajuste le depart selon l'epaisseur du trait
if (pen_width && (first_end == QET::Simple || first_end == QET::Circle)) {
start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
}
} else {
start_point = point1;
}
// dessine la seconde extremite
if (draw_2nd_end) {
QList<QPointF> four_points2(fourEndPoints(point2, point1, length2));
if (second_end == QET::Circle) {
painter -> drawEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
stop_point = four_points2[1];
} else if (second_end == QET::Diamond) {
painter -> drawPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1]);
stop_point = four_points2[1];
} else if (second_end == QET::Simple) {
painter -> drawPolyline(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
stop_point = point2;
} else if (second_end == QET::Triangle) {
painter -> drawPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
stop_point = four_points2[0];
}
// ajuste l'arrivee selon l'epaisseur du trait
if (pen_width && (second_end == QET::Simple || second_end == QET::Circle)) {
stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
}
} else {
stop_point = point2;
}
painter -> drawLine(start_point, stop_point);
}
/**
@@ -70,6 +168,11 @@ const QDomElement PartLine::toXml(QDomDocument &xml_document) const {
xml_element.setAttribute("y1", QString("%1").arg(p1.y()));
xml_element.setAttribute("x2", QString("%1").arg(p2.x()));
xml_element.setAttribute("y2", QString("%1").arg(p2.y()));
xml_element.setAttribute("end1", QET::endTypeToString(first_end));
xml_element.setAttribute("length1", first_length);
xml_element.setAttribute("end2", QET::endTypeToString(second_end));
xml_element.setAttribute("length2", second_length);
stylesToXml(xml_element);
return(xml_element);
}
@@ -92,6 +195,10 @@ void PartLine::fromXml(const QDomElement &qde) {
)
)
);
first_end = QET::endTypeFromString(qde.attribute("end1"));
first_length = qde.attribute("length1", "1.5").toDouble();
second_end = QET::endTypeFromString(qde.attribute("end2"));
second_length = qde.attribute("length2", "1.5").toDouble();
}
/**
@@ -101,6 +208,8 @@ void PartLine::fromXml(const QDomElement &qde) {
* y1 : ordonnee du second point
* x2 : abscisse du premier point
* y2 : ordonnee du second point
*end1 : type d'embout du premier point
*end2 : type d'embout du second point
@param value Valeur a attribuer a la propriete
*/
void PartLine::setProperty(const QString &property, const QVariant &value) {
@@ -116,8 +225,20 @@ void PartLine::setProperty(const QString &property, const QVariant &value) {
new_p2.setX(value.toDouble());
} else if (property == "y2") {
new_p2.setY(value.toDouble());
} else setline = false;
setLine(QLineF(mapFromScene(new_p1), mapFromScene(new_p2)));
} else {
setline = false;
if (property == "end1") {
setFirstEndType(static_cast<QET::EndType>(value.toUInt()));
} else if (property == "end2") {
setSecondEndType(static_cast<QET::EndType>(value.toUInt()));
} else if (property == "length1") {
setFirstEndLength(value.toDouble());
} else if (property == "length2") {
setSecondEndLength(value.toDouble());
}
}
if (setline) setLine(QLineF(mapFromScene(new_p1), mapFromScene(new_p2)));
update();
}
/**
@@ -142,6 +263,14 @@ QVariant PartLine::property(const QString &property) {
return(sceneP2().x());
} else if (property == "y2") {
return(sceneP2().y());
} else if (property == "end1") {
return(firstEndType());
} else if (property == "end2") {
return(secondEndType());
} else if (property == "length1") {
return(firstEndLength());
} else if (property == "length2") {
return(secondEndLength());
}
return(QVariant());
}
@@ -186,6 +315,24 @@ QPainterPath PartLine::shape() const {
t.lineTo(points.at(2));
t.lineTo(points.at(3));
t.lineTo(points.at(0));
// n'en fait pas plus si la ligne se ramene a un point
if (line().p1() == line().p2()) return(t);
// ajoute un cercle pour l'extremite 1 si besoin
if (first_end) {
QPainterPath t2;
t2.addEllipse(firstEndCircleRect());
t.addPath(t2.subtracted(t));
}
// ajoute un cercle pour l'extremite 2 si besoin
if (second_end) {
QPainterPath t2;
t2.addEllipse(secondEndCircleRect());
t.addPath(t2.subtracted(t));
}
return(t);
}
@@ -233,12 +380,86 @@ QList<QPointF> PartLine::fourShapePoints() const {
return(result);
}
/**
@return le rectangle encadrant l'integralite de la premiere extremite
*/
QRectF PartLine::firstEndCircleRect() const {
QList<QPointF> interesting_points = fourEndPoints(
line().p1(),
line().p2(),
first_length
);
QRectF end_rect(
interesting_points[0] - QPointF(first_length, first_length),
QSizeF(2.0 * first_length, 2.0 * first_length)
);
return(end_rect);
}
/**
@return le rectangle encadrant l'integralite de la seconde extremite
*/
QRectF PartLine::secondEndCircleRect() const {
QList<QPointF> interesting_points = fourEndPoints(
line().p2(),
line().p1(),
second_length
);
QRectF end_rect(
interesting_points[0] - QPointF(second_length, second_length),
QSizeF(2.0 * second_length, 2.0 * second_length)
);
return(end_rect);
}
/**
Affiche differentes composantes du dessin :
- le boundingRect
- les point speciaux a chaque extremite
- la quadrature du cercle a chaque extremite, meme si celle-ci est d'un
autre type
*/
void PartLine::debugPaint(QPainter *painter) {
painter -> save();
painter -> setPen(Qt::gray);
painter -> drawRect(boundingRect());
painter -> setPen(Qt::green);
painter -> drawRect(firstEndCircleRect());
painter -> drawRect(secondEndCircleRect());
painter -> setPen(Qt::red);
foreach(QPointF pointy, fourEndPoints(line().p1(), line().p2(), first_length)) {
painter -> drawEllipse(pointy, 0.1, 0.1);
}
foreach(QPointF pointy, fourEndPoints(line().p2(), line().p1(), second_length)) {
painter -> drawEllipse(pointy, 0.1, 0.1);
}
painter -> restore();
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartLine::boundingRect() const {
qreal adjust = 1.5;
QRectF r(QGraphicsLineItem::boundingRect());
// cas special : le cercle sort largement du bounding rect originel
if (first_end == QET::Circle) {
r = r.united(firstEndCircleRect());
}
if (second_end == QET::Circle) {
r = r.united(secondEndCircleRect());
}
// la taille du bounding rect est ajustee de 0.2px
qreal adjust = 0.6;
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
}
@@ -251,3 +472,91 @@ QRectF PartLine::boundingRect() const {
bool PartLine::isUseless() const {
return(sceneP1() == sceneP2());
}
/**
@param end_type nouveau type d'embout pour l'extremite 1
*/
void PartLine::setFirstEndType(const QET::EndType &end_type) {
first_end = end_type;
}
/**
@return le type d'embout pour l'extremite 1
*/
QET::EndType PartLine::firstEndType() const {
return(first_end);
}
/**
@param end_type Nouveau type d'embout pour l'extremite 2
*/
void PartLine::setSecondEndType(const QET::EndType &end_type) {
second_end = end_type;
}
/**
@return le type d'embout pour l'extremite 2
*/
QET::EndType PartLine::secondEndType() const {
return(second_end);
}
/**
@return Les quatre points interessants a l'extremite d'une droite
Ces points sont, dans l'ordre :
* O : point sur la ligne, a une distance length de l'extremite
* A : point sur la ligne a une distance 2 x length de l'extremite
* B : point a une distance length de O - O est le projete de B sur la droite
* C : point a une distance length de O - O est le projete de C sur la droite
B et C sont situes de part et d'autre de la ligne
@param end_point Extremite concernee
@param other_point Autre point permettant de definir une ligne
@param length Longueur a utiliser entre l'extremite et le point O
*/
QList<QPointF> PartLine::fourEndPoints(const QPointF &end_point, const QPointF &other_point, const qreal &length) {
// vecteur et longueur de la ligne
QPointF line_vector = end_point - other_point;
qreal line_length = sqrt(pow(line_vector.x(), 2) + pow(line_vector.y(), 2));
// vecteur unitaire et vecteur perpendiculaire
QPointF u(line_vector / line_length * length);
QPointF v(-u.y(), u.x());
// points O, A, B et C
QPointF o(end_point - u);
QPointF a(o - u);
QPointF b(o + v);
QPointF c(o - v);
return(QList<QPointF>() << o << a << b << c);
}
/**
@param length nouvelle longueur de la premiere extremite
la longueur de l'extemite ne peut exceder celle de la ligne
*/
void PartLine::setFirstEndLength(const qreal &length) {
first_length = qMin(qAbs(length), line().length());
}
/**
@return longueur de la premiere extremite
*/
qreal PartLine::firstEndLength() const {
return(first_length);
}
/**
@param length nouvelle longueur de la seconde extremite
la longueur de l'extemite ne peut exceder celle de la ligne
*/
void PartLine::setSecondEndLength(const qreal &length) {
second_length = qMin(qAbs(length), line().length());
}
/**
@return longueur de la seconde extremite
*/
qreal PartLine::secondEndLength() const {
return(second_length);
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -19,10 +19,18 @@
#define PART_LINE_H
#include <QtGui>
#include "customelementgraphicpart.h"
#include "qet.h"
class LineEditor;
/**
Cette classe represente une ligne pouvant etre utilisee pour composer le
dessin d'un element dans l'editeur d'element.
Une ligne est composee de deux points. Elle peut comporter des extremites
speciales definissables grace aux methodes setFirstEndType et
setSecondEndType. La taille des extremites est definissable via les
methodes setFirstEndLength et setSecondEndLength.
A noter que les extremites ne sont pas dessinees si la longueur requise
pour leur dessin n'est pas contenue dans la ligne. S'il n'y a de la place
que pour une seule extremite, c'est la premiere qui est privilegiee.
*/
class PartLine : public QGraphicsLineItem, public CustomElementGraphicPart {
// constructeurs, destructeur
@@ -36,17 +44,22 @@ class PartLine : public QGraphicsLineItem, public CustomElementGraphicPart {
// attributs
private:
LineEditor *informations;
QET::EndType first_end;
qreal first_length;
QET::EndType second_end;
qreal second_length;
// methodes
public:
enum { Type = UserType + 1104 };
/**
permet de caster un QGraphicsItem en PartLine avec qgraphicsitem_cast
@return le type de QGraphicsItem
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
virtual QString name() const { return(QObject::tr("ligne")); }
virtual QString name() const { return(QObject::tr("ligne", "element part name")); }
virtual const QDomElement toXml(QDomDocument &) const;
virtual void fromXml(const QDomElement &);
virtual QPointF sceneP1() const;
@@ -56,11 +69,23 @@ class PartLine : public QGraphicsLineItem, public CustomElementGraphicPart {
virtual void setProperty(const QString &, const QVariant &);
virtual QVariant property(const QString &);
virtual bool isUseless() const;
virtual void setFirstEndType(const QET::EndType &);
virtual QET::EndType firstEndType() const;
virtual void setSecondEndType(const QET::EndType &);
virtual QET::EndType secondEndType() const;
virtual void setFirstEndLength(const qreal &);
virtual qreal firstEndLength() const;
virtual void setSecondEndLength(const qreal &);
virtual qreal secondEndLength() const;
static uint requiredLengthForEndType(const QET::EndType &);
static QList<QPointF> fourEndPoints(const QPointF &, const QPointF &, const qreal &);
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
private:
QList<QPointF> fourShapePoints() const;
QRectF firstEndCircleRect() const;
QRectF secondEndCircleRect() const;
void debugPaint(QPainter *);
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -114,6 +114,7 @@ void PartPolygon::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWi
void PartPolygon::setProperty(const QString &property, const QVariant &value) {
CustomElementGraphicPart::setProperty(property, value);
if (property == "closed") closed = value.toBool();
update();
}
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -58,7 +58,7 @@ class PartPolygon : public QGraphicsPolygonItem, public CustomElementGraphicPart
@return le type de QGraphicsItem
*/
virtual int type() const { return Type; }
virtual QString name() const { return(QObject::tr("polygone")); }
virtual QString name() const { return(QObject::tr("polygone", "element part name")); }
void fromXml(const QDomElement &);
const QDomElement toXml(QDomDocument &) const;
virtual QRectF boundingRect() const;

View File

@@ -0,0 +1,207 @@
/*
Copyright 2006-2009 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 "partrectangle.h"
#include "rectangleeditor.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de ce rectangle
@param scene La scene sur laquelle figure ce rectangle
*/
PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsRectItem(parent, scene), CustomElementGraphicPart(editor) {
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
setAcceptedMouseButtons(Qt::LeftButton);
informations = new RectangleEditor(elementEditor(), this);
informations -> setElementTypeName(name());
style_editor -> appendWidget(informations);
style_editor -> setElementTypeName(name());
}
/// Destructeur
PartRectangle::~PartRectangle() {
}
/**
Dessine le rectangle
@param painter QPainter a utiliser pour rendre le dessin
@param options Options pour affiner le rendu
@param widget Widget sur lequel le rendu est effectue
*/
void PartRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) {
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
if (isSelected()) {
t.setColor(Qt::red);
}
// force le type de jointures pour les rectangles
t.setJoinStyle(Qt::MiterJoin);
// force le dessin avec un trait fin si l'une des dimensions du rectangle est nulle
if (!rect().width() || !rect().height()) {
t.setWidth(0);
}
painter -> setPen(t);
painter -> drawRect(rect());
if (isSelected()) {
painter -> setRenderHint(QPainter::Antialiasing, false);
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
QPointF center = rect().center();
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
}
}
/**
Exporte le rectangle en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant le rectangle
*/
const QDomElement PartRectangle::toXml(QDomDocument &xml_document) const {
QDomElement xml_element = xml_document.createElement("rect");
QPointF top_left(sceneTopLeft());
xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
xml_element.setAttribute("width", QString("%1").arg(rect().width()));
xml_element.setAttribute("height", QString("%1").arg(rect().height()));
stylesToXml(xml_element);
return(xml_element);
}
/**
Importe les proprietes d'une rectangle depuis un element XML
@param qde Element XML a lire
*/
void PartRectangle::fromXml(const QDomElement &qde) {
stylesFromXml(qde);
setRect(
QRectF(
mapFromScene(
qde.attribute("x", "0").toDouble(),
qde.attribute("y", "0").toDouble()
),
QSizeF(
qde.attribute("width", "0").toDouble(),
qde.attribute("height", "0").toDouble()
)
)
);
}
/**
Specifie la valeur d'une propriete donnee du rectangle
@param property propriete a modifier. Valeurs acceptees :
* x : abscisse du coin superieur gauche du rectangle
* y : ordonnee du coin superieur gauche du rectangle
* width : largeur du rectangle
* height : hauteur du rectangle
@param value Valeur a attribuer a la propriete
*/
void PartRectangle::setProperty(const QString &property, const QVariant &value) {
CustomElementGraphicPart::setProperty(property, value);
if (!value.canConvert(QVariant::Double)) return;
if (property == "x") {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.topLeft());
setRect(current_rect.translated(value.toDouble() - current_pos.x(), 0.0));
} else if (property == "y") {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.topLeft());
setRect(current_rect.translated(0.0, value.toDouble() - current_pos.y()));
} else if (property == "width") {
qreal new_width = qAbs(value.toDouble());
QRectF current_rect = rect();
current_rect.setWidth(new_width);
setRect(current_rect);
} else if (property == "height") {
qreal new_height = qAbs(value.toDouble());
QRectF current_rect = rect();
current_rect.setHeight(new_height);
setRect(current_rect);
}
update();
}
/**
Permet d'acceder a la valeur d'une propriete donnee du rectangle
@param property propriete lue. Valeurs acceptees :
* x : abscisse du coin superieur gauche du rectangle
* y : ordonnee du coin superieur gauche du rectangle
* width : largeur du rectangle
* height : hauteur du rectangle
@return La valeur de la propriete property
*/
QVariant PartRectangle::property(const QString &property) {
// appelle la methode property de CustomElementGraphicpart pour les styles
QVariant style_property = CustomElementGraphicPart::property(property);
if (style_property != QVariant()) return(style_property);
if (property == "x") {
return(mapToScene(rect().topLeft()).x());
} else if (property == "y") {
return(mapToScene(rect().topLeft()).y());
} else if (property == "width") {
return(rect().width());
} else if (property == "height") {
return(rect().height());
}
return(QVariant());
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartRectangle::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemSelectedChange) {
informations -> updateForm();
}
}
return(QGraphicsRectItem::itemChange(change, value));
}
/**
@return le coin superieur gauche du rectangle, dans les coordonnees de la
scene.
*/
QPointF PartRectangle::sceneTopLeft() const {
return(mapToScene(rect().topLeft()));
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Un rectangle est pertinent des lors que ses dimensions ne sont pas nulles.
*/
bool PartRectangle::isUseless() const {
return(rect().isNull());
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartRectangle::boundingRect() const {
qreal adjust = 1.5;
QRectF r(QGraphicsRectItem::boundingRect().normalized());
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
}

View File

@@ -0,0 +1,61 @@
/*
Copyright 2006-2009 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 PART_RECTANGLE_H
#define PART_RECTANGLE_H
#include <QtGui>
#include "customelementgraphicpart.h"
class RectangleEditor;
/**
Cette classe represente un rectangle pouvant etre utilise pour composer le
dessin d'un element dans l'editeur d'element.
*/
class PartRectangle : public QGraphicsRectItem, public CustomElementGraphicPart {
// constructeurs, destructeur
public:
PartRectangle(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
virtual ~PartRectangle();
private:
PartRectangle(const PartRectangle &);
// attributs
private:
RectangleEditor *informations;
// methodes
public:
enum { Type = UserType + 1109 };
/**
permet de caster un QGraphicsItem en PartRectangle avec qgraphicsitem_cast
@return le type de QGraphicsItem
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
virtual QString name() const { return(QObject::tr("rectangle", "element part name")); }
virtual const QDomElement toXml(QDomDocument &) const;
virtual void fromXml(const QDomElement &);
virtual QPointF sceneTopLeft() const;
virtual QRectF boundingRect() const;
virtual void setProperty(const QString &, const QVariant &);
virtual QVariant property(const QString &);
virtual bool isUseless() const;
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -39,6 +39,7 @@ PartTerminal::PartTerminal(QETElementEditor *editor, QGraphicsItem *parent, QGra
/// Destructeur
PartTerminal::~PartTerminal() {
if (informations -> parentWidget()) return; // le widget sera supprime par son parent
delete informations;
};

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -48,7 +48,7 @@ class PartTerminal : public CustomElementPart, public QGraphicsItem {
@return le type de QGraphicsItem
*/
virtual int type() const { return Type; }
virtual QString name() const { return(QObject::tr("borne")); }
virtual QString name() const { return(QObject::tr("borne", "element part name")); }
virtual void fromXml(const QDomElement &);
virtual const QDomElement toXml(QDomDocument &) const;
virtual QWidget *elementInformations();

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -33,14 +33,14 @@ PartText::PartText(QETElementEditor *editor, QGraphicsItem *parent, ElementScene
{
setDefaultTextColor(Qt::black);
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
setPlainText(QObject::tr("T"));
setPlainText(QObject::tr("T", "default text when adding a text in the element editor"));
infos = new TextEditor(elementEditor(), this);
infos -> setElementTypeName(name());
}
/// Destructeur
PartText::~PartText() {
if (infos -> parentWidget()) return; // le widget sera supprime par son parent
delete infos;
}
@@ -130,7 +130,7 @@ void PartText::focusOutEvent(QFocusEvent *e) {
if (previous_text != toPlainText()) {
undoStack().push(
new ChangePartCommand(
TextEditor::tr("texte") + " " + name(),
TextEditor::tr("contenu") + " " + name(),
this,
"text",
previous_text,
@@ -139,6 +139,13 @@ void PartText::focusOutEvent(QFocusEvent *e) {
);
previous_text = toPlainText();
}
// deselectionne le texte
QTextCursor qtc = textCursor();
qtc.clearSelection();
setTextCursor(qtc);
setTextInteractionFlags(Qt::NoTextInteraction);
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
}
@@ -176,6 +183,7 @@ void PartText::setProperty(const QString &property, const QVariant &value) {
} else if (property == "text") {
setPlainText(value.toString());
}
update();
}
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -44,7 +44,7 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
@return le type de QGraphicsItem
*/
virtual int type() const { return Type; }
virtual QString name() const { return(QObject::tr("texte")); }
virtual QString name() const { return(QObject::tr("texte", "element part name")); }
void fromXml(const QDomElement &);
const QDomElement toXml(QDomDocument &) const;
QWidget *elementInformations();

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -33,13 +33,14 @@ PartTextField::PartTextField(QETElementEditor *editor, QGraphicsItem *parent, QG
{
setDefaultTextColor(Qt::black);
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
setPlainText(QObject::tr("_"));
setPlainText(QObject::tr("_", "default text when adding a textfield in the element editor"));
infos = new TextFieldEditor(elementEditor(), this);
infos -> setElementTypeName(name());
}
/// Destructeur
PartTextField::~PartTextField() {
if (infos -> parentWidget()) return; // le widget sera supprime par son parent
delete infos;
}
@@ -148,7 +149,7 @@ void PartTextField::focusOutEvent(QFocusEvent *e) {
if (previous_text != toPlainText()) {
undoStack().push(
new ChangePartCommand(
TextFieldEditor::tr("texte") + " " + name(),
TextFieldEditor::tr("contenu") + " " + name(),
this,
"text",
previous_text,
@@ -157,6 +158,13 @@ void PartTextField::focusOutEvent(QFocusEvent *e) {
);
previous_text = toPlainText();
}
// deselectionne le texte
QTextCursor qtc = textCursor();
qtc.clearSelection();
setTextCursor(qtc);
setTextInteractionFlags(Qt::NoTextInteraction);
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
}
@@ -197,6 +205,7 @@ void PartTextField::setProperty(const QString &property, const QVariant &value)
} else if (property == "rotate") {
follow_parent_rotations = value.toBool();
}
update();
}
/**

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -48,7 +48,7 @@ class PartTextField : public QGraphicsTextItem, public CustomElementPart {
@return le type de QGraphicsItem
*/
virtual int type() const { return Type; }
virtual QString name() const { return(QObject::tr("champ de texte")); }
virtual QString name() const { return(QObject::tr("champ de texte", "element part name")); }
void fromXml(const QDomElement &);
const QDomElement toXml(QDomDocument &) const;
QWidget *elementInformations();

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -69,8 +69,8 @@ void PolygonEditor::updatePolygonPoints() {
if (points.count() < 2) {
QMessageBox::warning(
this,
tr("Erreur"),
tr("Le polygone doit comporter au moins deux points.")
tr("Erreur", "message box title"),
tr("Le polygone doit comporter au moins deux points.", "message box content")
);
return;
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -22,6 +22,8 @@
#include "customelementpart.h"
#include "newelementwizard.h"
#include "elementitemeditor.h"
#include "elementdefinition.h"
#include "elementdialog.h"
#include "recentfiles.h"
/**
@@ -31,8 +33,8 @@
QETElementEditor::QETElementEditor(QWidget *parent) :
QMainWindow(parent),
read_only(false),
min_title(tr("QElectroTech - \311diteur d'\351l\351ment")),
_filename(QString())
min_title(tr("QElectroTech - \311diteur d'\351l\351ment", "window title")),
opened_from_file(false)
{
setWindowTitle(min_title);
setWindowIcon(QIcon(":/ico/qet.png"));
@@ -47,6 +49,7 @@ QETElementEditor::QETElementEditor(QWidget *parent) :
// lecture des parametres
readSettings();
slot_updateMenus();
// affichage
show();
@@ -62,12 +65,18 @@ QETElementEditor::~QETElementEditor() {
void QETElementEditor::setupActions() {
new_element = new QAction(QIcon(":/ico/new.png"), tr("&Nouveau"), this);
open = new QAction(QIcon(":/ico/open.png"), tr("&Ouvrir"), this);
open_file = new QAction(QIcon(":/ico/open.png"), tr("&Ouvrir depuis un fichier"), this);
save = new QAction(QIcon(":/ico/save.png"), tr("&Enregistrer"), this);
save_as = new QAction(QIcon(":/ico/saveas.png"), tr("Enregistrer sous"), this);
save_as_file = new QAction(QIcon(":/ico/saveas.png"), tr("Enregistrer dans un fichier"), this);
reload = new QAction(QIcon(":/ico/reload.png"), tr("Recharger"), this);
quit = new QAction(QIcon(":/ico/exit.png"), tr("&Quitter"), this);
selectall = new QAction( tr("Tout s\351lectionner"), this);
deselectall = new QAction( tr("D\351s\351lectionner tout"), this);
cut = new QAction(QIcon(":/ico/cut.png"), tr("Co&uper"), this);
copy = new QAction(QIcon(":/ico/copy.png"), tr("Cop&ier"), this);
paste = new QAction(QIcon(":/ico/paste.png"), tr("C&oller"), this);
paste_in_area = new QAction(QIcon(":/ico/paste.png"), tr("C&oller dans la zone..."), this);
inv_select = new QAction( tr("Inverser la s\351lection"), this);
edit_delete = new QAction(QIcon(":/ico/delete.png"), tr("&Supprimer"), this);
zoom_in = new QAction(QIcon(":/ico/viewmag+.png"), tr("Zoom avant"), this);
@@ -83,6 +92,7 @@ void QETElementEditor::setupActions() {
edit_forward = new QAction(QIcon(":/ico/bring_forward.png"),tr("Amener au premier plan"), this);
move = new QAction(QIcon(":/ico/select.png"), tr("D\351placer un objet"), this);
add_line = new QAction(QIcon(":/ico/line.png"), tr("Ajouter une ligne"), this);
add_rectangle = new QAction(QIcon(":/ico/rectangle.png"), tr("Ajouter un rectangle"), this);
add_ellipse = new QAction(QIcon(":/ico/ellipse.png"), tr("Ajouter une ellipse"), this);
add_circle = new QAction(QIcon(":/ico/circle.png"), tr("Ajouter un cercle"), this);
add_polygon = new QAction(QIcon(":/ico/polygon.png"), tr("Ajouter un polygone"), this);
@@ -91,6 +101,17 @@ void QETElementEditor::setupActions() {
add_terminal = new QAction(QIcon(":/ico/terminal.png"), tr("Ajouter une borne"), this);
add_textfield = new QAction(QIcon(":/ico/textfield.png"), tr("Ajouter un champ de texte"), this);
QString add_status_tip = tr("Maintenez la touche Shift enfonc\351e pour effectuer plusieurs ajouts d'affil\351e");
add_line -> setStatusTip(add_status_tip);
add_rectangle -> setStatusTip(add_status_tip);
add_ellipse -> setStatusTip(add_status_tip);
add_circle -> setStatusTip(add_status_tip);
add_text -> setStatusTip(add_status_tip);
add_arc -> setStatusTip(add_status_tip);
add_terminal -> setStatusTip(add_status_tip);
add_textfield -> setStatusTip(add_status_tip);
add_polygon -> setStatusTip(tr("Utilisez le bouton droit de la souris pour poser le dernier point du polygone"));
undo = ce_scene -> undoStack().createUndoAction(this, tr("Annuler"));
redo = ce_scene -> undoStack().createRedoAction(this, tr("Refaire"));
undo -> setIcon(QIcon(":/ico/undo.png"));
@@ -100,12 +121,18 @@ void QETElementEditor::setupActions() {
new_element -> setShortcut(QKeySequence::New);
open -> setShortcut(QKeySequence::Open);
open_file -> setShortcut(tr("Ctrl+Shift+O"));
save -> setShortcut(QKeySequence::Save);
save_as_file -> setShortcut(tr("Ctrl+Shift+S"));
reload -> setShortcut(Qt::Key_F5);
quit -> setShortcut(QKeySequence(tr("Ctrl+Q")));
selectall -> setShortcut(QKeySequence::SelectAll);
deselectall -> setShortcut(QKeySequence(tr("Ctrl+Shift+A")));
inv_select -> setShortcut(QKeySequence(tr("Ctrl+I")));
cut -> setShortcut(QKeySequence::Cut);
copy -> setShortcut(QKeySequence::Copy);
paste -> setShortcut(QKeySequence::Paste);
paste_in_area -> setShortcut(tr("Ctrl+Shift+V"));
edit_delete -> setShortcut(QKeySequence(tr("Suppr")));
zoom_in -> setShortcut(QKeySequence::ZoomIn);
@@ -124,13 +151,19 @@ void QETElementEditor::setupActions() {
connect(new_element, SIGNAL(triggered()), this, SLOT(slot_new()));
connect(open, SIGNAL(triggered()), this, SLOT(slot_open()));
connect(open_file, SIGNAL(triggered()), this, SLOT(slot_openFile()));
connect(save, SIGNAL(triggered()), this, SLOT(slot_save()));
connect(save_as, SIGNAL(triggered()), this, SLOT(slot_saveAs()));
connect(save_as_file, SIGNAL(triggered()), this, SLOT(slot_saveAsFile()));
connect(reload, SIGNAL(triggered()), this, SLOT(slot_reload()));
connect(quit, SIGNAL(triggered()), this, SLOT(close()));
connect(selectall, SIGNAL(triggered()), ce_scene, SLOT(slot_selectAll()));
connect(deselectall, SIGNAL(triggered()), ce_scene, SLOT(slot_deselectAll()));
connect(inv_select, SIGNAL(triggered()), ce_scene, SLOT(slot_invertSelection()));
connect(cut, SIGNAL(triggered()), ce_view, SLOT(cut()));
connect(copy, SIGNAL(triggered()), ce_view, SLOT(copy()));
connect(paste, SIGNAL(triggered()), ce_view, SLOT(paste()));
connect(paste_in_area, SIGNAL(triggered()), ce_view, SLOT(pasteInArea()));
connect(zoom_in, SIGNAL(triggered()), ce_view, SLOT(zoomIn()));
connect(zoom_out, SIGNAL(triggered()), ce_view, SLOT(zoomOut()));
connect(zoom_fit, SIGNAL(triggered()), ce_view, SLOT(zoomFit()));
@@ -145,6 +178,7 @@ void QETElementEditor::setupActions() {
connect(edit_backward, SIGNAL(triggered()), ce_scene, SLOT(slot_sendBackward()));
connect(move, SIGNAL(triggered()), ce_scene, SLOT(slot_move()));
connect(add_line, SIGNAL(triggered()), ce_scene, SLOT(slot_addLine()));
connect(add_rectangle, SIGNAL(triggered()), ce_scene, SLOT(slot_addRectangle()));
connect(add_ellipse, SIGNAL(triggered()), ce_scene, SLOT(slot_addEllipse()));
connect(add_circle, SIGNAL(triggered()), ce_scene, SLOT(slot_addCircle()));
connect(add_polygon, SIGNAL(triggered()), ce_scene, SLOT(slot_addPolygon()));
@@ -155,6 +189,7 @@ void QETElementEditor::setupActions() {
connect(move, SIGNAL(triggered()), this, SLOT(slot_setRubberBandToView()));
connect(add_line, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
connect(add_rectangle, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
connect(add_ellipse, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
connect(add_circle, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
connect(add_polygon, SIGNAL(triggered()), this, SLOT(slot_setNoDragToView()));
@@ -167,6 +202,7 @@ void QETElementEditor::setupActions() {
move -> setCheckable(true);
add_line -> setCheckable(true);
add_rectangle -> setCheckable(true);
add_ellipse -> setCheckable(true);
add_circle -> setCheckable(true);
add_polygon -> setCheckable(true);
@@ -178,16 +214,17 @@ void QETElementEditor::setupActions() {
parts = new QActionGroup(this);
parts -> addAction(move);
parts -> addAction(add_line);
parts -> addAction(add_rectangle);
parts -> addAction(add_ellipse);
parts -> addAction(add_circle);
parts -> addAction(add_polygon);
parts -> addAction(add_text);
parts -> addAction(add_arc);
parts -> addAction(add_text);
parts -> addAction(add_textfield);
parts -> addAction(add_terminal);
parts -> setExclusive(true);
parts_toolbar = new QToolBar(tr("Parties"), this);
parts_toolbar = new QToolBar(tr("Parties", "toolbar title"), this);
parts_toolbar -> setObjectName("parts");
foreach (QAction *action, parts -> actions()) parts_toolbar -> addAction(action);
move -> setChecked(true);
@@ -199,13 +236,13 @@ void QETElementEditor::setupActions() {
parts_toolbar -> addAction(xml_preview);
*/
main_toolbar = new QToolBar(tr("Outils"), this);
main_toolbar = new QToolBar(tr("Outils", "toolbar title"), this);
main_toolbar -> setObjectName("main_toolbar");
view_toolbar = new QToolBar(tr("Affichage"), this);
view_toolbar = new QToolBar(tr("Affichage", "toolbar title"), this);
view_toolbar -> setObjectName("display");
element_toolbar = new QToolBar(tr("\311l\351ment"), this);
element_toolbar = new QToolBar(tr("\311l\351ment", "toolbar title"), this);
element_toolbar -> setObjectName("element_toolbar");
depth_toolbar = new QToolBar(tr("Profondeur"), this);
depth_toolbar = new QToolBar(tr("Profondeur", "toolbar title"), this);
depth_toolbar -> setObjectName("depth_toolbar");
main_toolbar -> addAction(new_element);
@@ -238,6 +275,7 @@ void QETElementEditor::setupActions() {
connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateInformations()));
connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updateMenus()));
connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slot_updateMenus()));
connect(&(ce_scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(slot_updateMenus()));
connect(&(ce_scene -> undoStack()), SIGNAL(cleanChanged(bool)), this, SLOT(slot_updateTitle()));
connect(&(ce_scene -> undoStack()), SIGNAL(indexChanged(int)), this, SLOT(slot_updatePartsList()));
@@ -261,10 +299,12 @@ void QETElementEditor::setupMenus() {
file_menu -> addAction(new_element);
file_menu -> addAction(open);
file_menu -> addAction(open_file);
file_menu -> addMenu(QETApp::elementsRecentFiles() -> menu());
connect(QETApp::elementsRecentFiles(), SIGNAL(fileOpeningRequested(const QString &)), this, SLOT(openRecentFile(const QString &)));
file_menu -> addAction(save);
file_menu -> addAction(save_as);
file_menu -> addAction(save_as_file);
file_menu -> addSeparator();
file_menu -> addAction(reload);
file_menu -> addSeparator();
@@ -277,6 +317,11 @@ void QETElementEditor::setupMenus() {
edit_menu -> addAction(deselectall);
edit_menu -> addAction(inv_select);
edit_menu -> addSeparator();
edit_menu -> addAction(cut);
edit_menu -> addAction(copy);
edit_menu -> addAction(paste);
edit_menu -> addAction(paste_in_area);
edit_menu -> addSeparator();
edit_menu -> addAction(edit_delete);
edit_menu -> addSeparator();
edit_menu -> addAction(edit_names);
@@ -309,6 +354,13 @@ void QETElementEditor::setupMenus() {
*/
void QETElementEditor::slot_updateMenus() {
bool selected_items = !ce_scene -> selectedItems().isEmpty();
bool clipboard_elmt = ElementScene::clipboardMayContainElement();
deselectall -> setEnabled(selected_items);
cut -> setEnabled(selected_items);
copy -> setEnabled(selected_items);
paste -> setEnabled(clipboard_elmt);
paste_in_area -> setEnabled(clipboard_elmt);
edit_delete -> setEnabled(selected_items);
edit_forward -> setEnabled(selected_items);
edit_raise -> setEnabled(selected_items);
@@ -323,10 +375,10 @@ void QETElementEditor::slot_updateMenus() {
void QETElementEditor::slot_updateTitle() {
QString title = min_title;
title += " - " + ce_scene -> names().name() + " ";
if (_filename != QString()) {
if (!ce_scene -> undoStack().isClean()) title += tr("[Modifi\351]");
if (isReadOnly()) title += tr(" [lecture seule]");
if (!filename_.isEmpty() || !location_.isNull()) {
if (!ce_scene -> undoStack().isClean()) title += tr("[Modifi\351]", "window title tag");
}
if (isReadOnly()) title += tr(" [lecture seule]", "window title tag");
setWindowTitle(title);
}
@@ -344,19 +396,25 @@ void QETElementEditor::setupInterface() {
// widget par defaut dans le QDockWidget
default_informations = new QLabel();
// ScrollArea pour accueillir un widget d'edition (change a la volee)
tools_dock_scroll_area_ = new QScrollArea();
// Pile de widgets pour accueillir les deux widgets precedents
tools_dock_stack_ = new QStackedWidget();
tools_dock_stack_ -> insertWidget(0, default_informations);
tools_dock_stack_ -> insertWidget(1, tools_dock_scroll_area_);
// panel sur le cote pour editer les parties
tools_dock = new QDockWidget(tr("Informations"), this);
tools_dock = new QDockWidget(tr("Informations", "dock title"), this);
tools_dock -> setObjectName("informations");
tools_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
tools_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
tools_dock -> setMinimumWidth(290);
tools_dock -> setMinimumWidth(380);
addDockWidget(Qt::RightDockWidgetArea, tools_dock);
QWidget *info_widget = new QWidget();
info_widget -> setLayout(new QVBoxLayout(info_widget));
tools_dock -> setWidget(info_widget);
tools_dock -> setWidget(tools_dock_stack_);
// panel sur le cote pour les annulations
undo_dock = new QDockWidget(tr("Annulations"), this);
undo_dock = new QDockWidget(tr("Annulations", "dock title"), this);
undo_dock -> setObjectName("undo");
undo_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
undo_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
@@ -374,7 +432,7 @@ void QETElementEditor::setupInterface() {
connect(ce_scene, SIGNAL(partsZValueChanged()), this, SLOT(slot_createPartsList()));
connect(ce_scene, SIGNAL(selectionChanged()), this, SLOT(slot_updatePartsList()));
connect(parts_list, SIGNAL(itemSelectionChanged()), this, SLOT(slot_updateSelectionFromPartsList()));
parts_dock = new QDockWidget(tr("Parties"), this);
parts_dock = new QDockWidget(tr("Parties", "dock title"), this);
parts_dock -> setObjectName("parts_list");
parts_dock -> setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
parts_dock -> setFeatures(QDockWidget::AllDockWidgetFeatures);
@@ -386,7 +444,7 @@ void QETElementEditor::setupInterface() {
slot_createPartsList();
// barre d'etat
statusBar() -> showMessage(tr("\311diteur d'\351l\351ments"));
statusBar() -> showMessage(tr("\311diteur d'\351l\351ments", "status bar message"));
}
/**
@@ -428,31 +486,26 @@ void QETElementEditor::slot_updateInformations() {
}
}
// recupere le layout
QLayout *layout = tools_dock -> widget() -> layout();
// enleve les widgets deja presents
QLayoutItem *qli;
while ((qli = layout -> takeAt(0)) != 0) {
if (QWidget *w = qli -> widget()) {
layout -> removeWidget(w);
w -> setParent(0);
w -> hide();
}
if (QWidget *previous_widget = tools_dock_scroll_area_ -> takeWidget()) {
previous_widget -> setParent(0);
previous_widget -> hide();
}
if (selected_parts.size() == 1) {
// recupere le premier CustomElementPart et en ajoute le widget d'edition
QWidget *edit_widget = selected_parts.first() -> elementInformations();
layout -> addWidget(edit_widget);
edit_widget -> show();
tools_dock_scroll_area_ -> setWidget(edit_widget);
tools_dock_stack_ -> setCurrentIndex(1);
} else {
default_informations -> setText(
selected_parts.size() ?
QString("%1").arg(selected_parts.size()) + tr(" parties s\351lectionn\351es.") :
tr("Aucune partie s\351lectionn\351e.")
tr(
"%n partie(s) s\351lectionn\351e(s).",
"",
selected_parts.size()
)
);
layout -> addWidget(default_informations);
default_informations -> show();
default_informations -> setAlignment(Qt::AlignHCenter | Qt::AlignTop);
tools_dock_stack_ -> setCurrentIndex(0);
}
}
@@ -468,6 +521,33 @@ void QETElementEditor::xmlPreview() {
);
}
/**
Verifie si l'ensemble des parties graphiques consituant l'element en cours
d'edition est bien contenu dans le rectangle representant les limites de
l'element. Si ce n'est pas le cas, l'utilisateur en est informe.
@return true si la situation est ok, false sinon
*/
bool QETElementEditor::checkElementSize() {
if (ce_scene -> borderContainsEveryParts()) {
return(true);
} else {
QMessageBox::warning(
this,
tr("Dimensions de l'\351l\351ment", "messagebox title"),
tr(
"Attention : certaines parties graphiques (textes, cercles, "
"lignes...) semblent d\351border du cadre de l'\351l\351ment. Cela"
" risque de g\351n\351rer des bugs graphiques lors de leur "
"manipulation sur un sch\351ma. Vous pouvez corriger cela soit "
"en d\351pla\347ant ces parties, soit en vous rendant dans "
"\311dition > \311diter la taille et le point de saisie."
, "messagebox content"
)
);
return(false);
}
}
/**
Charge un fichier
@param filepath Chemin du fichier a charger
@@ -480,7 +560,7 @@ void QETElementEditor::fromFile(const QString &filepath) {
QFileInfo infos_file(filepath);
if (!infos_file.exists() || !infos_file.isFile()) {
state = false;
error_message = tr("Le fichier ") + filepath + tr(" n'existe pas.");
error_message = QString(tr("Le fichier %1 n'existe pas.", "message box content")).arg(filepath);
}
// le fichier doit etre lisible
@@ -488,7 +568,7 @@ void QETElementEditor::fromFile(const QString &filepath) {
if (state) {
if (!file.open(QIODevice::ReadOnly)) {
state = false;
error_message = tr("Impossible d'ouvrir le fichier ") + filepath + ".";
error_message = QString(tr("Impossible d'ouvrir le fichier %1.", "message box content")).arg(filepath);
}
}
@@ -497,13 +577,13 @@ void QETElementEditor::fromFile(const QString &filepath) {
if (state) {
if (!document_xml.setContent(&file)) {
state = false;
error_message = tr("Ce fichier n'est pas un document XML valide");
error_message = tr("Ce fichier n'est pas un document XML valide", "message box content");
}
file.close();
}
if (!state) {
QMessageBox::critical(this, tr("Erreur"), error_message);
QMessageBox::critical(this, tr("Erreur", "toolbar title"), error_message);
return;
}
@@ -515,8 +595,8 @@ void QETElementEditor::fromFile(const QString &filepath) {
if (!infos_file.isWritable()) {
QMessageBox::warning(
this,
tr("\311dition en lecture seule"),
tr("Vous n'avez pas les privil\350ges n\351cessaires pour modifier cet \351lement. Il sera donc ouvert en lecture seule.")
tr("\311dition en lecture seule", "message box title"),
tr("Vous n'avez pas les privil\350ges n\351cessaires pour modifier cet \351lement. Il sera donc ouvert en lecture seule.", "message box content")
);
setReadOnly(true);
}
@@ -527,7 +607,6 @@ void QETElementEditor::fromFile(const QString &filepath) {
slot_updateMenus();
}
/**
Enregistre l'element vers un fichier
@param fn Chemin du fichier a enregistrer
@@ -536,7 +615,7 @@ void QETElementEditor::fromFile(const QString &filepath) {
bool QETElementEditor::toFile(const QString &fn) {
QFile file(fn);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::warning(this, tr("Erreur"), tr("Impossible d'ecrire dans ce fichier"));
QMessageBox::warning(this, tr("Erreur", "message box title"), tr("Impossible d'\351crire dans ce fichier", "message box content"));
return(false);
}
QTextStream out(&file);
@@ -546,6 +625,45 @@ bool QETElementEditor::toFile(const QString &fn) {
return(true);
}
/**
Enregistre l'element vers un emplacement
@param location Emplacement de l'element a enregistrer
@return true en cas de reussite, false sinon
*/
bool QETElementEditor::toLocation(const ElementsLocation &location) {
ElementsCollectionItem *item = QETApp::collectionItem(location);
ElementDefinition *element;
if (item) {
// l'element existe deja
element = qobject_cast<ElementDefinition *>(item);
} else {
// l'element n'existe pas encore, on demande sa creation
element = QETApp::createElement(location);
}
if (!element) {
QMessageBox::critical(
this,
tr("Erreur", "message box title"),
tr("Impossible d'atteindre l'\351l\351ment", "message box content")
);
return(false);
}
// enregistre l'element
element -> setXml(ce_scene -> toXml().documentElement());
if (!element -> write()) {
QMessageBox::critical(
this,
tr("Erreur", "message box title"),
tr("Impossible d'enregistrer l'\351l\351ment", "message box content")
);
return(false);
}
return(true);
}
/**
specifie si l'editeur d'element doit etre en mode lecture seule
@param ro true pour activer le mode lecture seule, false pour le desactiver
@@ -559,6 +677,9 @@ void QETElementEditor::setReadOnly(bool ro) {
ce_view -> setInteractive(!ro);
// active / desactive l'edition de la taille, du hotspot, des noms et des orientations
cut -> setEnabled(!ro);
copy -> setEnabled(!ro);
paste -> setEnabled(!ro);
selectall -> setEnabled(!ro);
deselectall -> setEnabled(!ro);
inv_select -> setEnabled(!ro);
@@ -587,15 +708,33 @@ void QETElementEditor::slot_new() {
}
/**
Demande un fichier a l'utilisateur et ouvre ce fichier
Ouvre un element
*/
void QETElementEditor::slot_open() {
// demande le chemin virtuel de l'element a ouvrir a l'utilisateur
ElementsLocation location = ElementDialog::getOpenElementLocation();
if (location.isNull()) return;
QETElementEditor *cee = new QETElementEditor();
cee -> fromLocation(location);
cee -> show();
}
/**
Ouvre un fichier
Demande un fichier a l'utilisateur et ouvre ce fichier
*/
void QETElementEditor::slot_openFile() {
// demande un nom de fichier a ouvrir a l'utilisateur
QString user_filename = QFileDialog::getOpenFileName(
this,
tr("Ouvrir un fichier"),
_filename.isEmpty() ? QETApp::customElementsDir() : QDir(_filename).absolutePath(),
tr("\311l\351ments QElectroTech (*.elmt);;Fichiers XML (*.xml);;Tous les fichiers (*)")
tr("Ouvrir un fichier", "dialog title"),
filename_.isEmpty() ? QETApp::customElementsDir() : QDir(filename_).absolutePath(),
tr(
"\311l\351ments QElectroTech (*.elmt);;"
"Fichiers XML (*.xml);;"
"Tous les fichiers (*)",
"filetypes allowed when opening an element file"
)
);
openElement(user_filename);
}
@@ -628,16 +767,13 @@ void QETElementEditor::openElement(const QString &filepath) {
Recharge l'element edite
*/
void QETElementEditor::slot_reload() {
// impossible de recharger un element non enregistre
if (_filename.isEmpty()) return;
// s'il ya des modifications, on demande a l'utilisateur s'il est certain
// de vouloir recharger
if (!ce_scene -> undoStack().isClean()) {
QMessageBox::StandardButton answer = QMessageBox::question(
this,
tr("Recharger l'\351l\351ment"),
tr("Vous avez efffectu\351 des modifications sur cet \351l\351ment. Si vous le rechargez, ces modifications seront perdues. Voulez-vous vraiment recharger l'\351l\351ment ?"),
tr("Recharger l'\351l\351ment", "dialog title"),
tr("Vous avez efffectu\351 des modifications sur cet \351l\351ment. Si vous le rechargez, ces modifications seront perdues. Voulez-vous vraiment recharger l'\351l\351ment ?", "dialog content"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
QMessageBox::Cancel
);
@@ -645,8 +781,19 @@ void QETElementEditor::slot_reload() {
}
// recharge l'element
ce_scene -> reset();
fromFile(_filename);
if (opened_from_file) {
// l'element a ete ouvert a partir d'un chemin de fichier
ce_scene -> reset();
fromFile(filename_);
} else {
// l'element a ete ouvert a partir d'un emplacement (ElementsLocation)
// il peut s'agir aussi bien d'un fichier que d'un element XML
if (ElementsCollectionItem *item = QETApp::collectionItem(location_)) {
item -> reload();
ce_scene -> reset();
fromLocation(location_);
}
}
}
/**
@@ -656,24 +803,57 @@ void QETElementEditor::slot_reload() {
@see slot_saveAs()
*/
bool QETElementEditor::slot_save() {
// verification avant d'enregistrer le fichier
checkElementSize();
// si on ne connait pas le nom du fichier en cours, enregistrer revient a enregistrer sous
if (_filename.isEmpty()) return(slot_saveAs());
// sinon on enregistre dans le nom de fichier connu
bool result_save = toFile(_filename);
if (result_save) ce_scene -> undoStack().setClean();
if (opened_from_file) {
if (filename_.isEmpty()) return(slot_saveAsFile());
// sinon on enregistre dans le nom de fichier connu
bool result_save = toFile(filename_);
if (result_save) ce_scene -> undoStack().setClean();
return(result_save);
} else {
if (location_.isNull()) return(slot_saveAs());
// sinon on enregistre a l'emplacement connu
bool result_save = toLocation(location_);
if (result_save) ce_scene -> undoStack().setClean();
return(result_save);
}
}
/**
Demande une localisation a l'utilisateur et enregistre l'element
*/
bool QETElementEditor::slot_saveAs() {
// demande une localisation a l'utilisateur
ElementsLocation location = ElementDialog::getSaveElementLocation();
if (location.isNull()) return(false);
// tente l'enregistrement
bool result_save = toLocation(location);
if (result_save) {
setLocation(location);
ce_scene -> undoStack().setClean();
}
// retourne un booleen representatif de la reussite de l'enregistrement
return(result_save);
}
/**
Demande un nom de fichier a l'utilisateur et enregistre l'element
*/
bool QETElementEditor::slot_saveAs() {
bool QETElementEditor::slot_saveAsFile() {
// demande un nom de fichier a l'utilisateur pour enregistrer l'element
QString fn = QFileDialog::getSaveFileName(
this,
tr("Enregistrer sous"),
_filename.isEmpty() ? QETApp::customElementsDir() : QDir(_filename).absolutePath(),
tr("\311l\351ments QElectroTech (*.elmt)")
tr("Enregistrer sous", "dialog title"),
filename_.isEmpty() ? QETApp::customElementsDir() : QDir(filename_).absolutePath(),
tr(
"\311l\351ments QElectroTech (*.elmt)",
"filetypes allowed when saving an element file"
)
);
// si aucun nom n'est entre, renvoie faux.
if (fn.isEmpty()) return(false);
@@ -702,9 +882,14 @@ bool QETElementEditor::canClose() {
// demande d'abord a l'utilisateur s'il veut enregistrer l'element en cours
QMessageBox::StandardButton answer = QMessageBox::question(
this,
tr("Enregistrer l'\351l\351ment en cours ?"),
tr("Voulez-vous enregistrer l'\351l\351ment ") + ce_scene -> names().name() + tr(" ?"),
QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
tr("Enregistrer l'\351l\351ment en cours ?", "dialog title"),
QString(
tr(
"Voulez-vous enregistrer l'\351l\351ment %1 ?",
"dialog content - %1 is an element name"
)
).arg(ce_scene -> names().name()),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
QMessageBox::Cancel
);
bool result;
@@ -787,6 +972,7 @@ void QETElementEditor::slot_updateSelectionFromPartsList() {
parts_list -> blockSignals(false);
ce_scene -> blockSignals(false);
slot_updateInformations();
slot_updateMenus();
}
/// Lit les parametres de l'editeur d'element
@@ -808,3 +994,70 @@ void QETElementEditor::writeSettings() {
settings.setValue("elementeditor/geometry", saveGeometry());
settings.setValue("elementeditor/state", saveState());
}
/**
@return les decalages horizontaux et verticaux (sous la forme d'un point) a
utiliser lors d'un copier/coller avec decalage.
*/
QPointF QETElementEditor::pasteOffset() {
QPointF paste_offset(5.0, 0.0);
return(paste_offset);
}
/**
@return Le type de mouvement a effectuer lors d'un copier/coller avec
decalage.
*/
QET::OrientedMovement QETElementEditor::pasteMovement() {
return(QET::ToEast);
}
/**
@param location Emplacement de l'element a editer
*/
void QETElementEditor::fromLocation(const ElementsLocation &location) {
// l'element doit exister
ElementsCollectionItem *item = QETApp::collectionItem(location);
ElementDefinition *element = 0;
if (!item) {
QMessageBox::critical(
this,
tr("\311l\351ment inexistant.", "message box title"),
tr("L'\351l\351ment n'existe pas.", "message box content")
);
return;
}
if (!item -> isElement() || !(element = qobject_cast<ElementDefinition *>(item)) || element -> isNull()) {
QMessageBox::critical(
this,
tr("\311l\351ment inexistant.", "message box title"),
tr("Le chemin virtuel choisi ne correspond pas \340 un \351l\351ment.", "message box content")
);
return;
}
// le fichier doit etre un document XML
QDomDocument document_xml;
QDomNode node = document_xml.importNode(element -> xml(), true);
document_xml.appendChild(node);
// chargement de l'element
ce_scene -> fromXml(document_xml);
slot_createPartsList();
// gestion de la lecture seule
if (!element -> isWritable()) {
QMessageBox::warning(
this,
tr("\311dition en lecture seule", "message box title"),
tr("Vous n'avez pas les privil\350ges n\351cessaires pour modifier cet \351lement. Il sera donc ouvert en lecture seule.", "message box content")
);
setReadOnly(true);
}
// memorise le fichier
setLocation(location);
slot_updateMenus();
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -18,8 +18,10 @@
#ifndef CUSTOM_ELEMENT_EDITOR_H
#define CUSTOM_ELEMENT_EDITOR_H
#include <QtGui>
#include "qet.h"
#include "elementscene.h"
#include "orientationset.h"
#include "elementslocation.h"
class ElementView;
/**
Cette classe represente un editeur d'element. Elle permet a l'utilisateur
@@ -48,6 +50,12 @@ class QETElementEditor : public QMainWindow {
ElementScene *ce_scene;
/// container pour les widgets d'edition des parties
QDockWidget *tools_dock;
/// Pile de widgets pour tools_dock
QStackedWidget *tools_dock_stack_;
/// label affiche lors de la selection de plusieurs elements
QLabel *default_informations;
/// ScrollArea pour le DockWidget affichant des infos sur la partie selectionnee
QScrollArea *tools_dock_scroll_area_;
/// container pour la liste des annulations
QDockWidget *undo_dock;
/// Container pour la liste des parties
@@ -55,9 +63,10 @@ class QETElementEditor : public QMainWindow {
/// Liste des parties
QListWidget *parts_list;
/// actions du menu fichier
QAction *new_element, *open, *save, *save_as, *reload, *quit;
QAction *new_element, *open, *open_file, *save, *save_as, *save_as_file, *reload, *quit;
/// actions du menu edition
QAction *selectall, *deselectall, *inv_select;
QAction *cut, *copy, *paste, *paste_in_area;
QAction *undo, *redo;
QAction *zoom_in, *zoom_out, *zoom_fit, *zoom_reset;
QAction *edit_delete, *edit_size_hs, *edit_names, *edit_ori;
@@ -66,14 +75,16 @@ class QETElementEditor : public QMainWindow {
QToolBar *parts_toolbar, *main_toolbar, *view_toolbar, *depth_toolbar, *element_toolbar;
/// actions de la barre d'outils
QActionGroup *parts;
QAction *move, *add_line, *add_circle, *add_ellipse, *add_polygon, *add_text;
QAction *move, *add_line, *add_circle, *add_rectangle, *add_ellipse, *add_polygon, *add_text;
QAction *add_arc, *add_terminal, *add_textfield;
/// label affiche lors de la selection de plusieurs elements
QLabel *default_informations;
/// titre minimal
QString min_title;
/// Nom de fichier
QString _filename;
/// Nom de fichier de l'element edite
QString filename_;
/// Emplacement de l'element edite
ElementsLocation location_;
/// booleen indiquant si l'element en cours d'edition provient d'un fichier ou d'un emplacement
bool opened_from_file;
// methodes
public:
@@ -84,15 +95,21 @@ class QETElementEditor : public QMainWindow {
void setNames(const NamesList &);
void setOrientations(const OrientationSet &orientation_set);
OrientationSet orientations() const;
void setLocation(const ElementsLocation &);
ElementsLocation location() const;
void setFileName(const QString &);
QString fileName() const;
void setReadOnly(bool);
bool isReadOnly() const;
void fromFile(const QString &);
void fromLocation(const ElementsLocation &);
bool toFile(const QString &);
bool toLocation(const ElementsLocation &);
ElementScene *elementScene() const;
void readSettings();
void writeSettings();
static QPointF pasteOffset();
static QET::OrientedMovement pasteMovement();
protected:
void closeEvent(QCloseEvent *);
@@ -106,11 +123,13 @@ class QETElementEditor : public QMainWindow {
public slots:
void slot_new();
void slot_open();
void slot_openFile();
void openRecentFile(const QString &);
void openElement(const QString &);
void slot_reload();
bool slot_save();
bool slot_saveAs();
bool slot_saveAsFile();
void slot_setRubberBandToView();
void slot_setNoDragToView();
void slot_setNormalMode();
@@ -121,6 +140,7 @@ class QETElementEditor : public QMainWindow {
void slot_updatePartsList();
void slot_updateSelectionFromPartsList();
void xmlPreview();
bool checkElementSize();
};
/**
@@ -179,18 +199,35 @@ inline OrientationSet QETElementEditor::orientations() const {
}
/**
@param fn Le nouveau nom de fichier de l'element edite
@param el Le nouvel emplacement de l'element edite
*/
inline void QETElementEditor::setFileName(const QString &fn) {
_filename = fn;
inline void QETElementEditor::setLocation(const ElementsLocation &el) {
location_ = el;
opened_from_file = false;
slot_updateTitle();
}
/**
@return le nomde fichier de l'element edite
@return l'emplacement de l'element edite
*/
inline ElementsLocation QETElementEditor::location() const {
return(location_);
}
/**
@param fn Le nouveau nom de fichier de l'element edite
*/
inline void QETElementEditor::setFileName(const QString &fn) {
filename_ = fn;
opened_from_file = true;
slot_updateTitle();
}
/**
@return le nom de fichier de l'element edite
*/
inline QString QETElementEditor::fileName() const {
return(_filename);
return(filename_);
}
/**

View File

@@ -0,0 +1,108 @@
/*
Copyright 2006-2009 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 "rectangleeditor.h"
#include "partrectangle.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param rect Le rectangle a editer
@param parent le Widget parent
*/
RectangleEditor::RectangleEditor(QETElementEditor *editor, PartRectangle *rect, QWidget *parent) : ElementItemEditor(editor, parent) {
part = rect;
x = new QLineEdit();
y = new QLineEdit();
w = new QLineEdit();
h = new QLineEdit();
x -> setValidator(new QDoubleValidator(x));
y -> setValidator(new QDoubleValidator(y));
w -> setValidator(new QDoubleValidator(w));
h -> setValidator(new QDoubleValidator(h));
QGridLayout *grid = new QGridLayout(this);
grid -> addWidget(new QLabel(tr("Coin sup\351rieur gauche\240: ")), 0, 0);
grid -> addWidget(new QLabel("x"), 1, 0);
grid -> addWidget(x, 1, 1);
grid -> addWidget(new QLabel("y"), 1, 2);
grid -> addWidget(y, 1, 3);
grid -> addWidget(new QLabel(tr("Dimensions\240: ")), 2, 0);
grid -> addWidget(new QLabel(tr("Largeur\240:")), 3, 0);
grid -> addWidget(w, 3, 1);
grid -> addWidget(new QLabel(tr("Hauteur\240:")), 4, 0);
grid -> addWidget(h, 4, 1);
activeConnections(true);
updateForm();
}
/// Destructeur
RectangleEditor::~RectangleEditor() {
}
/**
Met a jour le rectangle a partir des donnees du formulaire
*/
void RectangleEditor::updateRectangle() {
part -> setProperty("x", x -> text().toDouble());
part -> setProperty("y", y -> text().toDouble());
part -> setProperty("width", w -> text().toDouble());
part -> setProperty("height", h -> text().toDouble());
}
/// Met a jour l'abscisse du coin superieur gauche du rectangle et cree un objet d'annulation
void RectangleEditor::updateRectangleX() { addChangePartCommand(tr("abscisse"), part, "x", x -> text().toDouble()); }
/// Met a jour l'ordonnee du coin superieur gauche du rectangle et cree un objet d'annulation
void RectangleEditor::updateRectangleY() { addChangePartCommand(tr("ordonn\351e"), part, "y", y -> text().toDouble()); }
/// Met a jour la largeur du rectangle et cree un objet d'annulation
void RectangleEditor::updateRectangleW() { addChangePartCommand(tr("largeur"), part, "width", w -> text().toDouble()); }
/// Met a jour la hauteur du rectangle et cree un objet d'annulation
void RectangleEditor::updateRectangleH() { addChangePartCommand(tr("hauteur"), part, "height", h -> text().toDouble()); }
/**
Met a jour le formulaire d'edition
*/
void RectangleEditor::updateForm() {
activeConnections(false);
x -> setText(part -> property("x").toString());
y -> setText(part -> property("y").toString());
w -> setText(part -> property("width").toString());
h -> setText(part -> property("height").toString());
activeConnections(true);
}
/**
Active ou desactive les connexionx signaux/slots entre les widgets internes.
@param active true pour activer les connexions, false pour les desactiver
*/
void RectangleEditor::activeConnections(bool active) {
if (active) {
connect(x, SIGNAL(editingFinished()), this, SLOT(updateRectangleX()));
connect(y, SIGNAL(editingFinished()), this, SLOT(updateRectangleY()));
connect(w, SIGNAL(editingFinished()), this, SLOT(updateRectangleW()));
connect(h, SIGNAL(editingFinished()), this, SLOT(updateRectangleH()));
} else {
disconnect(x, SIGNAL(editingFinished()), this, SLOT(updateRectangleX()));
disconnect(y, SIGNAL(editingFinished()), this, SLOT(updateRectangleY()));
disconnect(w, SIGNAL(editingFinished()), this, SLOT(updateRectangleW()));
disconnect(h, SIGNAL(editingFinished()), this, SLOT(updateRectangleH()));
}
}

View File

@@ -0,0 +1,53 @@
/*
Copyright 2006-2009 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 RECTANGLE_EDITOR_H
#define RECTANGLE_EDITOR_H
#include <QtGui>
#include "elementitemeditor.h"
class PartRectangle;
/**
Cette classe represente le widget d'edition d'un rectangle dans l'editeur
d'element.
*/
class RectangleEditor : public ElementItemEditor {
Q_OBJECT
//constructeurs, destructeur
public:
RectangleEditor(QETElementEditor *, PartRectangle *, QWidget * = 0);
~RectangleEditor();
private:
RectangleEditor(const RectangleEditor &);
// attributs
private:
PartRectangle *part;
QLineEdit *x, *y, *w, *h;
// methodes
public slots:
void updateRectangle();
void updateRectangleX();
void updateRectangleY();
void updateRectangleW();
void updateRectangleH();
void updateForm();
private:
void activeConnections(bool);
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -27,26 +27,26 @@
StyleEditor::StyleEditor(QETElementEditor *editor, CustomElementGraphicPart *p, QWidget *parent) : ElementItemEditor(editor, parent), part(p) {
// couleur
color = new QButtonGroup(this);
color -> addButton(black_color = new QRadioButton(tr("Noir")), CustomElementGraphicPart::BlackColor);
color -> addButton(white_color = new QRadioButton(tr("Blanc")), CustomElementGraphicPart::WhiteColor);
color -> addButton(black_color = new QRadioButton(tr("Noir", "element part color")), CustomElementGraphicPart::BlackColor);
color -> addButton(white_color = new QRadioButton(tr("Blanc", "element part color")), CustomElementGraphicPart::WhiteColor);
// style
style = new QButtonGroup(this);
style -> addButton(normal_style = new QRadioButton(tr("Normal")), CustomElementGraphicPart::NormalStyle);
style -> addButton(dashed_style = new QRadioButton(tr("Pointill\351")), CustomElementGraphicPart::DashedStyle);
style -> addButton(normal_style = new QRadioButton(tr("Normal", "element part line style")), CustomElementGraphicPart::NormalStyle);
style -> addButton(dashed_style = new QRadioButton(tr("Pointill\351", "element part line style")), CustomElementGraphicPart::DashedStyle);
style -> button(part -> lineStyle()) -> setChecked(true);
// epaisseur
weight = new QButtonGroup(this);
weight -> addButton(none_weight = new QRadioButton(tr("Nulle")), CustomElementGraphicPart::NoneWeight);
weight -> addButton(thin_weight = new QRadioButton(tr("Fine")), CustomElementGraphicPart::ThinWeight);
weight -> addButton(normal_weight = new QRadioButton(tr("Normale")), CustomElementGraphicPart::NormalWeight);
weight -> addButton(none_weight = new QRadioButton(tr("Nulle", "element part weight")), CustomElementGraphicPart::NoneWeight);
weight -> addButton(thin_weight = new QRadioButton(tr("Fine", "element part weight")), CustomElementGraphicPart::ThinWeight);
weight -> addButton(normal_weight = new QRadioButton(tr("Normale", "element part weight")), CustomElementGraphicPart::NormalWeight);
// remplissage
filling = new QButtonGroup(this);
filling -> addButton(no_filling = new QRadioButton(tr("Aucun")), CustomElementGraphicPart::NoneFilling );
filling -> addButton(black_filling = new QRadioButton(tr("Noir")), CustomElementGraphicPart::BlackFilling);
filling -> addButton(white_filling = new QRadioButton(tr("Blanc")), CustomElementGraphicPart::WhiteFilling);
filling -> addButton(no_filling = new QRadioButton(tr("Aucun", "element part filling")), CustomElementGraphicPart::NoneFilling );
filling -> addButton(black_filling = new QRadioButton(tr("Noir", "element part filling")), CustomElementGraphicPart::BlackFilling);
filling -> addButton(white_filling = new QRadioButton(tr("Blanc", "element part filling")), CustomElementGraphicPart::WhiteFilling);
// antialiasing
antialiasing = new QCheckBox(tr("Antialiasing"));

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -81,7 +81,7 @@ void TextEditor::updateTextX() { addChangePartCommand(tr("abscisse"), part, "
/// Met a jour l'ordonnee de la position du texte et cree un objet d'annulation
void TextEditor::updateTextY() { addChangePartCommand(tr("ordonn\351e"), part, "y", qle_y -> text().toDouble()); updateForm(); }
/// Met a jour le texte et cree un objet d'annulation
void TextEditor::updateTextT() { addChangePartCommand(tr("texte"), part, "text", qle_text -> text()); }
void TextEditor::updateTextT() { addChangePartCommand(tr("contenu"), part, "text", qle_text -> text()); }
/// Met a jour la taille du texte et cree un objet d'annulation
void TextEditor::updateTextS() { addChangePartCommand(tr("taille"), part, "size", font_size -> value()); }

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -86,7 +86,7 @@ void TextFieldEditor::updateTextFieldX() { addChangePartCommand(tr("abscisse"),
/// Met a jour l'ordonnee de la position du champ de texte et cree un objet d'annulation
void TextFieldEditor::updateTextFieldY() { addChangePartCommand(tr("ordonn\351e"), part, "y", qle_y -> text().toDouble()); updateForm(); }
/// Met a jour le texte du champ de texte et cree un objet d'annulation
void TextFieldEditor::updateTextFieldT() { addChangePartCommand(tr("texte"), part, "text", qle_text -> text()); }
void TextFieldEditor::updateTextFieldT() { addChangePartCommand(tr("contenu"), part, "text", qle_text -> text()); }
/// Met a jour la taille du champ de texte et cree un objet d'annulation
void TextFieldEditor::updateTextFieldS() { addChangePartCommand(tr("taille"), part, "size", font_size -> value()); }
/// Met a jour la taille du champ de texte et cree un objet d'annulation

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2007 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -138,8 +138,8 @@ void Element::deselect() {
@return La pixmap de l'element
*/
QPixmap Element::pixmap() {
if (apercu.isNull()) updatePixmap(); // on genere la pixmap si ce n'est deja fait
return(apercu);
if (preview.isNull()) updatePixmap(); // on genere la pixmap si ce n'est deja fait
return(preview);
}
/**
@@ -220,10 +220,10 @@ void Element::drawSelection(QPainter *painter, const QStyleOptionGraphicsItem *)
*/
void Element::updatePixmap() {
// Pixmap transparente faisant la taille de base de l'element
apercu = QPixmap(dimensions);
apercu.fill(QColor(255, 255, 255, 0));
preview = QPixmap(dimensions);
preview.fill(QColor(255, 255, 255, 0));
// QPainter sur la pixmap, avec antialiasing
QPainter p(&apercu);
QPainter p(&preview);
p.setRenderHint(QPainter::Antialiasing, true);
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
// Translation de l'origine du repere de la pixmap
@@ -416,9 +416,7 @@ QDomElement Element::toXml(QDomDocument &document, QHash<Terminal *, int> &table
QDomElement element = document.createElement("element");
// type
QString chemin_elmt = typeId();
QString type_elmt = QETApp::symbolicPath(chemin_elmt);
element.setAttribute("type", type_elmt);
element.setAttribute("type", typeId());
// position, selection et orientation
element.setAttribute("x", QString("%1").arg(pos().x()));

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -53,7 +53,7 @@ class Element : public QObject, public QGraphicsItem {
private:
QSize dimensions;
QPoint hotspot_coord;
QPixmap apercu;
QPixmap preview;
// methodes
public:
@@ -69,11 +69,11 @@ class Element : public QObject, public QGraphicsItem {
/// @return la liste des conducteurs relies a cet element
virtual QList<Conductor *> conductors() const = 0;
/// @return le nombre de bornes actuel de cet element
virtual int nbTerminals() const = 0;
virtual int terminalsCount() const = 0;
/// @return le nombre de bornes minimum de cet element
virtual int nbTerminalsMin() const = 0;
virtual int minTerminalsCount() const = 0;
/// @return le nombre de bornes maximum de cet element
virtual int nbTerminalsMax() const = 0;
virtual int maxTerminalsCount() const = 0;
/**
Dessine l'element
*/
@@ -81,7 +81,7 @@ class Element : public QObject, public QGraphicsItem {
/// @return L'ID du type de l'element
virtual QString typeId() const = 0;
/// @return Le nom de l'element
virtual QString nom() const = 0;
virtual QString name() const = 0;
Diagram *diagram() const;
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);

View File

@@ -0,0 +1,461 @@
/*
Copyright 2006-2009 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 "elementdefinition.h"
#include "elementscollection.h"
#include "moveelementshandler.h"
#include "moveelementsdescription.h"
/**
@return true si l'element est rattache a une collection d'elements
Un element appartenant a une collection a forcement un chemin virtuel.
*/
bool ElementDefinition::hasParentCategory() {
return(parent_category_);
}
/**
@return la categorie a laquelle appartient cet element
*/
ElementsCategory *ElementDefinition::parentCategory() {
return(parent_category_);
}
/**
@return la liste des categories parentes de cet item.
*/
QList<ElementsCategory *> ElementDefinition::parentCategories() {
QList<ElementsCategory *> cat_list;
if (ElementsCategory *par_cat = parentCategory()) {
cat_list << par_cat -> parentCategories() << par_cat;
}
return(cat_list);
}
/**
@return true si l'element est rattache a une collection d'elements
Un element appartenant a une collection a forcement un chemin virtuel.
*/
bool ElementDefinition::hasParentCollection() {
return(parent_collection_);
}
/**
@param other_item Autre item
@return true si other_item est parent (direct ou indirect) de cet item, false sinon
*/
bool ElementDefinition::isChildOf(ElementsCollectionItem *other_item) {
// soit l'autre item est le parent direct de cet element
if (ElementsCategory *other_item_cat = other_item -> toCategory()) {
if (other_item_cat == parentCategory()) {
return(true);
}
}
// soit il est un parent indirect, auquel cas, on peut demander a la categorie parente de repondre a la question
if (ElementsCategory *parent_cat = parentCategory()) {
return(parent_cat -> isChildOf(other_item));
}
// arrive ici, l'autre item n'est pas parent de cet item
return(false);
}
/**
@return la collection d'element a laquelle appartient cet element
*/
ElementsCollection *ElementDefinition::parentCollection() {
return(parent_collection_);
}
/**
@return le projet auquel appartient cette categorie, si celle-ci
appartient a une collection.
*/
QETProject *ElementDefinition::project() {
if (hasParentCollection()) {
return(parentCollection() -> project());
}
return(0);
}
/**
Ne fait rien ; le projet doit etre defini au niveau d'une collection
*/
void ElementDefinition::setProject(QETProject *) {
}
/**
@return le protocole utilise par la collection a laquelle appartient cet element
*/
QString ElementDefinition::protocol() {
// il n'est pas possible d'avoir un protocole sans appartenir a une collection
if (!hasParentCollection()) return(QString());
return(parentCollection() -> protocol());
}
/**
Ne fait rien
*/
void ElementDefinition::setProtocol(const QString &) {
}
/**
@return le chemin virtuel complet de cet element (protocole + chemin)
*/
QString ElementDefinition::fullVirtualPath() {
// il n'est pas possible d'avoir un chemin virtuel sans appartenir a une collection
if (!hasParentCollection()) return(QString());
return(protocol() + "://" + virtualPath());
}
/**
@return l'emplacement de l'element
*/
ElementsLocation ElementDefinition::location() {
return(ElementsLocation(fullVirtualPath(), project()));
}
/**
@return une liste vide - un element ne possede pas de categorie
*/
QList<ElementsCategory *> ElementDefinition::categories() {
return(QList<ElementsCategory *>());
}
/**
@return toujours 0 - un element ne possede pas de categorie
*/
ElementsCategory *ElementDefinition::category(const QString &) {
return(0);
}
/**
@return toujours 0 - un element ne possede pas de categorie
*/
ElementsCategory *ElementDefinition::createCategory(const QString &) {
return(0);
}
/**
@return une liste contenant seulement cet element
*/
QList<ElementDefinition *> ElementDefinition::elements() {
return(QList<ElementDefinition *>() << this);
}
/**
@return cet element si path est vide, 0 sinon
*/
ElementDefinition *ElementDefinition::element(const QString &path) {
if (path.isEmpty()) return(this);
return(0);
}
/**
@return toujours 0 - un element n'en cree pas d'autre
*/
ElementDefinition *ElementDefinition::createElement(const QString &) {
return(0);
}
/**
@return toujours 0 - un element n'est pas une collection
*/
ElementsCollection *ElementDefinition::toCollection() {
return(0);
}
/**
@return la categorie parente de cet element
*/
ElementsCategory *ElementDefinition::toCategory() {
return(parentCategory());
}
/**
@return toujours 0 - un element n'est pas une categorie
*/
ElementsCategory *ElementDefinition::toPureCategory() {
return(0);
}
/**
@return un pointeur ElementDefinition * sur cet element
*/
ElementDefinition *ElementDefinition::toElement() {
return(this);
}
/**
@return true si cette definition d'element est egale (en termes de contenu)
a la definition d'element other, false sinon.
*/
bool ElementDefinition::equals(ElementDefinition &other) {
/*
Pour le moment, cette methode compare simplement l'export au format
texte des documents XML. Cela peut entrainer de faux positifs.
Exemple : un espace de plus ou de moins dans le XML n'en change pas
forcement la semantique. Mais cela changera l'export au format texte.
*/
QDomDocument this_xml_document;
this_xml_document.appendChild(this_xml_document.importNode(xml(), true));
QString this_text = this_xml_document.toString(0);
QDomDocument other_xml_document;
other_xml_document.appendChild(other_xml_document.importNode(other.xml(), true));
QString other_text = other_xml_document.toString(0);
return(other_text == this_text);
}
/**
@param target_category Categorie cible pour la copie ; elle doit exister
@param handler Gestionnaire d'erreurs a utiliser pour effectuer la copie
@param deep_copy Argument ignore - une copie "recursive" n'a pas de sens pour un element
@return La copie de l'element ou 0 si le processus a echoue
*/
ElementsCollectionItem *ElementDefinition::copy(ElementsCategory *target_category, MoveElementsHandler *handler, bool) {
if (!target_category) return(0);
// echec si le path name de cet element est vide
QString elmt_name(pathName());
if (elmt_name.isEmpty()) return(0);
// cree une description du mouvement a effectuer
MoveElementsDescription mvt_desc;
mvt_desc.setDestinationParentCategory(target_category);
// on tente une copie avec le meme nom interne
mvt_desc.setOriginalDestinationInternalName(pathName());
mvt_desc.setFinalDestinationInternalName(pathName());
mvt_desc.setHandler(handler);
copy(&mvt_desc);
return(mvt_desc.createdItem());
}
/**
Methode privee effectuant une copie de cet element a partir d'une
description du mouvement.
@param mvt_desc Description du mouvement
*/
void ElementDefinition::copy(MoveElementsDescription *mvt_desc) {
// quelques pointeurs pour simplifier l'ecriture de la methode
MoveElementsHandler *handler = mvt_desc -> handler();
ElementsCategory *target_category = mvt_desc -> destinationParentCategory();
ElementDefinition *element_copy = 0;
// verifie que la categorie parente cible est accessible en lecture
if (!target_category -> isReadable()) {
if (!handler) {
return;
} else {
do {
QET::Action todo = handler -> categoryIsNotReadable(target_category);
// on agit en fonction de la reponse du handler
if (todo == QET::Abort) {
mvt_desc -> abort();
return;
} else if (todo == QET::Ignore || todo == QET::Managed) {
return;
} else if (todo == QET::Retry || todo == QET::Erase) {
// reessayer = repasser dans la boucle
} else if (todo == QET::Rename) {
// cas non gere
}
} while (!target_category -> isReadable());
}
}
// verifie que la categorie parente cible est accessible en ecriture
if (!target_category -> isWritable()) {
if (!handler) {
return;
} else {
do {
QET::Action todo = handler -> categoryIsNotWritable(target_category);
// on agit en fonction de la reponse du handler
if (todo == QET::Abort) {
mvt_desc -> abort();
return;
} else if (todo == QET::Ignore || todo == QET::Managed) {
return;
} else if (todo == QET::Retry || todo == QET::Erase) {
// reessayer = repasser dans la boucle
} else if (todo == QET::Rename) {
// cas non gere
}
} while (!target_category -> isWritable());
}
}
// verifie que la cible n'existe pas deja
if ((element_copy = target_category -> element(mvt_desc -> finalDestinationInternalName()))) {
if (!handler) {
return;
} else {
do {
// la cible existe deja : on demande au Handler ce qu'on doit faire
QET::Action todo = handler -> elementAlreadyExists(this, element_copy);
// on agit en fonction de la reponse du handler
if (todo == QET::Abort) {
mvt_desc -> abort();
return;
} else if (todo == QET::Ignore || todo == QET::Managed) {
return;
} else if (todo == QET::Erase) {
break;
} else if (todo == QET::Rename) {
mvt_desc -> setFinalDestinationInternalName(handler -> nameForRenamingOperation());
}
} while ((element_copy = target_category -> element(mvt_desc -> finalDestinationInternalName())));
}
}
/*
A ce stade, on peut creer l'element cible : soit il n'existe pas, soit
on a l'autorisation de l'ecraser
*/
// si la cible existe deja, verifie qu'elle est accessible en ecriture
element_copy = target_category -> element(mvt_desc -> finalDestinationInternalName());
if (element_copy && !element_copy -> isWritable()) {
if (!handler) {
return;
} else {
do {
// la cible n'est pas accessible en ecriture : on demande au Handler ce qu'on doit faire
QET::Action todo = handler -> elementIsNotWritable(element_copy);
// on agit en fonction de la reponse du handler
if (todo == QET::Abort) {
mvt_desc -> abort();
return;
} else if (todo == QET::Ignore || todo == QET::Managed) {
return;
} else if (todo == QET::Retry || todo == QET::Erase) {
// reessayer = repasser dans la boucle
} else if (todo == QET::Rename) {
// cas non gere
}
} while (!element_copy -> isWritable());
}
}
// cree l'element cible
element_copy = target_category -> createElement(mvt_desc -> finalDestinationInternalName());
if (!element_copy) {
if (handler) {
handler -> errorWithAnElement(this, tr("L'\351l\351ment cible n'a pu \352tre cr\351\351."));
}
return;
}
// recopie la definition de l'element
element_copy -> setXml(xml());
element_copy -> write();
mvt_desc -> setCreatedItem(element_copy);
}
/**
@param target_category Categorie cible pour le deplacement ; elle doit exister
@param handler Gestionnaire d'erreurs a utiliser pour effectuer le deplacement
@return L'element apres deplacement ou 0 si le processus a echoue
*/
ElementsCollectionItem *ElementDefinition::move(ElementsCategory *target_category, MoveElementsHandler *handler) {
if (!target_category) return(0);
// echec si le path name de cet element est vide
QString elmt_name(pathName());
if (elmt_name.isEmpty()) return(0);
// cree une description du mouvement a effectuer
MoveElementsDescription mvt_desc;
mvt_desc.setDestinationParentCategory(target_category);
// on tente un deplacement avec le meme nom interne
mvt_desc.setOriginalDestinationInternalName(pathName());
mvt_desc.setFinalDestinationInternalName(pathName());
mvt_desc.setHandler(handler);
move(&mvt_desc);
return(mvt_desc.createdItem());
}
/**
Methode privee effectuant un delacement de cet element a partir d'une
description du mouvement.
Pour etre plus exact, cette methode effectue d'abord une copie de l'element,
puis, si celle-ci a reussi, il supprime l'element d'origine.
@param mvt_desc Description du mouvement
*/
void ElementDefinition::move(MoveElementsDescription *mvt_desc) {
// effectue une copie de l'element
copy(mvt_desc);
ElementsCollectionItem *item_copy = mvt_desc -> createdItem();
if (!item_copy) return;
ElementDefinition *element_copy = item_copy -> toElement();
if (!element_copy) return;
// supprime cet element
MoveElementsHandler *handler = mvt_desc -> handler();
// cet element doit etre accessible en ecriture pour etre supprime
if (!isWritable()) {
if (!handler) {
return;
} else {
do {
// on demande au Handler ce qu'on doit faire
QET::Action todo = handler -> elementIsNotWritable(this);
// on agit en fonction de la reponse du handler
if (todo == QET::Abort) {
mvt_desc -> abort();
return;
} else if (todo == QET::Ignore || todo == QET::Managed) {
return;
} else if (todo == QET::Retry || todo == QET::Erase) {
// reessayer = repasser dans la boucle
} else if (todo == QET::Rename) {
// cas non gere
}
} while (!isWritable());
}
}
// supprime cet element (sinon il ne s'agirait que d'une copie, pas d'un deplacement)
bool element_deletion = remove();
mvt_desc -> setSourceItemDeleted(element_deletion);
if (!element_deletion && handler) {
handler -> errorWithAnElement(this, tr("La suppression de cet \351l\351ment a \351chou\351."));
}
}
/**
Cette methode n'a aucun effet
@return toujours true
*/
bool ElementDefinition::removeContent() {
return(true);
}

126
sources/elementdefinition.h Normal file
View File

@@ -0,0 +1,126 @@
/*
Copyright 2006-2009 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 ELEMENT_DEFINITION_H
#define ELEMENT_DEFINITION_H
#include <QtXml>
#include "elementscategory.h"
class ElementsCollection;
class MoveElementsHandler;
/**
Cette classe abstraite represente une definition XML d'element,
c'est-a-dire qu'elle definit l'interface a implementer pour acceder a la
definition XML d'un element, que celle-ci proviennt d'un fichier *.elmt ou
d'un fichier projet QET.
*/
class ElementDefinition : public ElementsCollectionItem {
Q_OBJECT
public:
/**
Constructeur
*/
ElementDefinition(ElementsCategory *category = 0, ElementsCollection *collection = 0) : ElementsCollectionItem(category), parent_category_(category), parent_collection_(collection) {};
/**
Destructeur
*/
virtual ~ElementDefinition() {};
/**
@return la definition XML de l'element
*/
virtual QDomElement xml() = 0;
/**
Change la definition XML de l'element
@param xml_element Nouvelle definition XML de l'element
@return true si l'operation s'est bien passee, false sinon
*/
virtual bool setXml(const QDomElement &) = 0;
/**
@return true si la definition n'est pas disponible
*/
virtual bool isNull() const = 0;
virtual ElementsCategory *parentCategory();
virtual QList<ElementsCategory *> parentCategories();
virtual bool hasParentCategory();
/**
@return true si l'element est rattache a une collection d'elements
Un element appartenant a une collection a forcement un chemin virtuel.
*/
virtual bool hasParentCollection();
virtual bool isChildOf(ElementsCollectionItem *);
/**
@return la collection d'element a laquelle appartient cet element
*/
virtual ElementsCollection *parentCollection();
virtual QETProject *project();
virtual void setProject(QETProject *);
/**
@return le protocole utilise par la collection a laquelle appartient cet element
*/
virtual QString protocol();
/**
Ne fait rien.
*/
virtual void setProtocol(const QString &);
/**
@return le chemin virtuel complet de cet element (protocole + chemin)
*/
virtual QString fullVirtualPath();
/**
@return l'emplacement de cet element
*/
virtual ElementsLocation location();
virtual QList<ElementsCategory *> categories();
virtual ElementsCategory *category(const QString &);
virtual ElementsCategory *createCategory(const QString &);
virtual QList<ElementDefinition *> elements();
virtual ElementDefinition *element(const QString &);
virtual ElementDefinition *createElement(const QString &);
virtual ElementsCollectionItem *copy(ElementsCategory *, MoveElementsHandler *, bool = true);
virtual ElementsCollectionItem *move(ElementsCategory *, MoveElementsHandler *);
virtual bool isCollection() const { return(false); } ///< @return toujours false
virtual bool isRootCategory() const { return(false); } ///< @return toujours false
virtual bool isCategory() const { return(false); } ///< @return toujours false
virtual bool isElement() const { return(true ); } ///< @return toujours true
virtual ElementsCollection *toCollection();
virtual ElementsCategory *toCategory();
virtual ElementsCategory *toPureCategory();
virtual ElementDefinition *toElement();
virtual bool equals(ElementDefinition &);
virtual bool removeContent();
void copy(MoveElementsDescription *);
void move(MoveElementsDescription *);
// attributs
private:
ElementsCategory *parent_category_;
ElementsCollection *parent_collection_;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -16,16 +16,25 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementdeleter.h"
#include "qetapp.h"
/**
Constructeur
@param elmt_path Chemin du fichier representant l'element a supprimer
@param elmt_path Chemin virtuel du fichier representant l'element a supprimer
@param parent QWidget parent
*/
ElementDeleter::ElementDeleter(const QString &elmt_path, QWidget *parent) :
ElementDeleter::ElementDeleter(const ElementsLocation &elmt_path, QWidget *parent) :
QWidget(parent),
element_path(elmt_path)
element(0)
{
// recupere l'element a supprimer
ElementsCollectionItem *element_item = QETApp::collectionItem(elmt_path);
if (!element_item) return;
// on exige un element
if (!element_item -> isElement()) return;
element = element_item;
}
/// Destructeur
@@ -36,27 +45,31 @@ ElementDeleter::~ElementDeleter() {
Supprime l'element : verifie l'existence du fichier, demande confirmation a
l'utilisateur et avertit ce dernier si la suppression a echoue.
*/
void ElementDeleter::exec() {
bool ElementDeleter::exec() {
// verifie l'existence de l'element
QFile elmt_file(element_path);
if (!elmt_file.exists()) return;
if (!element || !element -> isElement()) return(false);
// confirmation #1
QMessageBox::StandardButton answer_1 = QMessageBox::question(
this,
tr("Supprimer l'\351l\351ment ?"),
tr("\312tes-vous s\373r de vouloir supprimer cet \351l\351ment ?\n"),
QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel
tr("Supprimer l'\351l\351ment ?", "message box title"),
tr("\312tes-vous s\373r de vouloir supprimer cet \351l\351ment ?\n", "message box content"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel
);
if (answer_1 != QMessageBox::Yes) return;
if (answer_1 != QMessageBox::Yes) return(false);
/**
@todo Regression : rafficher le chemin de l'element
*/
// supprime l'element
if (!elmt_file.remove()) {
if (!element -> remove()) {
QMessageBox::warning(
this,
tr("Suppression de l'\351l\351ment"),
tr("La suppression de l'\351l\351ment a \351chou\351.\n"
"V\351rifiez vos droits sur le fichier ") + element_path + tr(".")
tr("Suppression de l'\351l\351ment", "message box title"),
tr("La suppression de l'\351l\351ment a \351chou\351.", "message box content")
);
return(false);
}
return(true);
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2006-2008 Xavier Guerrin
Copyright 2006-2009 Xavier Guerrin
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
@@ -18,27 +18,28 @@
#ifndef ELEMENT_DELETER_H
#define ELEMENT_DELETER_H
#include "elementscategory.h"
#include "elementslocation.h"
#include <QtGui>
/**
Cette classe represente une couche d'abstraction pour supprimer
un element de la collection d'elements.
Elle demande notamment confirmation a l'utilisateur
Elle demande notamment confirmation a l'utilisateur.
*/
class ElementDeleter : public QWidget {
Q_OBJECT
// constructeurs, destructeur
public:
ElementDeleter(const QString &, QWidget * = 0);
ElementDeleter(const ElementsLocation &, QWidget * = 0);
virtual ~ElementDeleter();
private:
ElementDeleter(const ElementsCategory &);
// methodes
public slots:
void exec();
bool exec();
// attributs
private:
QString element_path;
ElementsCollectionItem *element;
};
#endif

Some files were not shown because too many files have changed in this diff Show More