diff --git a/sources/diagram.cpp b/sources/diagram.cpp index 2bcc71aac..9215988c8 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -980,6 +980,22 @@ QSet Diagram::selectedConductors() const { return(conductors_set); } +/** + @return la liste de tous les textes selectionnes : les textes independants, + mais aussi ceux rattaches a des conducteurs ou des elements +*/ +QSet Diagram::selectedTexts() const { + QSet selected_texts; + foreach(QGraphicsItem *item, selectedItems()) { + if (DiagramTextItem *dti = qgraphicsitem_cast(item)) { + selected_texts << dti; + } else if (ElementTextItem *eti = qgraphicsitem_cast(item)) { + selected_texts << eti; + } + } + return(selected_texts); +} + /// @return true si le presse-papier semble contenir un schema bool Diagram::clipboardMayContainDiagram() { QString clipboard_text = QApplication::clipboard() -> text().trimmed(); diff --git a/sources/diagram.h b/sources/diagram.h index 98b6623be..b987d51f3 100644 --- a/sources/diagram.h +++ b/sources/diagram.h @@ -157,6 +157,7 @@ class Diagram : public QGraphicsScene { const QSet &conductorsToMove(); const QHash &conductorsToUpdate(); const QSet &textsToMove(); + QSet selectedTexts() const; QSet selectedConductors() const; DiagramContent content() const; DiagramContent selectedContent(); diff --git a/sources/diagramcommands.cpp b/sources/diagramcommands.cpp index d296fa868..0b721541d 100644 --- a/sources/diagramcommands.cpp +++ b/sources/diagramcommands.cpp @@ -410,7 +410,8 @@ void ChangeDiagramTextCommand::redo() { RotateElementsCommand::RotateElementsCommand(const QHash &elements, const QList &texts, QUndoCommand *parent) : QUndoCommand(parent), elements_to_rotate(elements), - texts_to_rotate(texts) + texts_to_rotate(texts), + applied_rotation_angle_(-90.0) { setText( QString( @@ -432,7 +433,7 @@ void RotateElementsCommand::undo() { e -> setOrientation(elements_to_rotate[e]); } foreach(DiagramTextItem *dti, texts_to_rotate) { - dti -> rotateBy(90.0); + dti -> rotateBy(-applied_rotation_angle_); } } @@ -443,10 +444,93 @@ void RotateElementsCommand::redo() { e -> update(); } foreach(DiagramTextItem *dti, texts_to_rotate) { - dti -> rotateBy(-90.0); + dti -> rotateBy(applied_rotation_angle_); } } +/** + @return l'angle de rotation applique aux textes +*/ +qreal RotateElementsCommand::appliedRotationAngle() const { + return(applied_rotation_angle_); +} + +/** + @param angle l'angle de rotation a appliquer aux textes +*/ +void RotateElementsCommand::setAppliedRotationAngle(const qreal &angle) { + applied_rotation_angle_ = QET::correctAngle(angle); +} + +/** + Constructeur + @param previous_state Hash associant les textes impactes par l'action et leur angle de rotation avant l'action + @param applied_rotation Nouvel angle de rotation, a appliquer au textes concernes + @param parent QUndoCommand parent +*/ +RotateTextsCommand::RotateTextsCommand(const QHash &previous_state, double applied_rotation, QUndoCommand *parent) : + QUndoCommand(parent), + texts_to_rotate(previous_state), + applied_rotation_angle_(applied_rotation) +{ + defineCommandName(); +} + +/** + Constructeur + @param texts Liste des textes impactes par l'action. L'objet retiendra leur angle de rotation au moment de sa construction. + @param applied_rotation Nouvel angle de rotation, a appliquer au textes concernes + @param parent QUndoCommand parent +*/ +RotateTextsCommand::RotateTextsCommand(const QList &texts, double applied_rotation, QUndoCommand *parent) : + QUndoCommand(parent), + applied_rotation_angle_(applied_rotation) +{ + foreach(DiagramTextItem *text, texts) { + texts_to_rotate.insert(text, text -> rotationAngle()); + } + defineCommandName(); +} + +/** + Destructeur +*/ +RotateTextsCommand::~RotateTextsCommand() { +} + +/** + Annule la rotation des textes +*/ +void RotateTextsCommand::undo() { + foreach(DiagramTextItem *text, texts_to_rotate.keys()) { + text -> setRotationAngle(texts_to_rotate[text]); + } +} + +/** + Applique l'angle de rotation aux textes +*/ +void RotateTextsCommand::redo() { + foreach(DiagramTextItem *text, texts_to_rotate.keys()) { + text -> setRotationAngle(applied_rotation_angle_); + } +} + +/** + Definit le nom de la commande d'annulation +*/ +void RotateTextsCommand::defineCommandName() { + setText( + QString( + QObject::tr( + "orienter %1 \340 %2\260", + "undo caption - %1 looks like '42 texts', %2 is a rotation angle" + ) + ).arg(QET::ElementsAndConductorsSentence(0, 0, texts_to_rotate.count())) + .arg(applied_rotation_angle_) + ); +} + /** Constructeur @param c Conducteur modifie diff --git a/sources/diagramcommands.h b/sources/diagramcommands.h index c8aea7bfc..727869b24 100644 --- a/sources/diagramcommands.h +++ b/sources/diagramcommands.h @@ -227,7 +227,7 @@ class ChangeDiagramTextCommand : public QUndoCommand { }; /** - Cette classe represente l'action de pivoter plusieurs elements + Cette classe represente l'action de pivoter plusieurs elements ou champs de textes avec un meme angle */ class RotateElementsCommand : public QUndoCommand { // constructeurs, destructeur @@ -241,6 +241,8 @@ class RotateElementsCommand : public QUndoCommand { public: virtual void undo(); virtual void redo(); + qreal appliedRotationAngle() const; + void setAppliedRotationAngle(const qreal &); // attributs private: @@ -248,6 +250,36 @@ class RotateElementsCommand : public QUndoCommand { QHash elements_to_rotate; /// textes a pivoter QList texts_to_rotate; + /// angle de rotation a appliquer aux textes (valeur utilisee dans le redo + qreal applied_rotation_angle_; +}; + +/** + Cette classe represente l'action d'orienter plusieurs textes a un meme angle de rotation bien precis +*/ +class RotateTextsCommand : public QUndoCommand { + // constructeurs, destructeur + public: + RotateTextsCommand(const QHash &, double, QUndoCommand * = 0); + RotateTextsCommand(const QList &, double, QUndoCommand * = 0); + virtual ~RotateTextsCommand(); + private: + RotateTextsCommand(const RotateTextsCommand &); + + // methodes + public: + virtual void undo(); + virtual void redo(); + + private: + void defineCommandName(); + + // attributs + private: + /// textes pivotes associes a leur ancienne orientation + QHash texts_to_rotate; + /// angle de rotation a appliquer aux textes + double applied_rotation_angle_; }; /** diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 48ec4544a..e41519f98 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -32,6 +32,7 @@ #include "qetdiagrameditor.h" #include "qeticons.h" #include "qetmessagebox.h" +#include "qtextorientationspinboxwidget.h" /** Constructeur @@ -137,6 +138,58 @@ void DiagramView::rotateSelection() { scene -> undoStack().push(new RotateElementsCommand(elements_to_rotate, texts_to_rotate)); } +void DiagramView::rotateTexts() { + if (scene -> isReadOnly()) return; + + // recupere les champs de texte a orienter + QList texts_to_rotate; + foreach (QGraphicsItem *item, scene -> selectedItems()) { + if (DiagramTextItem *dti = qgraphicsitem_cast(item)) { + texts_to_rotate << dti; + } else if (ElementTextItem *eti = qgraphicsitem_cast(item)) { + // ici, on pivote un texte d'element meme si son parent est selectionne + texts_to_rotate << eti; + } + } + + // effectue les rotations s'il y a quelque chose a pivoter + if (texts_to_rotate.isEmpty()) return; + + // demande un angle a l'utilisateur + QDialog ori_text_dialog(diagramEditor()); + ori_text_dialog.setSizeGripEnabled(false); +#ifdef Q_WS_MAC + ori_text_dialog.setWindowFlags(Qt::Sheet); +#endif + ori_text_dialog.setWindowTitle(tr("Orienter les textes s\351lectionn\351s", "window title")); +// ori_text_dialog.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + + + QTextOrientationSpinBoxWidget *ori_widget = QETApp::createTextOrientationSpinBoxWidget(); + ori_widget -> setParent(&ori_text_dialog); + if (texts_to_rotate.count() == 1) { + ori_widget -> setOrientation(texts_to_rotate.at(0) -> rotationAngle()); + } + ori_widget -> spinBox() -> selectAll(); + + // boutons + QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(&buttons, SIGNAL(accepted()), &ori_text_dialog, SLOT(accept())); + connect(&buttons, SIGNAL(rejected()), &ori_text_dialog, SLOT(reject())); + + // ajout dans une disposition verticale + QVBoxLayout layout_v(&ori_text_dialog); + layout_v.setSizeConstraint(QLayout::SetFixedSize); + layout_v.addWidget(ori_widget); + layout_v.addStretch(); + layout_v.addWidget(&buttons); + + // si le dialogue est accepte + if (ori_text_dialog.exec() == QDialog::Accepted) { + scene -> undoStack().push(new RotateTextsCommand(texts_to_rotate, ori_widget -> orientation())); + } +} + /** Accepte ou refuse le drag'n drop en fonction du type de donnees entrant @param e le QDragEnterEvent correspondant au drag'n drop tente diff --git a/sources/diagramview.h b/sources/diagramview.h index 368cf33b6..5029f5fc8 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -102,6 +102,7 @@ class DiagramView : public QGraphicsView { void selectInvert(); void deleteSelection(); void rotateSelection(); + void rotateTexts(); void setVisualisationMode(); void setSelectionMode(); void zoomIn(); diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 34e1bcdfd..f85c257b1 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -196,6 +196,7 @@ void QETDiagramEditor::actions() { select_invert = new QAction( tr("Inverser la s\351lection"), this); delete_selection = new QAction(QET::Icons::EditDelete, tr("Supprimer"), this); rotate_selection = new QAction(QET::Icons::ObjectRotateRight, tr("Pivoter"), this); + rotate_texts = new QAction(QET::Icons::ObjectRotateRight, tr("Orienter les textes"), this); selection_prop = new QAction(QET::Icons::DialogInformation, tr("Propri\351t\351s de la s\351lection"), this); conductor_reset = new QAction(QET::Icons::ConductorSettings, tr("R\351initialiser les conducteurs"), this); conductor_default = new QAction(QET::Icons::DefaultConductor, tr("Conducteurs par d\351faut"), this); @@ -259,6 +260,7 @@ void QETDiagramEditor::actions() { #endif rotate_selection -> setShortcut(QKeySequence(tr("Space"))); + rotate_texts -> setShortcut(QKeySequence(tr("Ctrl+Space"))); selection_prop -> setShortcut(QKeySequence(tr("Ctrl+J"))); conductor_reset -> setShortcut(QKeySequence(tr("Ctrl+K"))); infos_diagram -> setShortcut(QKeySequence(tr("Ctrl+L"))); @@ -297,7 +299,8 @@ void QETDiagramEditor::actions() { select_nothing -> setStatusTip(tr("D\351s\351lectionne tous les \351l\351ments du sch\351ma", "status bar tip")); select_invert -> setStatusTip(tr("D\351s\351lectionne les \351l\351ments s\351lectionn\351s et s\351lectionne les \351l\351ments non s\351lectionn\351s", "status bar tip")); delete_selection -> setStatusTip(tr("Enl\350ve les \351l\351ments s\351lectionn\351s du sch\351ma", "status bar tip")); - rotate_selection -> setStatusTip(tr("Pivote les \351l\351ments s\351lectionn\351s", "status bar tip")); + rotate_selection -> setStatusTip(tr("Pivote les \351l\351ments et textes s\351lectionn\351s", "status bar tip")); + rotate_texts -> setStatusTip(tr("Pivote les textes s\351lectionn\351s \320 un angle pr\351cis", "status bar tip")); selection_prop -> setStatusTip(tr("\311dite les propri\351t\351s des objets s\351lectionn\351", "status bar tip")); conductor_reset -> setStatusTip(tr("Recalcule les chemins des conducteurs sans tenir compte des modifications", "status bar tip")); conductor_default -> setStatusTip(tr("Sp\351cifie les propri\351t\351s par d\351faut des conducteurs", "status bar tip")); @@ -355,6 +358,7 @@ void QETDiagramEditor::actions() { connect(select_invert, SIGNAL(triggered()), this, SLOT(slot_selectInvert()) ); connect(delete_selection, SIGNAL(triggered()), this, SLOT(slot_delete()) ); connect(rotate_selection, SIGNAL(triggered()), this, SLOT(slot_rotate()) ); + connect(rotate_texts, SIGNAL(triggered()), this, SLOT(slot_rotateTexts()) ); connect(fullscreen, SIGNAL(triggered()), this, SLOT(toggleFullScreen()) ); connect(configure, SIGNAL(triggered()), qet_app, SLOT(configureQET()) ); connect(windowed_view_mode, SIGNAL(triggered()), this, SLOT(setWindowedMode()) ); @@ -472,6 +476,7 @@ void QETDiagramEditor::menus() { menu_edition -> addSeparator(); menu_edition -> addAction(delete_selection); menu_edition -> addAction(rotate_selection); + menu_edition -> addAction(rotate_texts); menu_edition -> addAction(selection_prop); menu_edition -> addSeparator(); menu_edition -> addAction(conductor_reset); @@ -1055,6 +1060,13 @@ void QETDiagramEditor::slot_rotate() { if(currentDiagram()) currentDiagram() -> rotateSelection(); } +/** + Effectue l'action "Orienter les textes selectionnes" sur le schema en cours +*/ +void QETDiagramEditor::slot_rotateTexts() { + if (currentDiagram()) currentDiagram() -> rotateTexts(); +} + /** Effectue l'action "mode selection" sur le schema en cours */ @@ -1137,13 +1149,17 @@ void QETDiagramEditor::slot_updateComplexActions() { int selected_conductors_count = dv ? dv -> diagram() -> selectedConductors().count() : 0; conductor_reset -> setEnabled(editable_diagram && selected_conductors_count); - // actions ayant aussi besoin d'elements selectionnes - bool selected_elements = dv ? (dv -> hasSelectedItems()) : false; - cut -> setEnabled(editable_diagram && selected_elements); - copy -> setEnabled(selected_elements); - delete_selection -> setEnabled(editable_diagram && selected_elements); - rotate_selection -> setEnabled(editable_diagram && selected_elements && dv -> diagram() -> canRotateSelection()); - selection_prop -> setEnabled(editable_diagram && selected_elements); + // actions ayant aussi besoin d'items (elements, conducteurs, textes, ...) selectionnes + bool selected_items = dv ? (dv -> hasSelectedItems()) : false; + cut -> setEnabled(editable_diagram && selected_items); + copy -> setEnabled(selected_items); + delete_selection -> setEnabled(editable_diagram && selected_items); + rotate_selection -> setEnabled(editable_diagram && selected_items && dv -> diagram() -> canRotateSelection()); + selection_prop -> setEnabled(editable_diagram && selected_items); + + // actions ayant besoin de textes selectionnes + bool selected_texts = dv ? (dv -> diagram() -> selectedTexts().count()) : 0; + rotate_texts -> setEnabled(editable_diagram && selected_texts); } /** diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index e003022a9..670ca7aae 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -104,6 +104,7 @@ class QETDiagramEditor : public QMainWindow { void slot_selectInvert(); void slot_delete(); void slot_rotate(); + void slot_rotateTexts(); void slot_setSelectionMode(); void slot_setVisualisationMode(); void slot_updateActions(); @@ -177,7 +178,8 @@ class QETDiagramEditor : public QMainWindow { QAction *select_nothing; ///< Deselectionne tout QAction *select_invert; ///< Inverse la selection QAction *delete_selection; ///< Supprime la selection - QAction *rotate_selection; ///< Pivote les elements selectionnes + QAction *rotate_selection; ///< Pivote les elements et textes selectionnes de 90 degres + QAction *rotate_texts; ///< Pivote les textes selectionnes selon un angle parametrable QAction *selection_prop; ///< Lance le dialogue de description ou d'edition de la selection QAction *conductor_reset; ///< Reinitialise les conducteurs selectionnes QAction *conductor_default; ///< Lance le dialogue d'edition des conducteurs par defaut diff --git a/sources/qtextorientationspinboxwidget.cpp b/sources/qtextorientationspinboxwidget.cpp index 50fb94185..c7f8b2c88 100644 --- a/sources/qtextorientationspinboxwidget.cpp +++ b/sources/qtextorientationspinboxwidget.cpp @@ -103,6 +103,7 @@ void QTextOrientationSpinBoxWidget::build() { QHBoxLayout *main_layout = new QHBoxLayout(); main_layout -> addWidget(orientation_widget_); main_layout -> addWidget(spin_box_); + main_layout -> addStretch(); setLayout(main_layout); }